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 #include "bbox.h"
8 #include "xim.h"
9 
10 static Widget wtemp ;
11 
12 static char *wsubtype = NULL ;
BBOX_set_wsubtype(char * wt)13 void BBOX_set_wsubtype( char *wt ){ wsubtype = wt ; }
14 
15 #undef  DIALOG
16 #define DIALOG ( (wsubtype==NULL) ? "dialog" : wsubtype )
17 
18 #undef  MENU
19 #define MENU   ( (wsubtype==NULL) ? "menu" : wsubtype )
20 
21 static Widget old_wpar=NULL ; /* Apr 2013 -- for Allison */
22 static int old_xx=-666,old_yy=-666;
23 
24 /* macro to relocate popup w.r.t. parent [12 Oct 2017] */
25 
26 #undef  RELOCATE
27 #define RELOCATE(wwpar,wwpop,dd)                                 \
28  do{ int www=0 , hhh=0 ; Position qx=0,qy=0 ;                    \
29      MCW_widget_geom( wwpar , &www , &hhh , NULL,NULL ) ;        \
30      www /= dd ; if( www < 19 ) www = 19 ;                       \
31      hhh /= dd ; if( hhh < 10 ) hhh = 10 ;                       \
32      XtTranslateCoords( wwpar , www,hhh , &qx , &qy ) ;          \
33      XtVaSetValues( wwpop, XmNx,(int)qx, XmNy,(int)qy, NULL ) ;  \
34  } while(0) ;
35 
36 /*------------------------------------------------------------------------*/
37 /*
38    This function was meant to find the top parent of a widget and later
39    test if that parent was one that allowed rowcolumns. This was function
40    was to be called from new_MCW_bbox. However, none of the tests shown
41    below identified such forbidding widgets.
42    Code is left here for documentation purposes.
43 
44    Lesstif patrol          Jan 09
45 */
top_parent(Widget w)46 Widget top_parent( Widget w)
47 {
48    Widget pa = w;
49    int iw = 0;
50    char str[500]={""}, strb[500]={""};
51 
52 ENTRY("top_parent");
53 
54    while (pa) {
55       str[iw] = '-'; str[iw+1]='\0';
56       strb[iw] = ' '; strb[iw+1]='\0';
57       fprintf( stderr,
58                "%sWidget name %s      ancestor(%d)\n",
59                str, XtName(pa), iw);
60       if (XtIsTransientShell(pa)) {
61          fprintf(stderr,"%sTransient (%d)!!!\n",strb, iw);
62       } else {
63          /*fprintf(stderr,"%sNOOOT Transient (%d)!!!\n",strb, iw);*/
64       }
65       if (XtIsTopLevelShell(pa)) {
66          fprintf(stderr,"%sTopLevel (%d)!!!\n", strb, iw);
67       } else {
68          /*fprintf(stderr,"%sNOOOT TopLevel (%d)!!!\n", strb, iw);*/
69       }
70       if (XtIsSubclass(pa, xmCascadeButtonWidgetClass)) {
71          fprintf(stderr,"%sCascadeButtonWidget (%d)!!!\n", strb, iw);
72       } else {
73          /*fprintf(stderr,"%sNOOOT CascadeButtonWidget (%d)!!!\n", strb, iw);*/
74 
75       }
76       if (XtIsShell(pa)) {
77          fprintf(stderr,"%sShell (%d)!!!\n", strb, iw);
78       } else {
79          /*fprintf(stderr,"%sNOOOT Shell (%d)!!!\n", strb, iw);*/
80       }
81       w = pa;
82       pa = XtParent(w);
83       ++iw;
84    }
85    RETURN(w);
86 }
87 /*------------------------------------------------------------------------*/
88 /*
89    A simple way to determine if a widget has a popup_menu for a parent.
90 
91    Lesstif Partol,         Jan 09
92 */
is_daddy_popup(Widget w)93 int is_daddy_popup(Widget w)
94 {
95    Widget pa = w;
96    int iw = 0;
97    char str[500]={""}, strb[500]={""};
98 
99 ENTRY("is_daddy_popup");
100 
101    while (pa) {
102       str[iw] = '-'; str[iw+1]='\0';
103       strb[iw] = ' '; strb[iw+1]='\0';
104       if (!strcmp(XtName(pa), "popup_menu")) RETURN(1);
105       w = pa;
106       pa = XtParent(w);
107       ++iw;
108    }
109    RETURN(0);
110 }
111 
112 /*
113    A structure to hold widget and callback information
114    for the callback wrapper used by new_MCW_bbox
115 
116    Lesstif Patrol,      Jan 09
117 */
118 
119 typedef struct {
120    MCW_bbox *bb;
121    XtCallbackProc cb;
122    XtPointer cb_data;
123    XtPointer client_data;
124    Widget parent;
125    int is_popup;
126    int bb_type;
127 } cb_wrap_struct;
128 
129 /*------------------------------------------------------------------------*/
130 /* set all buttons in a button box, given that button ikeep
131    has been pressed on */
MCW_enforce_radio_bbox(MCW_bbox * bb,int ikeep)132 void MCW_enforce_radio_bbox( MCW_bbox *bb, int ikeep  )
133 {
134    int ib;
135    RwcBoolean oset ;
136 
137 ENTRY("MCW_enforce_radio_bbox") ;
138 
139    if( bb == NULL ) EXRETURN ;  /* 01 Feb 2000 */
140    for( ib=0 ; ib < bb->nbut ; ib++ ){
141       if (ib != ikeep) {
142          oset = XmToggleButtonGetState( bb->wbut[ib] ) ;
143          if( XtIsSensitive(bb->wbut[ib]) && oset){
144             XmToggleButtonSetState( bb->wbut[ib] , !oset , False ) ;
145             XmUpdateDisplay( bb->wbut[ib] ) ;
146          }
147       }
148    }
149    bb->value = MCW_val_bbox(bb) ;
150    EXRETURN ;
151 }
152 
153 
154 /*------------------------------------------------------------------------*/
155 /*
156    Manually handle radio buttons where rowcolumn widgets are not allowed
157 
158    See new_MCW_bbox for help
159 
160    Lesstif Patrol,   Jan 2009
161 */
new_MCW_bbox_cbwrap(Widget w,XtPointer client_data,XtPointer call_data)162 void new_MCW_bbox_cbwrap ( Widget w, XtPointer client_data, XtPointer call_data )
163 {
164    int ib=0, icaller = -1;
165    RwcBoolean oset = False;
166    cb_wrap_struct *cbws = (cb_wrap_struct *)client_data;
167    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data ;
168    int dbg = 0;
169 
170 ENTRY("new_MCW_bbox_cbwrap") ;
171 
172    if (cbws->is_popup) {
173       if (dbg) {  /* some debugging */
174          fprintf(stderr,"Potential for work\n");
175          /* For some reason, when a button other than button
176          0 is pressed, there are two callback calls made.
177          The first comes from widget 0 with a NULL event,
178          and the second from the widget pressed. */
179          for (ib=0; ib<cbws->bb->nbut; ++ib) {
180             if (cbws->bb->wbut[ib] == w) {
181                fprintf(stderr,
182                         "A call from widget (%p) %s at ib = %d, reason: %d\n",
183                         cbws->bb->wbut[ib], XtName(w), ib, cbs->reason);
184                if (cbs->event) {
185                   fprintf(stderr,
186                         "   event->type = %d\n", cbs->event->type);
187                } else {
188                   fprintf(stderr,
189                         "   event is NULL\n");
190                }
191             }
192          }
193       }
194 
195       if (cbs->event) {
196          if( cbws->bb_type != MCW_BB_check ){ /* 05 May 2020 */
197            for (ib=0; ib<cbws->bb->nbut && icaller < 0; ++ib) {
198              if (cbws->bb->wbut[ib] == w) icaller = ib;
199            }
200 
201            /* what --was-- the state the calling widget? */
202            oset = !XmToggleButtonGetState( cbws->bb->wbut[icaller] );
203            if (oset && cbws->bb_type == MCW_BB_radio_one) {
204               /* widget was already set, and we're in radio one mode
205                 turn it back on and vamoose */
206               XmToggleButtonSetState(cbws->bb->wbut[icaller], oset, False);
207               EXRETURN;
208            }
209 
210            /* flip everything but the calling widget */
211            MCW_enforce_radio_bbox(cbws->bb, icaller);
212          }
213       } else {
214          /* ignore the initial call */
215          /* for some reason, if you press on widgets other than 0, you get
216          two calls, one from widget 0 with a NULL event and another from
217          the proper widget with a proper event */
218       }
219    } else {
220       /* This is not a popup menu case, rowcolumns are allowed.
221          No need to do anything */
222       if (dbg) {  /* some debugging */
223          fprintf(stderr,"I thought this caused no trouble, but check anyway\n");
224          /* For some reason, when a button other than button
225          0 is pressed, there are two callback calls made.
226          The first comes from widget 0 with a NULL event,
227          and the second from the widget pressed. */
228          for (ib=0; ib<cbws->bb->nbut; ++ib) {
229             if (cbws->bb->wbut[ib] == w) {
230                fprintf(stderr,
231                         "A call from widget (%p) %s at ib = %d, reason: %d\n",
232                         cbws->bb->wbut[ib], XtName(w), ib, cbs->reason);
233                if (cbs->event) {
234                   fprintf(stderr,
235                         "   event->type = %d\n", cbs->event->type);
236                } else {
237                   fprintf(stderr,
238                         "   event is NULL\n");
239                }
240             }
241          }
242       }
243 
244    }
245 
246    /* Now call the intended callback */
247    if( cbws->cb != NULL )
248      (cbws->cb)(w, cbws->cb_data, call_data);
249 
250    EXRETURN;
251 }
252 
253 /*-------------------------------------------------------------------------
254    create a new MCW_bbox:
255        parent    = parent Widget
256        num_but   = number of buttons (from 1 to MCW_MAX_BB)
257        label_but = array of strings of button labels
258        bb_type   = MCW_BB_check      -> check box (any may be on)
259                    MCW_BB_radio_one  -> radio box, exactly one will be on
260                    MCW_BB_radio_zero -> radio box, zero or one will be on
261        bb_frame  = MCW_BB_noframe    -> no frame around box
262                  = MCW_BB_frame      -> put frame around box
263        cb        = Callback procedure for Disarm (NULL for none)
264        cb_data   = data to pass to Callback procedure (NULL for none)
265 
266    Lesstif Patrol, Jan 13, 2009
267    ----------------------------
268    Rowcolumn widgets are not allowed in popup menus. Motif allowed them
269    to work, in most cases, but Lesstif does not. To fix this, new_MCW_bbox
270    was modified to check whether MCW_bbox has a popup parent. The check is
271    done with function 'is_daddy_popup'. If the parent is a popup, then
272    a rowcolumn widget is NOT created and the widget wtop is set to the
273    parent Widget. For MCW_bbox with a popup parent, allowing 'frame' to
274    be wtop if a frame is requested is bad news.
275    With this modification however, radio buttons must be managed manually.
276    To do so, new_MCW_bbox always calls a wrapper callback named
277    new_MCW_bbox_cbwrap. This callback will perform radio button management
278    if necessary and then call the button's intended callbacks.
279 ---------------------------------------------------------------------------*/
280 
new_MCW_bbox(Widget parent,int num_but,char * label_but[],int bb_type,int bb_frame,XtCallbackProc cb,XtPointer cb_data)281 MCW_bbox * new_MCW_bbox( Widget parent ,
282                          int num_but , char *label_but[] ,
283                          int bb_type , int bb_frame ,
284                          XtCallbackProc cb , XtPointer cb_data )
285 {
286    MCW_bbox *bb ;
287    int ib , initial_value ;
288    Widget rc_parent, gp;
289    Arg wa[30] ;  int na ;
290    Pixel  fg_pix=0 ;
291    int is_popup=0;
292    cb_wrap_struct *cbws=NULL;
293    int dbg = 0;
294 
295 ENTRY("new_MCW_bbox") ;
296 
297    if( num_but <= 0 || num_but >= 32 ){
298      fprintf(stderr,"\n*** illegal new_MCW_bbox has %d buttons\n",num_but) ;
299      EXIT(1) ;
300    }
301 
302    /* study the parent     Lesstif Patrol*/
303 
304    /* finding out if a parent was 'transient' failed.
305       the function that was to do that is called
306       gp = top_parent(parent); and is left here for documentation
307       purposes. */
308 
309    /* this simpler approach worked fine */
310    is_popup = is_daddy_popup(parent);
311    if (dbg) {
312       if (is_popup) {
313          for( ib=0 ; ib < num_but ; ib++ ){
314             fprintf(stderr,"     Popping for button %s\n", label_but[ib]);
315          }
316       } else {
317          for( ib=0 ; ib < num_but ; ib++ ){
318             fprintf(stderr,"     Not popping for button %s\n", label_but[ib]);
319          }
320       }
321    }
322 
323    bb = (MCW_bbox *) XtMalloc( sizeof(MCW_bbox) ) ;
324    memset(bb, 0, sizeof(MCW_bbox)) ;  /* 12 Feb 2009 [lesstif patrol] */
325 
326    bb->nbut      = num_but ;
327    initial_value = 0 ;
328 
329    /***--- create Frame, if desired ---***/
330 
331    switch( bb_frame ){
332 
333       case MCW_BB_frame:
334         STATUS("create frame") ;
335         rc_parent = bb->wtop = bb->wframe =
336            XtVaCreateManagedWidget(
337               "frame" , xmFrameWidgetClass , parent ,
338                   XmNshadowType , XmSHADOW_ETCHED_IN ,
339                   XmNtraversalOn , True ,
340                   XmNinitialResourcesPersistent , False ,
341               NULL ) ;
342       break ;
343 
344       case MCW_BB_noframe:
345       default:
346         rc_parent  = parent ;
347         bb->wframe = NULL ;
348       break ;
349    }
350 
351    /***--- create RowColumn to hold the buttons ---***/
352 
353    if (!is_popup) {
354    #define MAX_PER_COL 8
355 
356       na = 0 ;
357 
358    #ifdef BBOX_COL
359       XtSetArg( wa[na] , XmNpacking    , XmPACK_COLUMN )               ; na++ ;
360       XtSetArg( wa[na] , XmNnumColumns , 1 + (num_but-1)/MAX_PER_COL ) ; na++ ;
361    #else
362       XtSetArg( wa[na] , XmNpacking    , XmPACK_TIGHT )                ; na++ ;
363    #endif
364 
365       XtSetArg( wa[na] , XmNmarginHeight , 0 ) ; na++ ;  /* squash things in */
366       XtSetArg( wa[na] , XmNmarginWidth  , 0 ) ; na++ ;
367       XtSetArg( wa[na] , XmNspacing      , 1 ) ; na++ ;
368 
369       XtSetArg( wa[na] , XmNtraversalOn , True ) ; na++ ;
370       XtSetArg( wa[na] , XmNinitialResourcesPersistent , False ) ; na++ ;
371 
372       if( bb_type == MCW_BB_radio_zero || bb_type == MCW_BB_radio_one ){
373 
374         XtSetArg( wa[na] , XmNradioBehavior , True ) ; na++ ;
375 
376         if( bb_type == MCW_BB_radio_one ){
377           XtSetArg( wa[na] , XmNradioAlwaysOne , True ) ; na++ ;
378         } else {
379           XtSetArg( wa[na] , XmNradioAlwaysOne , False ) ; na++ ;
380         }
381       } else {
382         XtSetArg( wa[na] , XmNradioBehavior , False ) ; na++ ; /* 05 May 2020 */
383       }
384 
385       STATUS("create rowcol") ;
386       bb->wrowcol = XtCreateWidget(
387                       DIALOG , xmRowColumnWidgetClass , rc_parent ,
388                       wa , na ) ;
389       if( bb->wframe == NULL ) bb->wtop = bb->wrowcol ;  /* topmost widget */
390    } else {
391       bb->wrowcol = NULL;
392       /* You cannot use:
393          if( bb->wframe == NULL ) bb->wtop = parent;
394          If you do so, the recorder window does not respond to mouse
395          input */
396 
397       bb->wtop = parent;
398    }
399    if( bb_type == MCW_BB_radio_one ){
400       initial_value = 1 ;
401    }
402 
403    XtVaGetValues( bb->wtop , XmNforeground , &fg_pix , NULL ) ;
404 
405    /***--- create the buttons ---***/
406 
407    STATUS("create toggle buttons") ;
408    for( ib=0 ; ib < num_but ; ib++ ){
409       bb->wbut[ib] = XtVaCreateManagedWidget(
410                         DIALOG , xmToggleButtonWidgetClass ,
411                            is_popup ?  parent : bb->wrowcol ,
412                            LABEL_ARG(label_but[ib]) ,
413                            XmNmarginHeight  , 0 ,
414                            XmNmarginWidth   , 0 ,
415                            XmNselectColor   , fg_pix ,  /* 04 Nov 1996 */
416                            XmNrecomputeSize , False ,
417                            XmNtraversalOn   , True  ,
418                            XmNinitialResourcesPersistent , False ,
419                         NULL ) ;
420 
421       if( cb != NULL ) {
422         cbws = (cb_wrap_struct *)calloc(1, sizeof(cb_wrap_struct));
423         cbws->bb = bb;
424         cbws->cb = cb;
425         cbws->cb_data = cb_data;
426         cbws->parent = parent;
427         cbws->is_popup = is_popup;
428         cbws->bb_type = bb_type;
429         if (dbg) fprintf(stderr,
430                         "Registering callback for\n"
431                         "   widget (%p) %s at ib = %d, labeled %s\n",
432                         bb->wbut[ib], XtName(bb->wbut[ib]), ib, label_but[ib]);
433         XtAddCallback(  bb->wbut[ib] ,
434                         XmNdisarmCallback ,
435                         new_MCW_bbox_cbwrap, (XtPointer)cbws);
436       }
437    }
438    for( ib=num_but ; ib < MCW_MAX_BB ; ib++ ) bb->wbut[ib] = NULL ;
439 
440    MCW_set_bbox( bb , initial_value ) ;
441    STATUS("manage button box") ;
442    if (bb->wrowcol) XtManageChild( bb->wrowcol ) ;
443 
444    bb->parent = bb->aux = NULL ;
445    RETURN(bb) ;
446 }
447 
448 /*------------------------------------------------------------------------*/
449 
MCW_bbox_hints(MCW_bbox * bb,int nh,char ** hh)450 void MCW_bbox_hints( MCW_bbox *bb , int nh , char **hh )
451 {
452    int ib ;
453 
454    if( bb == NULL || nh == 0 || hh == NULL ) return ;
455    if( nh > bb->nbut ) nh = bb->nbut ;
456    for( ib=0 ; ib < nh ; ib++ )
457      MCW_register_hint( bb->wbut[ib] , hh[ib] ) ;
458    return ;
459 }
460 
461 /*------------------------------------------------------------------------*/
462 
MCW_set_bbox(MCW_bbox * bb,int val)463 void MCW_set_bbox( MCW_bbox *bb , int val )
464 {
465    int     ib ;
466    RwcBoolean nset , oset ;
467 
468 ENTRY("MCW_set_bbox") ;
469 
470    if( bb == NULL ) EXRETURN ;  /* 01 Feb 2000 */
471    bb->value = val ;
472    for( ib=0 ; ib < bb->nbut ; ib++ ){
473      nset = ( val & (1<<ib) ) ? (True) : (False) ;
474      oset = XmToggleButtonGetState( bb->wbut[ib] ) ;
475      if( nset != oset && XtIsSensitive(bb->wbut[ib]) ){
476        XmToggleButtonSetState( bb->wbut[ib] , nset , False ) ;
477        XmUpdateDisplay( bb->wbut[ib] ) ;
478      }
479    }
480    EXRETURN ;
481 }
482 
483 /*------------------------------------------------------------------------*/
484 
MCW_val_bbox(MCW_bbox * bb)485 int MCW_val_bbox( MCW_bbox *bb )
486 {
487    int ib , val ;
488    RwcBoolean set ;
489 
490    if( bb == NULL ) return 0 ;  /* 01 Feb 2000 */
491    val = 0 ;
492    for( ib=0 ; ib < bb->nbut ; ib++ ){
493      set = XmToggleButtonGetState( bb->wbut[ib] ) ;
494      if( set ) val |= (1<<ib) ;
495    }
496    bb->value = val ;
497    return val ;
498 }
499 
500 /*----------------------------------------------------------------------
501   Create a new MCW_arrowval:   [label] [v][^] [value]
502     parent  = parent Widget
503     label   = string to put to left of arrows (NULL means none)
504     direc   = MCW_AV_downup    for down and up arrows
505               MCW_AV_leftright for left and right arrows
506               MCW_AV_updown    for up and down arrows
507               MCW_AV_optmenu   for option menu (completely different style!)
508     minval  = smallest value allowed } value is like in Scales:
509     maxval  = largest  value allowed }   an integer
510     inival  = initial  value         }
511     textype = MCW_AV_notext   to turn display of value off
512               MCW_AV_editext  to allow user to edit the text
513               MCW_AV_noactext like above, but no "activation" when the
514                               cursor leaves the window
515               MCW_AV_readtext to make the text display readonly
516     decim   = # of decimals to shift to left for display of value
517               (like Scales)
518 
519     delta_value = pointer to a function that will be called when the value
520                   changes (due to arrows or text edit);  not used if NULL
521     delta_data  = pointer to data to be passed to delta_value;
522                      delta_value( av , delta_data ) ;
523                   where av is a pointer to the MCW_arrowval that changed.
524                   (N.B.: the old value is available as av->old_ival
525                                                     or av->old_fval)
526 
527     text_proc   = pointer to a function that returns the text to display
528                     in the value window;  if non-NULL, then textype is
529                     forced to be MCW_AV_readtext;  the routine is called by
530 
531                       string = text_proc( av , text_data )
532 
533     text_data   = pointer to data to be passed to text_proc
534 ---------------------------------------------------------------------------*/
535 
new_MCW_arrowval(Widget parent,char * label,int direc,int minval,int maxval,int inival,int textype,int decim,gen_func * delta_value,XtPointer delta_data,str_func * text_proc,XtPointer text_data)536 MCW_arrowval * new_MCW_arrowval( Widget parent ,
537                                  char *label ,
538                                  int    direc ,
539                                  int    minval , int maxval , int inival ,
540                                  int    textype ,  int decim ,
541                                  gen_func *delta_value, XtPointer delta_data,
542                                  str_func *text_proc  , XtPointer text_data
543                                )
544 {
545    MCW_arrowval *av = NULL ;
546    int asizx = 20 , asizy = 15 ;  /* arrow sizes */
547    int aup , adown ;
548 
549 ENTRY("new_MCW_arrowval") ;
550 
551    /** July 1996: optmenu capability as a dropin for arrowval **/
552 
553    if( direc == MCW_AV_optmenu ){
554      av = new_MCW_optmenu( parent , label , minval,maxval,inival , decim ,
555                            delta_value , delta_data , text_proc , text_data ) ;
556      RETURN(av) ;
557    }
558 
559    av = myXtNew( MCW_arrowval ) ;
560    STATUS("creating wrowcol") ;
561    av->wrowcol = XtVaCreateWidget(
562                     DIALOG , xmRowColumnWidgetClass , parent ,
563 
564                        XmNpacking      , XmPACK_TIGHT ,
565                        XmNorientation  , XmHORIZONTAL ,
566                        XmNmarginHeight , 0 ,
567                        XmNmarginWidth  , 0 ,
568                        XmNspacing      , 0 ,
569 #if 0
570                        XmNresizeHeight , False ,
571                        XmNresizeWidth  , False ,
572 #endif
573                        XmNinitialResourcesPersistent , False ,
574                        XmNtraversalOn , True ,
575                     NULL ) ;
576 
577    if( label != NULL && strlen(label) > 0 ){
578       XmString   xstr = XmStringCreateLtoR( label , XmFONTLIST_DEFAULT_TAG );
579       XmFontList xflist = (XmFontList)NULL ;
580 
581       STATUS("creating wlabel") ;
582       av->wlabel = XtVaCreateManagedWidget(
583                     DIALOG , xmLabelWidgetClass , av->wrowcol ,
584                        XmNlabelString   , xstr  ,
585                        XmNrecomputeSize , False ,
586                        XmNmarginWidth   , 0     ,
587                        XmNinitialResourcesPersistent , False ,
588                     NULL ) ;
589       LABELIZE(av->wlabel) ;
590       XtVaGetValues( av->wlabel , XmNfontList , &xflist , NULL ) ;
591 
592       STATUS("getting label height") ;
593       if( xflist != (XmFontList)NULL ){
594         asizy = XmStringHeight( xflist , xstr ) ;
595       } else {
596         static int first = 1 ;
597         if( first ){ ERROR_message("Can't get font list?"); first=0; }
598       }
599       STATUS("freeing xstr") ;
600       XmStringFree( xstr ) ;
601 
602    } else {
603       av->wlabel = NULL ;
604    }
605 
606    if( asizx < asizy ) asizx = asizy ;
607    else                asizy = asizx ;
608 
609    STATUS("creating item labels") ;
610 
611    adown = (direc==MCW_AV_leftright) ? XmARROW_LEFT
612           :(direc==MCW_AV_downup   ) ? XmARROW_DOWN : XmARROW_UP   ;
613 
614    aup   = (direc==MCW_AV_leftright) ? XmARROW_RIGHT
615           :(direc==MCW_AV_downup   ) ? XmARROW_UP   : XmARROW_DOWN ;
616 
617    av->wdown = XtVaCreateManagedWidget(
618                   "arrow" , xmArrowButtonWidgetClass , av->wrowcol ,
619 
620                      XmNarrowDirection , adown ,
621 
622                      XmNheight , asizy , XmNwidth , asizx ,
623                      XmNborderWidth , 0 ,
624 
625                      XmNinitialResourcesPersistent , False ,
626                      XmNtraversalOn , True ,
627                   NULL ) ;
628 
629    av->wup    = XtVaCreateManagedWidget(
630                   "arrow" , xmArrowButtonWidgetClass , av->wrowcol ,
631 
632                      XmNarrowDirection , aup ,
633 
634                      XmNheight , asizy , XmNwidth , asizx ,
635                      XmNborderWidth , 0 ,
636 
637                      XmNinitialResourcesPersistent , False ,
638                      XmNtraversalOn , True ,
639                   NULL ) ;
640 
641    XtAddCallback( av->wdown , XmNarmCallback    , AV_press_CB , av ) ;
642    XtAddCallback( av->wdown , XmNdisarmCallback , AV_press_CB , av ) ;
643    XtAddCallback( av->wup   , XmNarmCallback    , AV_press_CB , av ) ;
644    XtAddCallback( av->wup   , XmNdisarmCallback , AV_press_CB , av ) ;
645 
646    if( text_proc != NULL && textype != MCW_AV_notext )
647       textype = MCW_AV_readtext ;
648 
649    switch( textype ){
650 
651       default:
652       case MCW_AV_notext:
653          av->wtext     = NULL ;
654          av->text_CB   = NULL ;
655          av->text_data = NULL ;
656       break ;
657 
658       /* Note hardwire of 9 columns of text, here and in AV_fval_to_char;
659          this CANNOT be changed just by changing AV_NCOL below, you must
660          also edit the sprintf formats in AV_fval_to_char.
661 
662          If text_proc is not NULL, then av->wtext could have its dimensions
663          changed later to handle the user supplied string.  My point above
664          is that the default text_proc is hardwired to 9 characters wide.
665       */
666 
667 #ifndef AV_NCOL
668 #define AV_NCOL 9
669 #endif
670 
671       case MCW_AV_readtext:
672          STATUS("creating wtext1") ;
673          av->wtext = XtVaCreateManagedWidget(
674                        DIALOG , TEXT_CLASS , av->wrowcol ,
675 
676                           XmNcolumns         , AV_NCOL ,
677                           XmNeditable        , False ,
678                           XmNmaxLength       , AV_NCOL ,
679                           XmNresizeWidth     , False ,
680                           XmNshadowThickness , 0 ,
681 #if 0
682                           XmNsensitive       , False ,   /* looks bad */
683 #endif
684                           XmNmarginHeight    , 1 ,
685                           XmNmarginWidth     , 1 ,
686 
687                           XmNcursorPositionVisible , False ,
688 
689                           XmNinitialResourcesPersistent , False ,
690                           XmNtraversalOn , True ,
691                        NULL ) ;
692 
693          av->text_CB   = (text_proc != NULL ) ? (text_proc)
694                                               : (AV_default_text_CB) ;
695          av->text_data = text_data ;
696       break ;
697 
698       case MCW_AV_noactext:                   /* noactext added 08 Feb 1999 */
699       case MCW_AV_editext:{
700          Widget wf ; int maxlen ;
701 
702          if( textype == MCW_AV_noactext ){
703             STATUS("creating frame") ;
704             wf = XtVaCreateWidget( DIALOG , xmFrameWidgetClass , av->wrowcol ,
705                                       XmNshadowType , XmSHADOW_OUT ,
706                                       XmNshadowThickness , 1 ,
707                                       XmNtraversalOn , True ,
708                                       XmNinitialResourcesPersistent , False ,
709                                    NULL ) ;
710             maxlen = AV_MAXLEN ;
711          } else {
712             wf     = av->wrowcol ;
713             maxlen = AV_NCOL ;
714          }
715 
716          STATUS("creating wtext2") ;
717          av->wtext = XtVaCreateManagedWidget(
718                        DIALOG , TEXT_CLASS , wf ,
719 
720                           XmNcolumns         , AV_NCOL ,
721                           XmNeditable        , True ,
722                           XmNmaxLength       , maxlen ,
723                           XmNresizeWidth     , False ,
724 
725                           XmNmarginHeight    , 1 ,
726                           XmNmarginWidth     , 1 ,
727 
728                           XmNcursorPositionVisible , True ,
729                           XmNblinkRate , 0 ,
730                           XmNautoShowCursorPosition , True ,
731 
732                           XmNinitialResourcesPersistent , False ,
733                           XmNtraversalOn , True ,
734                        NULL ) ;
735 
736          if( textype == MCW_AV_noactext ) XtManageChild(wf) ;
737 
738          if( textype == MCW_AV_editext ){
739             XtAddCallback( av->wtext , XmNactivateCallback    ,
740                                        AV_textact_CB , av ) ; /* return key */
741 
742             XtAddCallback( av->wtext , XmNlosingFocusCallback ,
743                                        AV_textact_CB , av ) ; /* tab key */
744 
745             XtInsertEventHandler( av->wtext ,        /* notify when */
746                                   LeaveWindowMask ,  /* pointer leaves */
747                                   FALSE ,            /* this window */
748                                   AV_leave_EV ,
749                                   (XtPointer) av ,
750                                   XtListTail ) ;     /* last in queue */
751          }
752 
753          av->text_CB   = AV_default_text_CB ;
754          av->text_data = NULL ;
755       }
756       break ;
757 
758    }
759 
760    av->wname = NULL ;
761 
762    XtManageChild( av->wrowcol ) ;
763 
764    if( minval < maxval ){
765       av->fmin = av->imin = minval ; AV_SHIFT_VAL(decim,av->fmin) ;
766       av->fmax = av->imax = maxval ; AV_SHIFT_VAL(decim,av->fmax) ;
767    } else {
768       av->fmin = av->imin = -9999999 ; AV_SHIFT_VAL(decim,av->fmin) ;
769       av->fmax = av->imax =  9999999 ; AV_SHIFT_VAL(decim,av->fmax) ;
770    }
771    av->decimals  = decim ;
772    av->timer_id  = 0 ;
773    av->fastdelay = MCW_AV_shortdelay ;  /* default delay on 2nd call */
774 
775    av->fval = av->ival = inival ; AV_SHIFT_VAL(decim,av->fval) ;
776 
777    av->sval = av->old_sval = NULL ;  /* string values */
778 
779    av->block_assign_actions = 0 ;    /* don't block these actions */
780    av->wmenu  = NULL ;               /* signal that this is NOT an optmenu */
781    av->optmenu_call_if_unchanged = 0 ; /* 10 Oct 2007 */
782 
783    AV_assign_ival( av , inival ) ;
784 
785    av->dval_CB   = delta_value ;
786    av->dval_data = delta_data ;
787 
788    av->allow_wrap = 0 ;
789 
790    av->parent = av->aux = NULL ;
791    av->fstep = 0.0 ;  /* 16 Feb 1999 */
792    RETURN(av) ;
793 }
794 
795 /*-----------------------------------------------------------------------*/
796 
AV_colsize()797 int AV_colsize()                      /* 11 Dec 2001 */
798 {
799    int cc=20 ; char *ee ;
800    ee = getenv("AFNI_MENU_COLSIZE") ;
801    if( ee != NULL ){
802       cc = (int) strtol(ee,NULL,10) ;
803       if( cc < 9 ) cc = 10 ;
804    }
805    return cc ;
806 }
807 
808 /*-----------------------------------------------------------------------
809   This can be used as a "drop in" replacement for a arrowval with a
810   small fixed number of elements.  The textype argument is missing because
811   the only one that makes sense is MCW_AV_readtext (readonly text as button
812   labels).  The direc argument is missing because that choice has already
813   been made.
814 -------------------------------------------------------------------------*/
815 
816 #define COLSIZE AV_colsize()  /* 11 Dec 2001: redefined from a constant */
817 
818 static void optmenu_EV( Widget,XtPointer,XEvent *,RwcBoolean *) ; /* prototype */
819 
820 static volatile int allow_optmenu_EV = 1 ;
821 
allow_MCW_optmenu_popup(int ii)822 void allow_MCW_optmenu_popup( int ii ){ allow_optmenu_EV = ii ; }
823 
824 #undef  USE_FIXUP
825 #ifdef  USE_FIXUP
826 static void optmenu_EV_fixup( Widget ww ) ;
827 #endif
828 
829 
830 /*
831 This is the only fix we could come up with to keep
832 AFNI from crashing when users open a pulldown menu
833 and select from a menu within:
834 
835 graph-->click Opt AND drag to Tran 0D  = BOOM
836 
837 Doing:
838 graph-->click Opt, RELEASE -->click Tran 0D = Hazah!
839 
840 The problem is either in Lesstif or Xt.
841 
842 What we do is capture the button release over such
843 menus and dispatch a button press immediately. So
844 every time there is a button release atop such menus,
845 there is an additional button press call done.
846 
847 That seems to do the trick, we hope.
848 
849             Feb 13 2009, [LPatrol]
850 */
text_EV(int v)851 const char *text_EV(int v)
852 {
853    switch (v) {
854       case EnterNotify:
855          return("enter");
856       case LeaveNotify:
857          return("leave");
858       case ButtonPress:
859          return("press");
860       case ButtonRelease:
861          return("release");
862       default:
863          return("dunno");
864    }
865    return("weird");
866 }
enter_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)867 void enter_EV( Widget w , XtPointer client_data ,
868                   XEvent * ev , RwcBoolean * continue_to_dispatch )
869 {
870    XLeaveWindowEvent * lev = (XLeaveWindowEvent *) ev ;
871    XButtonEvent *bev = (XButtonEvent *)ev;
872    MCW_arrowval *av = (MCW_arrowval *)client_data;
873    int is_popup = 0;
874    static Widget widlist[10000];
875    int N_widlist=0;
876    int dbg =0;
877 
878    #ifdef USING_LESSTIF
879    if (CPU_IS_64_BIT() ){
880       is_popup = is_daddy_popup(w);
881       if (dbg > 1) {
882          fprintf(stderr,
883                      "\n"
884                      "ispopup=%d\n"
885                      "%s bev->button = %d\n"
886                      "av->wdown=%p, av->wlabel=%p\n"
887                      "w        =%p, w         =%p\n"
888                      "av->wrowcol=%p\n"
889                      "ev->type %d (realized: %d) \n"
890                      "  Queued %d, QAF %d, QAR %d\n"
891                      "E%d,L%d,P%d,R%d\n"
892                      "\n",
893                      is_popup, text_EV(lev->type), bev->button,
894                      av->wdown, av->wlabel, w, w, av->wrowcol,
895                      lev->type,
896                      XtIsRealized(w),
897                      XEventsQueued(XtDisplay(w), QueuedAlready ),
898                      XEventsQueued(XtDisplay(w), QueuedAfterFlush ),
899                      XEventsQueued(XtDisplay(w), QueuedAfterReading ),
900                      EnterNotify, LeaveNotify, ButtonPress, ButtonRelease);
901       } else if (dbg) {
902          fprintf(stderr,
903                      "\n"
904                      "%s widget %p, button = %d\n""\n",
905                      text_EV(lev->type), w, bev->button);
906 
907       }
908 
909       /* NOTICE: This last ditch fix only for an option menu inside a pulldown
910          window.  */
911       if (is_popup && bev->button == 1 && ev->type == ButtonRelease) {
912                      /* Button release over menu button: DUCK! */
913          if (dbg) fprintf(stderr,"Holy Toledo!\n");
914          ev->type = ButtonPress;  /* Make that be a button press first */
915          XtDispatchEvent(ev); /* pray real hard now */
916          /* DO NOT reset ev->type to ButtonRelease; don't ask. */
917       }
918    }
919    #endif
920 }
921 
922 /* create a chooser list of text strings */
923 /* label - title string to the left of the chooser dropdown
924    minval - minimum value of index (usually 0)
925    maxval - maximum value of index (usually the number of strings - 1
926    inival - initial value of index (to get default string shown)
927    decim - number of decimal places to shift a number in a string (I haven't used this yet)
928    delta_value - callback function when item is changed (use void function)
929    delta_data - ?
930    text_proc - function to use as the chooser list is filled
931                (usually MCW_av_substring_CB)
932    text_data - list of strings to fill chooser list (char **)
933                (probably should not freed (static may be good too) )
934 */
new_MCW_optmenu(Widget parent,char * label,int minval,int maxval,int inival,int decim,gen_func * delta_value,XtPointer delta_data,str_func * text_proc,XtPointer text_data)935 MCW_arrowval * new_MCW_optmenu( Widget parent ,
936                                 char *label ,
937                                 int   minval , int maxval , int inival ,
938                                 int decim ,
939                                 gen_func *delta_value, XtPointer delta_data,
940                                 str_func *text_proc  , XtPointer text_data
941                               )
942 {
943 ENTRY("new_MCW_optmenu") ;
944 
945    #ifdef USING_LESSTIF_NOT_DOING_THIS_CRAP
946       if (CPU_IS_64_BIT() ){
947          RETURN(new_MCW_optmenu_64fix(
948                   parent , label ,
949                   minval , maxval , inival ,
950                   decim ,
951                   delta_value, delta_data,
952                   text_proc  , text_data));
953       }
954    #endif
955 
956    RETURN(new_MCW_optmenu_orig(
957                   parent , label ,
958                   minval , maxval , inival ,
959                   decim ,
960                   delta_value, delta_data,
961                   text_proc  , text_data));
962 }
963 
new_MCW_optmenu_orig(Widget parent,char * label,int minval,int maxval,int inival,int decim,gen_func * delta_value,XtPointer delta_data,str_func * text_proc,XtPointer text_data)964 MCW_arrowval * new_MCW_optmenu_orig( Widget parent ,
965                                 char *label ,
966                                 int   minval , int maxval , int inival ,
967                                 int decim ,
968                                 gen_func *delta_value, XtPointer delta_data,
969                                 str_func *text_proc  , XtPointer text_data
970                               )
971 {
972    MCW_arrowval *av = myXtNew( MCW_arrowval ) ;
973    Widget wmenu , wbut ;
974    Arg args[5] ;
975    int nargs , ival ;
976    XmString xstr ;
977    char *butlabel , *blab ;
978    int dbg = 0;
979 
980 ENTRY("new_MCW_optmenu_orig") ;
981 
982    /** create the menu window **/
983 
984 STATUS("creating menu window") ;
985    av->wmenu = wmenu = XmCreatePulldownMenu( parent , MENU , NULL , 0 ) ;
986    av->optmenu_call_if_unchanged = 0 ;  /* 10 Oct 2007 */
987 
988    VISIBILIZE_WHEN_MAPPED(wmenu) ;
989 #if 0   /* doesn't work well if optmenu is inside a popup! */
990    if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(wmenu) ;
991 #endif
992 
993    /** create the button that pops down the menu **/
994 
995    nargs = 0 ;
996    XtSetArg( args[nargs] , XmNsubMenuId , wmenu ) ; nargs++ ;
997    XtSetArg( args[nargs] , XmNtraversalOn, True ) ; nargs++ ;
998 
999    if( label == NULL ) label = " " ;  /* 24 Sep 2001 */
1000 
1001    xstr = XmStringCreateLtoR( label , XmFONTLIST_DEFAULT_TAG ) ;
1002    XtSetArg( args[nargs] , XmNlabelString , xstr ) ; nargs++ ;
1003 
1004 STATUS("creating option menu") ;
1005    av->wrowcol = XmCreateOptionMenu( parent , DIALOG , args , nargs ) ;
1006    XmStringFree(xstr) ;
1007    XtVaSetValues( av->wrowcol ,
1008                      XmNmarginWidth  , 0 ,
1009                      XmNmarginHeight , 0 ,
1010                      XmNspacing      , 2 ,
1011                      XmNtraversalOn  , True ,
1012                   NULL ) ;
1013 
1014    av->wlabel = XmOptionLabelGadget (av->wrowcol) ;
1015    av->wdown  = XmOptionButtonGadget(av->wrowcol) ;
1016    av->wup    = NULL ;
1017    av->wtext  = NULL ;  /* signal that this is NOT really an arrowval */
1018    av->wname  = NULL ;
1019 
1020    XtVaSetValues( av->wlabel ,              /* label next to menu button */
1021                      XmNmarginWidth  , 0 ,
1022                      XmNmarginHeight , 0 ,
1023                      XmNmarginBottom , 0 ,
1024                      XmNmarginTop    , 0 ,
1025                      XmNmarginRight  , 0 ,
1026                      XmNmarginLeft   , 0 ,
1027                   NULL ) ;
1028 
1029    if( label == NULL || strlen(label) == 0 ){
1030       XtVaSetValues( av->wlabel  , XmNwidth   , 0 , NULL ) ;
1031       XtVaSetValues( av->wrowcol , XmNspacing , 2 , NULL ) ;
1032    }
1033 
1034    XtVaSetValues( av->wdown ,               /* menu button */
1035                      XmNmarginWidth  , 0 ,
1036                      XmNmarginHeight , 0 ,
1037                      XmNmarginBottom , 0 ,
1038                      XmNmarginTop    , 0 ,
1039                      XmNmarginRight  , 0 ,
1040                      XmNmarginLeft   , 0 ,
1041                      XmNtraversalOn  , True ,
1042                      XmNhighlightThickness , 0 ,
1043                   NULL ) ;
1044 
1045    av->text_CB   = (text_proc != NULL ) ? (text_proc)
1046                                         : (AV_default_text_CB) ;
1047    av->text_data = text_data ;
1048    av->decimals  = decim ;
1049    av->fmin      = av->imin = minval ; AV_SHIFT_VAL(decim,av->fmin) ;
1050    av->fmax      = av->imax = maxval ; AV_SHIFT_VAL(decim,av->fmax) ;
1051    av->sval      = av->old_sval = NULL ;
1052 
1053    av->block_assign_actions = 1 ;    /* temporarily block these actions */
1054 
1055    /** create the buttons on the menu window **/
1056 
1057    for( ival=minval ; ival <= maxval ; ival++ ){
1058 
1059       AV_assign_ival( av , ival ) ;  /* just to create label */
1060 
1061       blab = butlabel = XtNewString( av->sval ) ;
1062       if( av->text_CB==AV_default_text_CB && butlabel[0]==' ' && minval >= 0 ){
1063         blab += 1 ;  /* deal with leading blanks in default routine */
1064       }
1065 
1066       xstr = XmStringCreateLtoR( blab , XmFONTLIST_DEFAULT_TAG ) ;
1067 
1068       wbut = XtVaCreateManagedWidget(
1069                 DIALOG , xmPushButtonWidgetClass , wmenu ,
1070                   XmNlabelString  , xstr ,
1071                   XmNmarginWidth  , 0 ,
1072                   XmNmarginHeight , 0 ,
1073                   XmNmarginBottom , 0 ,
1074                   XmNmarginTop    , 0 ,
1075                   XmNmarginRight  , 0 ,
1076                   XmNmarginLeft   , 0 ,
1077                   XmNuserData     , (XtPointer)ITOP(ival) , /* Who am I? */
1078                   XmNtraversalOn  , True  ,
1079                   XmNinitialResourcesPersistent , False ,
1080                 NULL ) ;
1081 
1082       XmStringFree(xstr) ; myXtFree(butlabel) ;
1083 
1084       XtAddCallback( wbut , XmNactivateCallback , AVOPT_press_CB , av ) ;
1085 
1086       if( ival == inival )
1087         XtVaSetValues( av->wrowcol ,  XmNmenuHistory , wbut , NULL ) ;
1088    }
1089 
1090    XtManageChild( av->wrowcol ) ;
1091 
1092    av->timer_id  = 0 ;  /* won't be used for this type of arrowval! */
1093    av->fastdelay = 0 ;
1094 
1095    av->block_assign_actions = 0 ;   /* unblock these actions */
1096 
1097    AV_assign_ival( av , inival ) ;  /* actual initial assignment */
1098 
1099    av->dval_CB   = delta_value ;
1100    av->dval_data = delta_data ;
1101 
1102    av->allow_wrap = 0 ;
1103 
1104    av->parent = av->aux = NULL ;
1105    av->fstep = 0.0 ;  /* 16 Feb 1999 */
1106 
1107    /* 11 Dec 2001: allow user to choose via Button-3 popup */
1108 
1109    if( allow_optmenu_EV ){
1110      XtInsertEventHandler( av->wrowcol ,      /* handle events in optmenu */
1111                            ButtonPressMask ,  /* button presses */
1112                            FALSE ,            /* nonmaskable events? */
1113                            optmenu_EV ,       /* handler */
1114                            (XtPointer) av ,   /* client data */
1115                            XtListTail ) ;     /* last in queue */
1116 #ifdef USE_FIXUP
1117      optmenu_EV_fixup( av->wrowcol ) ;
1118 #endif
1119    }
1120 
1121    RETURN(av) ;
1122 }
1123 
1124 
new_MCW_optmenu_64fix(Widget parent,char * label,int minval,int maxval,int inival,int decim,gen_func * delta_value,XtPointer delta_data,str_func * text_proc,XtPointer text_data)1125 MCW_arrowval * new_MCW_optmenu_64fix( Widget parent ,
1126                                 char *label ,
1127                                 int   minval , int maxval , int inival ,
1128                                 int decim ,
1129                                 gen_func *delta_value, XtPointer delta_data,
1130                                 str_func *text_proc  , XtPointer text_data
1131                               )
1132 {
1133    MCW_arrowval *av = myXtNew( MCW_arrowval ) ;
1134    Widget wmenu , wbut, rcholder , lb, rcparent;
1135    Arg args[5] ;
1136    int nargs , ival ;
1137    XmString xstr ;
1138    char *butlabel , *blab ;
1139    int dbg = 0;
1140 
1141 ENTRY("new_MCW_optmenu_64fix") ;
1142 
1143 rcparent = XtVaCreateWidget ("rowcolumn",
1144          xmRowColumnWidgetClass, parent,
1145          XmNpacking, XmPACK_TIGHT,
1146          XmNorientation , XmHORIZONTAL ,
1147          XmNmarginHeight, 0 ,
1148          XmNmarginWidth , 0 ,
1149          NULL);   /** create the menu window **/
1150 
1151    av->wmenu = wmenu = XmCreatePulldownMenu( rcparent , MENU , NULL , 0 ) ;
1152    av->optmenu_call_if_unchanged = 0 ;  /* 10 Oct 2007 */
1153 
1154    VISIBILIZE_WHEN_MAPPED(wmenu) ;
1155 #if 0   /* doesn't work well if optmenu is inside a popup! */
1156    if( !AFNI_yesenv("AFNI_DISABLE_TEAROFF") ) TEAROFFIZE(wmenu) ;
1157 #endif
1158 
1159    /** create the button that pops down the menu **/
1160 
1161    nargs = 0 ;
1162    XtSetArg( args[nargs] , XmNsubMenuId , wmenu ) ; nargs++ ;
1163    XtSetArg( args[nargs] , XmNtraversalOn, True ) ; nargs++ ;
1164 
1165    if( label == NULL ) label = " " ;  /* 24 Sep 2001 */
1166 
1167    rcholder = XtVaCreateWidget ("rowcolumn",
1168          xmRowColumnWidgetClass, rcparent,
1169          XmNpacking, XmPACK_TIGHT,
1170          XmNorientation , XmHORIZONTAL ,
1171                   XmNmarginWidth  , 0 ,
1172                   XmNmarginHeight , 0 ,
1173                   XmNmarginBottom , 0 ,
1174                   XmNmarginTop    , 0 ,
1175                   XmNmarginRight  , 0 ,
1176                   XmNmarginLeft   , 0 ,
1177                      XmNspacing      , 0 ,
1178          NULL);
1179    lb = XtVaCreateManagedWidget (label,
1180                                xmLabelWidgetClass, rcholder,
1181                                XmNmarginHeight, 0 ,
1182                                XmNmarginWidth , 0 ,
1183                   XmNmarginWidth  , 0 ,
1184                   XmNmarginHeight , 0 ,
1185                   XmNmarginBottom , 0 ,
1186                   XmNmarginTop    , 0 ,
1187                   XmNmarginRight  , 0 ,
1188                   XmNmarginLeft   , 0 ,
1189                               NULL) ;
1190    LABELIZE(lb) ;
1191 
1192    xstr = XmStringCreateLtoR( "" , XmFONTLIST_DEFAULT_TAG ) ;
1193    XtSetArg( args[nargs] , XmNlabelString , xstr ) ; nargs++ ;
1194    av->wrowcol = XmCreateOptionMenu( rcholder , DIALOG , args , nargs ) ;
1195    XmStringFree(xstr) ;
1196    XtVaSetValues( av->wrowcol ,
1197                      XmNmarginWidth  , 0 ,
1198                      XmNmarginHeight , 0 ,
1199                      XmNspacing      , 2 ,
1200                      XmNtraversalOn  , True ,
1201                   NULL ) ;
1202 
1203    #ifdef USING_LESSTIF
1204    if (CPU_IS_64_BIT() ){
1205       XtInsertEventHandler( av->wrowcol ,
1206                                ButtonReleaseMask ,
1207                                FALSE ,
1208                                enter_EV,
1209                                (XtPointer) av,
1210                                XtListHead) ;
1211       /*
1212       XtInsertEventHandler( av->wrowcol ,
1213                                ButtonPressMask ,
1214                                FALSE ,
1215                                enter_EV,
1216                                (XtPointer) av ,
1217                                XtListHead) ;
1218       XtInsertEventHandler( av->wrowcol ,
1219                                EnterWindowMask ,
1220                                FALSE ,
1221                                enter_EV,
1222                                (XtPointer) av,
1223                                XtListHead) ;
1224 
1225       XtInsertEventHandler( av->wrowcol ,
1226                                LeaveWindowMask ,
1227                                FALSE ,
1228                                enter_EV,
1229                                (XtPointer) av,
1230                                XtListHead) ;
1231       */
1232    }
1233    #endif
1234    av->wlabel = lb ;
1235    av->wdown  = XmOptionButtonGadget(av->wrowcol) ;
1236    av->wup    = NULL ;
1237    av->wtext  = NULL ;  /* signal that this is NOT really an arrowval */
1238 
1239    XtVaSetValues( av->wlabel ,              /* label next to menu button */
1240                      XmNmarginWidth  , 0 ,
1241                      XmNmarginHeight , 0 ,
1242                      XmNmarginBottom , 0 ,
1243                      XmNmarginTop    , 0 ,
1244                      XmNmarginRight  , 0 ,
1245                      XmNmarginLeft   , 0 ,
1246                   NULL ) ;
1247 
1248    if( label == NULL || strlen(label) == 0 ){
1249       XtVaSetValues( av->wlabel  , XmNwidth   , 0 , NULL ) ;
1250       XtVaSetValues( av->wrowcol , XmNspacing , 2 , NULL ) ;
1251    }
1252 
1253    XtVaSetValues( av->wdown ,               /* menu button */
1254                      XmNmarginWidth  , 0 ,
1255                      XmNmarginHeight , 0 ,
1256                      XmNmarginBottom , 0 ,
1257                      XmNmarginTop    , 0 ,
1258                      XmNmarginRight  , 0 ,
1259                      XmNmarginLeft   , 0 ,
1260                      XmNtraversalOn  , True ,
1261                      XmNhighlightThickness , 0 ,
1262                   NULL ) ;
1263 
1264    av->text_CB   = (text_proc != NULL ) ? (text_proc)
1265                                         : (AV_default_text_CB) ;
1266    av->text_data = text_data ;
1267    av->decimals  = decim ;
1268    av->fmin      = av->imin = minval ; AV_SHIFT_VAL(decim,av->fmin) ;
1269    av->fmax      = av->imax = maxval ; AV_SHIFT_VAL(decim,av->fmax) ;
1270    av->sval      = av->old_sval = NULL ;
1271 
1272    av->block_assign_actions = 1 ;    /* temporarily block these actions */
1273 
1274    /** create the buttons on the menu window **/
1275 
1276    for( ival=minval ; ival <= maxval ; ival++ ){
1277 
1278       AV_assign_ival( av , ival ) ;  /* just to create label */
1279 
1280       blab = butlabel = XtNewString( av->sval ) ;
1281       if( av->text_CB==AV_default_text_CB && butlabel[0]==' ' && minval >= 0 ){
1282         blab += 1 ;  /* deal with leading blanks in default routine */
1283       }
1284 
1285       xstr = XmStringCreateLtoR( blab , XmFONTLIST_DEFAULT_TAG ) ;
1286 
1287       wbut = XtVaCreateManagedWidget(
1288                 DIALOG , xmPushButtonWidgetClass , wmenu ,
1289                   XmNlabelString  , xstr ,
1290                   XmNmarginWidth  , 0 ,
1291                   XmNmarginHeight , 0 ,
1292                   XmNmarginBottom , 0 ,
1293                   XmNmarginTop    , 0 ,
1294                   XmNmarginRight  , 0 ,
1295                   XmNmarginLeft   , 0 ,
1296                   XmNuserData     , (XtPointer)ITOP(ival) , /* Who am I? */
1297                   XmNtraversalOn  , True  ,
1298                   XmNinitialResourcesPersistent , False ,
1299                 NULL ) ;
1300 
1301       XmStringFree(xstr) ; myXtFree(butlabel) ;
1302 
1303       XtAddCallback( wbut , XmNactivateCallback , AVOPT_press_CB , av ) ;
1304 
1305       if( ival == inival )
1306         XtVaSetValues( av->wrowcol ,  XmNmenuHistory , wbut , NULL ) ;
1307    }
1308 
1309    XtManageChild( av->wrowcol ) ;
1310 
1311    av->timer_id  = 0 ;  /* won't be used for this type of arrowval! */
1312    av->fastdelay = 0 ;
1313 
1314    av->block_assign_actions = 0 ;   /* unblock these actions */
1315 
1316    AV_assign_ival( av , inival ) ;  /* actual initial assignment */
1317 
1318    av->dval_CB   = delta_value ;
1319    av->dval_data = delta_data ;
1320 
1321    av->allow_wrap = 0 ;
1322 
1323    av->parent = av->aux = NULL ;
1324    av->fstep = 0.0 ;  /* 16 Feb 1999 */
1325 
1326    /* 11 Dec 2001: allow user to choose via Button-3 popup */
1327 
1328    if( allow_optmenu_EV ){
1329      XtInsertEventHandler( av->wlabel ,      /* handle events in optmenu */
1330                            ButtonPressMask ,  /* button presses */
1331                            FALSE ,            /* nonmaskable events? */
1332                            optmenu_EV ,       /* handler */
1333                            (XtPointer) av ,   /* client data */
1334                            XtListTail ) ;     /* last in queue */
1335 #ifdef USE_FIXUP
1336      optmenu_EV_fixup( av->wlabel ) ;
1337 #endif
1338    }
1339    XtManageChild( rcholder);
1340    XtManageChild( rcparent);
1341    RETURN(av) ;
1342 }
1343 
1344 /*----------------------------------------------------------------------------
1345    Relabels all the buttons on an optmenu, adding or unmanaging as needed.
1346    The label and action callback remain the same.
1347 ------------------------------------------------------------------------------*/
1348 
refit_MCW_optmenu(MCW_arrowval * av,int minval,int maxval,int inival,int decim,str_func * text_proc,XtPointer text_data)1349 void refit_MCW_optmenu( MCW_arrowval *av ,
1350                         int  minval , int maxval , int inival , int decim ,
1351                         str_func *text_proc  , XtPointer text_data )
1352 {
1353    Widget *children=NULL , wbut , wmenu ;
1354    int  num_children=0 , ic , ival ;
1355    char *butlabel , *blab ;
1356    XmString xstr ;
1357    int maxbut ;   /* 23 Aug 2003 */
1358    static int iwarn=0;
1359 
1360 ENTRY("refit_MCW_optmenu") ;
1361 
1362    /** sanity check **/
1363 
1364    if( av == NULL || av->wmenu == NULL ) EXRETURN ;
1365    wmenu = av->wmenu ;
1366 
1367    /** get all the existing children **/
1368 
1369 #if 0
1370    XtUnmanageChild( av->wrowcol ) ; XtUnmanageChild( wmenu ) ;
1371 #endif
1372 
1373    XtVaGetValues( wmenu ,
1374                      XmNchildren    , &children ,
1375                      XmNnumChildren , &num_children ,
1376                   NULL ) ;
1377 
1378    /* 23 Aug 2003: replace hard limit of 255 buttons
1379                    with maxbut from environment variable */
1380 
1381    maxbut = AFNI_numenv( "AFNI_MAX_OPTMENU" ) ;
1382         if( maxbut <= 0 ) maxbut = 1024 ; /* up from 255 ZSS Aug. 4 2011 */
1383    else if( maxbut < 99 ) maxbut = 99 ;
1384    if( maxval > minval+maxbut ) {
1385       if (!iwarn % 15) {   /* ZSS June 2011 */
1386          INFO_message(
1387    "\n"
1388    "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
1389    "The number of sub-bricks in one of your datasets exceeds \n"
1390    "   the current maximum of %d. Some menus like Ulay/Olay/Thr \n"
1391    "   will not allow you to select sub-bricks beyond #%d.\n"
1392    "To access all sub-bricks from such menus, increase the value of \n"
1393    "   environment variable 'AFNI_MAX_OPTMENU'. You can do so for this \n"
1394    "   AFNI session via the 'Edit Environment' plugin. For a more lasting \n"
1395    "   fix, add the line:\n"
1396    "        AFNI_MAX_OPTMENU = XXX \n"
1397    "   under the '***ENVIRONMENT' section of your .afnirc file with XXX \n"
1398    "   being a suitably large number. \n"
1399    "   For details, search for 'AFNI_MAX_OPTMENU' in AFNI's README.environment.\n"
1400    "You can still use the 'Index' widget in the main AFNI controller\n"
1401    "   to access all sub-bricks in such large datasets.\n"
1402    "\n"
1403    "This message is shown intermittently.  This message is only\n"
1404    "a WARNING and does not mean that anything is seriously wrong!\n"
1405    "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
1406             , maxbut, maxbut);
1407       }
1408       ++iwarn;
1409       maxval = minval+maxbut ;  /* 23 Mar 2003 */
1410    }
1411    /** reset some internal parameters **/
1412 
1413    av->text_CB   = (text_proc != NULL ) ? (text_proc)
1414                                         : (AV_default_text_CB) ;
1415    av->text_data = text_data ;
1416    av->decimals  = decim ;
1417    av->fmin      = av->imin = minval ; AV_SHIFT_VAL(decim,av->fmin) ;
1418    av->fmax      = av->imax = maxval ; AV_SHIFT_VAL(decim,av->fmax) ;
1419 
1420    myXtFree(av->sval) ; myXtFree(av->old_sval) ;  /* 09 Mar 1999 */
1421 
1422    av->block_assign_actions = 1 ;    /* temporarily block these actions */
1423 
1424    /** create buttons anew **/
1425 
1426    STATUS("create buttons anew") ;
1427    for( ival=minval ; ival <= maxval ; ival++ ){
1428 
1429       ic = ival - minval ;           /* index into widget list */
1430 
1431       AV_assign_ival( av , ival ) ;  /* just to create label */
1432 
1433       blab = butlabel = XtNewString( av->sval ) ;
1434       if( av->text_CB==AV_default_text_CB && butlabel[0]==' ' && minval >= 0 ){
1435          blab += 1 ;  /* deal with leading blanks in default routine */
1436       }
1437 
1438       xstr = XmStringCreateLtoR( blab , XmFONTLIST_DEFAULT_TAG ) ;
1439 
1440       /** re-use old button if possible, otherwise add a new one **/
1441 
1442       if( ic < num_children ){
1443          XtPointer user_old=NULL ;
1444          int       ival_old ;
1445          XmString  xstr_old=NULL ;
1446 
1447          wbut = children[ic] ;
1448          XtVaGetValues( wbut ,
1449                            XmNlabelString , &xstr_old ,
1450                            XmNuserData    , &user_old ,
1451                         NULL ) ;
1452          ival_old = PTOI(user_old) ;
1453 
1454          if( ival_old != ival || XmStringCompare(xstr_old,xstr) != True ){
1455             STATUS("setting label in recycled button") ;
1456             XtVaSetValues( wbut ,
1457                               XmNlabelString, xstr,               /* change label */
1458                               XmNuserData   , (XtPointer)ITOP(ival), /* Who am I? */
1459                            NULL ) ;
1460          }
1461 #if 1
1462          STATUS("freeing xstr_old") ;
1463          XmStringFree( xstr_old ) ;
1464 #endif
1465          STATUS("managing child") ;
1466          XtManageChild( wbut ) ;    /* if not now managed */
1467       } else {
1468          STATUS("setting up new button") ;
1469          wbut = XtVaCreateManagedWidget(
1470                    DIALOG , xmPushButtonWidgetClass , wmenu ,
1471                      XmNlabelString  , xstr ,
1472                      XmNmarginWidth  , 0 ,
1473                      XmNmarginHeight , 0 ,
1474                      XmNmarginBottom , 0 ,
1475                      XmNmarginTop    , 0 ,
1476                      XmNmarginRight  , 0 ,
1477                      XmNmarginLeft   , 0 ,
1478                      XmNuserData     , (XtPointer)ITOP(ival) , /* Who am I? */
1479                      XmNtraversalOn , True  ,
1480                      XmNinitialResourcesPersistent , False ,
1481                    NULL ) ;
1482          XtAddCallback( wbut , XmNactivateCallback , AVOPT_press_CB , av ) ;
1483       }
1484 
1485       STATUS("freeing xstr") ;
1486       XmStringFree(xstr) ; myXtFree(butlabel) ;
1487 
1488       if( ival == inival ){
1489         STATUS("setting menu history") ;
1490         XtVaSetValues( av->wrowcol ,  XmNmenuHistory , wbut , NULL ) ;
1491       }
1492    }
1493 
1494    /** Unmanage extra children from an old incarnation **/
1495 
1496    ic = maxval-minval+1 ;  /* first child after those used above */
1497 
1498    if( ic < num_children ){
1499      STATUS("unmanaging unused children") ;
1500      XtUnmanageChildren( children + ic , num_children - ic ) ;
1501    }
1502 
1503    /** set number of columns to see **/
1504 
1505    STATUS("set number of columns") ;
1506    AVOPT_columnize( av , 1+(maxval-minval)/COLSIZE ) ;
1507 
1508 #if 0
1509    XtManageChild( wmenu ) ;
1510    XtManageChild( av->wrowcol ) ;
1511 #endif
1512 
1513 #if 0
1514    RWC_XtPopdown( XtParent(wmenu) ) ;  /* 28 Apr 1997 */
1515 #endif
1516 
1517    av->block_assign_actions = 0 ;   /* unblock these actions */
1518    AV_assign_ival( av , inival ) ;  /* actual initial assignment */
1519 
1520    EXRETURN ;
1521 }
1522 
1523 /*--------------------------------------------------------------------------
1524   11 Dec 2001: Provide a Button 3 list to choose from for an optmenu
1525 ----------------------------------------------------------------------------*/
1526 
optmenu_finalize(Widget w,XtPointer cd,MCW_choose_cbs * cbs)1527 static void optmenu_finalize( Widget w, XtPointer cd, MCW_choose_cbs *cbs )
1528 {
1529    MCW_arrowval *av = (MCW_arrowval *) cd ;
1530    int ival ;
1531 
1532 ENTRY("optmenu_finalize") ;
1533 
1534    if( av == NULL || av->wmenu == NULL ) EXRETURN ;
1535 
1536    ival = cbs->ival + av->imin ;
1537    AV_assign_ival( av , ival ) ;
1538 
1539    /* call user callback, if present */
1540 
1541    if( av->dval_CB != NULL &&
1542        (av->optmenu_call_if_unchanged || av->fval != av->old_fval) )
1543 #if 0
1544       av->dval_CB( av , av->dval_data ) ;
1545 #else
1546       AFNI_CALL_VOID_2ARG( av->dval_CB ,
1547                            MCW_arrowval * , av ,
1548                            XtPointer      , av->dval_data ) ;
1549 #endif
1550 
1551    EXRETURN ;
1552 }
1553 
1554 /*--------------------------------------------------------------------------*/
1555 /* 15 Mar 2004: fix the cursors on the optmenus with popups */
1556 
1557 #ifdef USE_FIXUP
1558 static volatile int    nwid = 0    ;
1559 static volatile Widget *wid = NULL ;
1560 
1561 /*- called if an optmenu is destroyed, to remove it from the fixup list -*/
1562 
optmenu_EV_fixup_CB(Widget ww,XtPointer xp,XtPointer cd)1563 static void optmenu_EV_fixup_CB( Widget ww , XtPointer xp, XtPointer cd )
1564 {
1565    int ii ;
1566 ENTRY("optmenu_EV_fixup_CB") ;
1567    for( ii=0 ; ii < nwid ; ii++ )
1568      if( wid[ii] == ww ) wid[ii] = (Widget)NULL ;
1569    EXRETURN ; ;
1570 }
1571 
1572 /*- called occasionally to see if anyone can be fixed yet -*/
1573 
1574 static volatile XtIntervalId timer_id = (XtIntervalId)0 ;
1575 static volatile XtAppContext timer_cx = (XtAppContext)NULL ;
1576 
optmenu_EV_fixup_timer_CB(XtPointer cd,XtIntervalId * id)1577 static void optmenu_EV_fixup_timer_CB( XtPointer cd , XtIntervalId *id )
1578 {
1579 ENTRY("optmenu_EV_fixup_timer_CB") ;
1580    optmenu_EV_fixup((Widget)NULL) ;
1581    timer_id = XtAppAddTimeOut( timer_cx, 3033, optmenu_EV_fixup_timer_CB, NULL ) ;
1582    EXRETURN ;
1583 }
1584 
1585 /*- called with NULL to fix anything on the current list;
1586     called with a Widget to put it on the to-be-fixed-up list -*/
1587 
optmenu_EV_fixup(Widget ww)1588 static void optmenu_EV_fixup( Widget ww )   /* 15 Mar 2004 - RWCox */
1589 {
1590    int ii , jj ;
1591    Widget *qwid ;
1592 
1593 ENTRY("optmenu_EV_fixup") ;
1594 
1595    if( ww == (Widget)NULL ){                   /* try to fix what's on the list */
1596      if( nwid == 0 ) EXRETURN ;  /* that was easy */
1597 if(PRINT_TRACING){ char str[256]; sprintf(str,"scanning %d widgets for fixing",nwid); STATUS(str); }
1598      for( ii=jj=0 ; ii < nwid ; ii++ ){
1599        if( wid[ii] != (Widget)NULL && XtIsRealized(wid[ii])      &&
1600            XtIsManaged(wid[ii])    && MCW_widget_visible(wid[ii])  ){
1601 if(PRINT_TRACING){ char str[256]; sprintf(str,"  about to fix ii=%d",ii); STATUS(str); }
1602          POPUP_cursorize(wid[ii]) ;
1603          XtRemoveCallback( wid[ii], XmNdestroyCallback, optmenu_EV_fixup_CB, NULL ) ;
1604          wid[ii] = NULL ; jj++ ;
1605 if(PRINT_TRACING){ char str[256]; sprintf(str,"  #%d cursor fixed",ii); STATUS(str); }
1606        }
1607 else if(PRINT_TRACING){ char str[256]; sprintf(str,"  #%d not fixable",ii); STATUS(str); }
1608      }
1609      if( jj == 0 ){ STATUS("nothing to fix"); EXRETURN; }
1610      if( jj >= nwid ){ STATUS("fixed them all"); free(wid); wid = NULL; nwid = 0; EXRETURN; }
1611      qwid = (Widget *) calloc( nwid , sizeof(Widget) ) ;
1612      for( ii=jj=0 ; ii < nwid ; ii++ )
1613        if( wid[ii] != (Widget)NULL ) qwid[jj++] = wid[ii] ;
1614      nwid = jj ;
1615      for( ii=0 ; ii < nwid ; ii++ ) wid[ii] = qwid[ii] ;
1616      free(qwid) ;
1617 if(PRINT_TRACING){ char str[256]; sprintf(str,"  %d left to fix later",nwid); STATUS(str); }
1618 
1619    } else {                               /* add to the list */
1620      wid = (Widget *)realloc( (void *)wid , sizeof(Widget)*(nwid+1) ) ;
1621      wid[nwid++] = ww ;
1622      XtAddCallback( ww, XmNdestroyCallback, optmenu_EV_fixup_CB, NULL ) ;
1623      if( timer_cx == (XtAppContext)NULL ){
1624 STATUS("  starting first timer callback") ;
1625        timer_cx = XtWidgetToApplicationContext(ww) ;
1626        timer_id = XtAppAddTimeOut( timer_cx, 5055, optmenu_EV_fixup_timer_CB, NULL ) ;
1627      }
1628 if(PRINT_TRACING){ char str[256]; sprintf(str," now have %d to fix",nwid); STATUS(str); }
1629    }
1630    EXRETURN ;
1631 }
1632 #endif  /* USE_FIXUP */
1633 
1634 /*--------------------------------------------------------------------------*/
1635 
optmenu_EV(Widget w,XtPointer cd,XEvent * ev,RwcBoolean * continue_to_dispatch)1636 static void optmenu_EV( Widget w , XtPointer cd ,
1637                         XEvent *ev , RwcBoolean *continue_to_dispatch )
1638 {
1639    MCW_arrowval *av = (MCW_arrowval *) cd ;
1640    int  ic , ival , sval , nstr ;
1641    XButtonEvent *bev = (XButtonEvent *) ev ;
1642    Dimension lw=0 ;
1643    static char **strlist=NULL ;
1644    static  int  nstrlist=0 ;    /* 06 Aug 2002 */
1645    char *slab=NULL ;
1646    XmString xstr=NULL ;
1647 
1648    /*-- Attempt to fix a Motif problem with Button 2
1649         when the optmenu is itself in a popup menu.
1650         The pointer grab is never released, so the
1651         X server is effectively frozen forever (or
1652         until the afni process is SIGTERM-ed). Here,
1653         if we see Button 2, then we manually ungrab
1654         the pointer.  This has the side-effect of
1655         popping down the popup menu.  If the optmenu
1656         is NOT in a popup menu, it has no side effect. --*/
1657 
1658 #ifdef USE_FIXUP
1659    optmenu_EV_fixup(NULL) ;
1660 #endif
1661 
1662    if( bev->button == Button2 ){
1663      XUngrabPointer( bev->display , CurrentTime ) ; return ;
1664    }
1665 
1666    /*-- start of actual work --*/
1667 
1668 ENTRY("optmenu_EV") ;
1669 
1670    /** sanity checks **/
1671 
1672    if( w == NULL || av == NULL || av->wmenu == NULL ) EXRETURN ;
1673 
1674    if( bev->button != Button3 ) EXRETURN ;
1675    if( av->imin >= av->imax   ) EXRETURN ;   /* 15 Oct 2007: nugation */
1676 
1677    XtVaGetValues( av->wlabel , XmNwidth,&lw , NULL ) ;
1678    if( bev->x > lw ) EXRETURN ;
1679 
1680    /** get ready to popup a new list chooser **/
1681 
1682    POPDOWN_strlist_chooser ;
1683 
1684    av->block_assign_actions = 1 ;         /* temporarily block actions */
1685    sval = av->ival ;
1686 
1687    /* 06 Aug 2002: free list of old strings, if any */
1688 
1689    for( ic=0 ; ic < nstrlist ; ic++ ) free(strlist[ic]) ;
1690 
1691    /** make a list of strings **/
1692 
1693    nstrlist = nstr = av->imax - av->imin + 1 ;
1694    strlist = (char **) realloc( strlist , sizeof(char *)*nstr ) ;
1695 
1696    for( ival=av->imin ; ival <= av->imax ; ival++ ){
1697       AV_assign_ival( av , ival ) ;       /* just to create label */
1698       ic = ival - av->imin ;              /* index into widget list */
1699       strlist[ic] = strdup( av->sval ) ;  /* copy label */
1700    }
1701 
1702    AV_assign_ival( av , sval ) ;
1703    av->block_assign_actions = 0 ;         /* back to normal */
1704 
1705    /** actually choose something **/
1706 
1707    XtVaGetValues( av->wlabel , XmNlabelString , &xstr , NULL ) ;
1708    XmStringGetLtoR( xstr , XmFONTLIST_DEFAULT_TAG , &slab ) ;
1709    XmStringFree(xstr) ;
1710 
1711    MCW_choose_strlist( w , slab , nstr ,
1712                        sval - av->imin , strlist ,
1713                        optmenu_finalize , cd      ) ;
1714    EXRETURN ;
1715 }
1716 
1717 /*--------------------------------------------------------------------------
1718    Create a colormenu -- an optmenu with buttons colorized
1719 ----------------------------------------------------------------------------*/
1720 
new_MCW_colormenu(Widget parent,char * label,MCW_DC * dc,int min_col,int max_col,int ini_col,gen_func * delta_value,XtPointer delta_data)1721 MCW_arrowval * new_MCW_colormenu( Widget parent , char *label , MCW_DC *dc ,
1722                                   int min_col , int max_col , int ini_col ,
1723                                   gen_func *delta_value, XtPointer delta_data
1724                                 )
1725 {
1726    MCW_arrowval *av ;
1727    Widget *children=NULL ;
1728    int  num_children=0 , ic , icol ;
1729 
1730 ENTRY("new_MCW_colormenu") ;
1731 
1732    av = new_MCW_optmenu( parent , label ,
1733                          min_col , max_col , ini_col , 0 ,
1734                          delta_value , delta_data ,
1735                          MCW_DC_ovcolor_text , (XtPointer)dc ) ;
1736 
1737    XtVaGetValues( av->wmenu , XmNchildren    , &children ,
1738                               XmNnumChildren , &num_children , NULL ) ;
1739    for( ic=0 ; ic < num_children ; ic++ ){
1740       icol = min_col + ic ;
1741       if( icol > 0 ) MCW_set_widget_bg( children[ic] , 0 , dc->ovc->pix_ov[icol] ) ;
1742       else           MCW_set_widget_bg( children[ic] , "gray40" , 0 ) ;
1743    }
1744 
1745    if( max_col > COLSIZE ) AVOPT_columnize( av , 1+(max_col-1)/COLSIZE ) ;
1746 
1747    RETURN(av) ;
1748 }
1749 
1750 /*-----------------------------------------------------------------------*/
1751 
colorize_MCW_optmenu(MCW_arrowval * av,char * cname,int ibut)1752 void colorize_MCW_optmenu( MCW_arrowval *av , char *cname , int ibut )
1753 {
1754    Widget *children=NULL ;
1755    int num_children=0 , ic,ibot,itop ;
1756 
1757 ENTRY("colorize_MCW_optmenu") ;
1758 
1759    if( av == NULL || av->wmenu == NULL ) EXRETURN ;
1760    if( cname == NULL || *cname == '\0' ) cname = "gray40" ;
1761 
1762    XtVaGetValues( av->wmenu , XmNchildren    , &children ,
1763                               XmNnumChildren , &num_children , NULL ) ;
1764    if( children == NULL || num_children <= 0 || ibut >= num_children ) EXRETURN ;
1765 
1766    if( ibut < 0 ){ ibot = 0 ; itop = num_children-1 ; }
1767    else          { ibot = itop = ibut ; }
1768 
1769    for( ic=ibot ; ic <= itop ; ic++ )
1770      MCW_set_widget_bg( children[ic] , cname , 0 ) ;
1771 
1772    EXRETURN ;
1773 }
1774 
1775 /*-----------------------------------------------------------------------*/
1776 
MCW_av_substring_CB(MCW_arrowval * av,XtPointer cd)1777 char * MCW_av_substring_CB( MCW_arrowval *av , XtPointer cd )
1778 {
1779    char **str = (char **) cd ;
1780    return str[av->ival] ;
1781 }
1782 
1783 /*-----------------------------------------------------------------------*/
1784 
AVOPT_press_CB(Widget wbut,XtPointer client_data,XtPointer call_data)1785 void AVOPT_press_CB( Widget wbut, XtPointer client_data, XtPointer call_data )
1786 {
1787    MCW_arrowval *av = (MCW_arrowval *) client_data ;
1788    int newval ;
1789    XtPointer xval=NULL ;
1790 
1791 ENTRY("AVOPT_press_CB");
1792 
1793    XtVaGetValues( wbut , XmNuserData , &xval , NULL ) ;
1794    newval = PTOI(xval) ;
1795 
1796    AV_assign_ival( av , newval ) ;  /* assign */
1797 
1798    /* call user callback, if present */
1799 
1800    if( av->dval_CB != NULL &&
1801       (av->optmenu_call_if_unchanged || av->fval != av->old_fval) )
1802 #if 0
1803       av->dval_CB( av , av->dval_data ) ;
1804 #else
1805       AFNI_CALL_VOID_2ARG( av->dval_CB ,
1806                            MCW_arrowval * , av ,
1807                            XtPointer      , av->dval_data ) ;
1808 #endif
1809 
1810    EXRETURN ;
1811 }
1812 
1813 /*-----------------------------------------------------------------------*/
1814 
AV_press_CB(Widget warrow,XtPointer client_data,XtPointer call_data)1815 void AV_press_CB( Widget warrow, XtPointer client_data, XtPointer call_data )
1816 {
1817    MCW_arrowval *av                 = (MCW_arrowval *) client_data ;
1818    XmArrowButtonCallbackStruct *cbs =
1819                         (XmArrowButtonCallbackStruct *) call_data ;
1820 
1821    XtIntervalId fake_id = 0 ;
1822 
1823    /* release of button */
1824 
1825    switch( cbs->reason ){
1826 
1827       default:
1828       case XmCR_DISARM:
1829          if( av->timer_id != 0 ) XtRemoveTimeOut( av->timer_id ) ; /* stop */
1830          av->timer_id = 0 ;
1831       break ;
1832 
1833       case XmCR_ARM:
1834               if( warrow == av->wup   ) av->incr =  1 ;  /* go up */
1835          else if( warrow == av->wdown ) av->incr = -1 ;  /* down  */
1836          else                           return ;
1837 
1838          if( cbs->event->type == ButtonPress ) av->delay = MCW_AV_longdelay ;
1839          else                                  av->delay = 0 ;
1840 
1841          av->xev = *(cbs->event) ;  /* copy event for user's info */
1842 
1843          AV_timer_CB( av , &fake_id ) ; /* do the work */
1844    }
1845    return;
1846 }
1847 
1848 /*------------------------------------------------------------------------*/
1849 
AV_timer_CB(XtPointer client_data,XtIntervalId * id)1850 void AV_timer_CB( XtPointer client_data , XtIntervalId *id )
1851 {
1852    MCW_arrowval *av = (MCW_arrowval *) client_data ;
1853    int newval ;
1854    double sval ;
1855 
1856    if( av->fstep == 0.0 ){   /* 16 Feb 1999: this is the old way */
1857 
1858       sval = av->fval ;  AV_SHIFT_VAL( -av->decimals , sval ) ;
1859 
1860       if( av->incr < 0 ){
1861          newval = (int) floor( 0.99 + sval + av->incr ) ;
1862       } else {
1863          newval = (int)  ceil(-0.99 + sval + av->incr ) ;
1864       }
1865 
1866       if( newval > av->imax && av->allow_wrap ){            /* out of range? wrap. */
1867          newval = av->imin ;
1868       } else if( newval < av->imin && av->allow_wrap ){
1869          newval = av->imax ;
1870 
1871       } else if( newval > av->imax || newval < av->imin ){  /* out of range? stop. */
1872          av->timer_id = 0 ;
1873          return ;
1874       }
1875 
1876       AV_assign_ival( av , newval ) ;  /* assign */
1877 
1878    } else {  /* 16 Feb 1999: this is the new way, if user sets fstep */
1879 
1880       if( av->incr > 0 )
1881          sval = av->fval + av->fstep ;
1882       else
1883          sval = av->fval - av->fstep ;
1884 
1885       if( sval > av->fmax || sval < av->fmin ){  /* out of range? stop. */
1886          av->timer_id = 0 ;
1887          return ;
1888       }
1889 
1890       AV_assign_fval( av , sval ) ;
1891    }
1892 
1893    /* call user callback, if present */
1894 
1895    if( av->dval_CB != NULL && av->fval != av->old_fval )
1896 #if 0
1897       av->dval_CB( av , av->dval_data ) ;
1898 #else
1899       AFNI_CALL_VOID_2ARG( av->dval_CB ,
1900                            MCW_arrowval * , av ,
1901                            XtPointer      , av->dval_data ) ;
1902 #endif
1903 
1904    /* delay and then call again, if desired */
1905 
1906    if( av->delay <= 0 ) return ;
1907 
1908    av->timer_id = XtAppAddTimeOut(
1909                      XtWidgetToApplicationContext( av->wrowcol ) ,
1910                      av->delay , AV_timer_CB , av ) ;
1911 
1912    if( av->delay == MCW_AV_longdelay ){
1913       if( av->fastdelay > 0 ) av->delay = av->fastdelay ;
1914       else                    av->delay = MCW_AV_shortdelay ;
1915    }
1916 
1917    return ;
1918 }
1919 
1920 /*------------------------------------------------------------------------*/
1921 /* Assign the integer value, but do not call the callback */
1922 
AV_assign_ival(MCW_arrowval * av,int nval)1923 void AV_assign_ival( MCW_arrowval *av , int nval )
1924 {
1925    int newival = nval ;
1926    char *cval = NULL ;
1927 
1928 ENTRY("AV_assign_ival") ;
1929 
1930    if( av == NULL ) EXRETURN ;  /* 01 Feb 2000 */
1931 
1932    if( newival > av->imax ) newival = av->imax ;
1933    if( newival < av->imin ) newival = av->imin ;
1934 
1935    /* assign */
1936 
1937    av->old_ival = av->ival ;
1938    av->old_fval = av->fval ;
1939 
1940    av->fval = av->ival = newival ;
1941 
1942    /* adjust decimal point */
1943 
1944    AV_SHIFT_VAL( av->decimals , av->fval ) ;
1945 
1946    /* change text display, if present */
1947 
1948    if( av->text_CB != NULL ){
1949 STATUS("adjust text") ;
1950 #if 0
1951       cval = av->text_CB( av , av->text_data ) ;            /* save   */
1952 #else
1953       AFNI_CALL_VALU_2ARG( av->text_CB , char * , cval ,
1954                            MCW_arrowval * , av ,
1955                            XtPointer      , av->text_data ) ;
1956 #endif
1957       myXtFree( av->old_sval ) ; av->old_sval = av->sval ;  /* string */
1958       av->sval = XtNewString( cval ) ;                      /* values */
1959 
1960       if( av->wtext != NULL && ! av->block_assign_actions )
1961          TEXT_SET( av->wtext , cval ) ;
1962    }
1963 
1964    /* if an option menu, change display */
1965 
1966    if( av->wmenu != NULL && ! av->block_assign_actions ){
1967 
1968       Widget *children=NULL , wbut=NULL ;
1969       int  num_children=0 , ic ;
1970 STATUS("adjust optmenu history") ;
1971       XtVaGetValues( av->wmenu ,
1972                         XmNchildren    , &children ,
1973                         XmNnumChildren , &num_children ,
1974                      NULL ) ;
1975 
1976       XtVaGetValues( av->wrowcol , XmNmenuHistory , &wbut , NULL ) ;
1977 
1978       ic = newival - av->imin ;
1979 
1980       if( ic >= 0 && ic < num_children && wbut != children[ic] )
1981         XtVaSetValues( av->wrowcol ,  XmNmenuHistory , children[ic] , NULL ) ;
1982    }
1983 
1984    EXRETURN ;
1985 }
1986 
1987 /*-------------------------------------------------------------------------
1988   format a floating value for output
1989 ---------------------------------------------------------------------------*/
1990 
AV_default_text_CB(MCW_arrowval * av,XtPointer junk)1991 char * AV_default_text_CB( MCW_arrowval *av , XtPointer junk )
1992 {
1993    static char buf[32] ;
1994 
1995    if( av == NULL ) buf[0] = '\0' ;
1996    else             AV_fval_to_char( av->fval , buf ) ;
1997    return &(buf[0]) ;
1998 }
1999 
2000 /*------------------------------------------------------------------------*/
2001 
AV_fval_to_char(float qval,char * buf)2002 void AV_fval_to_char( float qval , char *buf )
2003 {
2004    float aval = fabs(qval) ;
2005    int lv ;
2006    char lbuf[16] ;
2007    int il ;
2008 
2009    /* special case if the value is an integer */
2010 
2011    lv = (fabs(qval) < 9999999.0) ? (int)qval : 10000001 ;
2012 
2013    if( qval == lv && abs(lv) < 10000000 ){
2014       if( lv >= 0 ) sprintf( buf , " %d" , lv ) ;
2015       else          sprintf( buf , "%d"  , lv ) ;
2016       return ;
2017    }
2018 
2019 /* macro to strip trailing zeros from output */
2020 
2021 #define BSTRIP \
2022    for( il=AV_NCOL-1 ; il>1 && lbuf[il]=='0' ; il-- ) lbuf[il] = '\0'
2023 
2024    /* noninteger: choose floating format based on magnitude */
2025 
2026    lv = (int) (10.0001 + log10(aval)) ;
2027 
2028    switch( lv ){
2029 
2030       default:
2031          if( qval > 0.0 ) sprintf( lbuf , "%9.3e" , qval ) ;
2032          else             sprintf( lbuf , "%9.2e" , qval ) ;
2033       break ;
2034 
2035       case  6:  /* 0.0001-0.001 */
2036       case  7:  /* 0.001 -0.01  */
2037       case  8:  /* 0.01  -0.1   */
2038       case  9:  /* 0.1   -1     */
2039       case 10:  /* 1     -9.99  */
2040          sprintf( lbuf , "%9.6f" , qval ) ; BSTRIP ; break ;
2041 
2042       case 11:  /* 10-99.9 */
2043          sprintf( lbuf , "%9.5f" , qval ) ; BSTRIP ; break ;
2044 
2045       case 12:  /* 100-999.9 */
2046          sprintf( lbuf , "%9.4f" , qval ) ; BSTRIP ; break ;
2047 
2048       case 13:  /* 1000-9999.9 */
2049          sprintf( lbuf , "%9.3f" , qval ) ; BSTRIP ; break ;
2050 
2051       case 14:  /* 10000-99999.9 */
2052          sprintf( lbuf , "%9.2f" , qval ) ; BSTRIP ; break ;
2053 
2054       case 15:  /* 100000-999999.9 */
2055          sprintf( lbuf , "%9.1f" , qval ) ; BSTRIP ; break ;
2056 
2057       case 16:  /* 1000000-9999999.9 */
2058          sprintf( lbuf , "%9.0f" , qval ) ; break ;
2059    }
2060 
2061    lv = strlen(lbuf) ;                /* length of result at this stage */
2062 
2063    if( lv <= AV_NCOL ){               /* length OK */
2064       strcpy(buf,lbuf) ;
2065    } else {                           /* too long (should not occur!) */
2066       sprintf( lbuf , "%%%d.%dg" , AV_NCOL , AV_NCOL-7 ) ;
2067       sprintf( buf , lbuf , qval ) ;
2068    }
2069    return ;
2070 }
2071 
2072 /*------------------------------------------------------------------------*/
2073 
AV_format_fval(float fval)2074 char * AV_format_fval( float fval )
2075 {
2076    static char buf[32] ;
2077    AV_fval_to_char( fval , buf ) ;
2078    return buf ;
2079 }
2080 
2081 /*------------------------------------------------------------------------*/
2082 
AV_uformat_fval(float fval)2083 char * AV_uformat_fval( float fval )
2084 {
2085    static char buf[32] ;
2086    AV_fval_to_char( fval , buf ) ;
2087    if( buf[0] == ' ' ) return (buf+1) ;
2088    return buf ;
2089 }
2090 
2091 /*------------------------------------------------------------------------*/
2092 
AV_assign_fval(MCW_arrowval * av,float qval)2093 void AV_assign_fval( MCW_arrowval *av , float qval )
2094 {
2095    double newfval = qval ;
2096    char *cval ;
2097 
2098    if( av == NULL ) return ; /* 01 Feb 2000 */
2099 
2100    if( newfval > av->fmax ) newfval = av->fmax ;
2101    if( newfval < av->fmin ) newfval = av->fmin ;
2102 
2103    /* assign */
2104 
2105    av->old_ival = av->ival ;
2106    av->old_fval = av->fval ;
2107 
2108    av->fval = newfval ;
2109 
2110    /* adjust decimal point */
2111 
2112    AV_SHIFT_VAL( -av->decimals , newfval ) ;
2113 
2114    av->ival = (int) floor(newfval) ;
2115 
2116    /* change text display, if present */
2117 
2118    if( av->text_CB != NULL ){
2119 #if 0
2120       cval = av->text_CB( av , av->text_data ) ;            /* save   */
2121 #else
2122       AFNI_CALL_VALU_2ARG( av->text_CB , char * , cval ,
2123                            MCW_arrowval * , av ,
2124                            XtPointer      , av->text_data ) ;
2125 #endif
2126       myXtFree( av->old_sval ) ; av->old_sval = av->sval ;  /* string */
2127       av->sval = XtNewString( cval ) ;                      /* values */
2128 
2129       if( av->wtext != NULL && ! av->block_assign_actions )
2130          TEXT_SET( av->wtext , cval ) ;
2131    }
2132 
2133    return ;
2134 }
2135 
2136 /*----------------------------------------------------------------------*/
2137 
AV_leave_EV(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)2138 void AV_leave_EV( Widget w , XtPointer client_data ,
2139                   XEvent *ev , RwcBoolean *continue_to_dispatch )
2140 {
2141    MCW_arrowval *av       = (MCW_arrowval *) client_data ;
2142    XLeaveWindowEvent *lev = (XLeaveWindowEvent *) ev ;
2143    XmAnyCallbackStruct cbs ;
2144 
2145    if( lev->type != LeaveNotify || av == NULL ) return ;
2146 
2147    cbs.reason = XmCR_ACTIVATE ;  /* simulate a return press */
2148    AV_textact_CB( av->wtext , (XtPointer) av , &cbs ) ;
2149 }
2150 
2151 /*----------------------------------------------------------------------*/
2152 
AV_textact_CB(Widget wtex,XtPointer client_data,XtPointer call_data)2153 void AV_textact_CB( Widget wtex, XtPointer client_data, XtPointer call_data )
2154 {
2155    MCW_arrowval *av         = (MCW_arrowval *) client_data ;
2156    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data ;
2157 
2158    float sval ;
2159    int   ii ;
2160    char *str ;
2161 
2162 ENTRY("AV_textact_CB") ;
2163 
2164    if( (cbs->reason != XmCR_ACTIVATE && cbs->reason != XmCR_LOSING_FOCUS )
2165        || wtex != av->wtext ){
2166       fprintf(stderr,"\n*** Illegal call to AV_textact_CB ***\n") ;
2167       EXRETURN ;
2168    }
2169 
2170    str = TEXT_GET( wtex ) ;  /* get the new text */
2171 
2172    /* check if new text is any different from last value */
2173 
2174    if( av->sval != NULL && strcmp( av->sval , str ) == 0 ){
2175      myXtFree(str) ; EXRETURN ;
2176    }
2177 
2178    MCW_invert_widget( wtex ) ;  /* start flash */
2179 
2180    ii = sscanf( str , "%f" , &sval ) ;  /* convert to float in sval */
2181 
2182    if( ii == 0 ) sval = av->fval ;  /* bad float conversion */
2183 
2184    AV_assign_fval( av , sval ) ;  /* will alter ival,fval,sval in av */
2185 
2186    if( av->dval_CB != NULL && av->fval != av->old_fval )  /* value changed */
2187 #if 0
2188       av->dval_CB( av , av->dval_data ) ;
2189 #else
2190       AFNI_CALL_VOID_2ARG( av->dval_CB ,
2191                            MCW_arrowval * , av ,
2192                            XtPointer      , av->dval_data ) ;
2193 #endif
2194 
2195    myXtFree(str) ;  /* give it back */
2196 
2197    MCW_invert_widget( wtex ) ;  /* end flash */
2198    EXRETURN ;
2199 }
2200 
2201 /*----------------------------------------------------------------------
2202    NULL out the pointer to a popup widget when the widget is destroyed
2203 ------------------------------------------------------------------------*/
2204 
MCW_destroy_chooser_CB(Widget wpop,XtPointer client_data,XtPointer call_data)2205 void MCW_destroy_chooser_CB( Widget wpop ,
2206                              XtPointer client_data, XtPointer call_data )
2207 {
2208    Widget *wpointer = (Widget *) client_data ;
2209 ENTRY("MCW_destroy_chooser_CB") ;
2210    MCW_widget_geom( wpop , NULL,NULL , &old_xx,&old_yy ) ;  /* Apr 2013 */
2211    *wpointer = NULL ;
2212    EXRETURN ;
2213 }
2214 
MCW_kill_chooser_CB(Widget w,XtPointer client_data,XtPointer call_data)2215 void MCW_kill_chooser_CB( Widget w ,
2216                           XtPointer client_data, XtPointer call_data )
2217 {
2218    Widget wpop = (Widget) client_data ;
2219 ENTRY("MCW_kill_chooser_CB") ;
2220    MCW_widget_geom( wpop , NULL,NULL , &old_xx,&old_yy ) ;  /* Apr 2013 */
2221    XtDestroyWidget(wpop) ;
2222 EXRETURN ;
2223 }
2224 
2225 /*-----------------------------------------------------------------------*/
2226 
2227 #undef RECOLOR_OPTMENU
2228 
MCW_DC_ovcolor_text(MCW_arrowval * av,MCW_DC * dc)2229 char * MCW_DC_ovcolor_text( MCW_arrowval *av , MCW_DC *dc )
2230 {
2231    int ii = av->ival ;
2232    Widget wfix ;
2233 
2234         if( ii < 0                    ) ii = 0 ;
2235    else if( ii > dc->ovc->ncol_ov - 1 ) ii = dc->ovc->ncol_ov - 1 ;
2236 
2237    wfix = av->wtext ;
2238 
2239    if( wfix != NULL ){
2240       if( ii > 0 ) MCW_set_widget_bg( wfix , 0 , dc->ovc->pix_ov[ii] ) ;
2241       else         MCW_set_widget_bg( wfix , "gray40" , 0 ) ;
2242    }
2243 
2244 #ifdef RECOLOR_OPTMENU
2245    /** make the option menu cascade button gadget be outlined in color **/
2246 
2247    else if( av->wmenu != NULL && XtIsRealized(av->wrowcol) ){
2248       Pixel ptop=0 , pbot=0 ;
2249       wfix = av->wrowcol ;
2250       if( ii > 0 ) pbot = ptop = dc->ovc->pix_ov[ii] ;
2251       else         XtVaGetValues( XtParent(wfix) ,
2252                                      XmNtopShadowColor    , &ptop ,
2253                                      XmNbottomShadowColor , &pbot ,
2254                                   NULL ) ;
2255       XtVaSetValues( wfix ,
2256                         XmNtopShadowColor    , ptop ,
2257                         XmNbottomShadowColor , pbot ,
2258                      NULL ) ;
2259    }
2260 #endif
2261 
2262    return dc->ovc->label_ov[ii] ;
2263 }
2264 
2265 /*------------------------------------------------------------------------
2266    Get a table index for a DC overlay color:
2267      pops up a shell to let the user make the selection
2268 
2269      wpar     = parent widget (where to popup)
2270      dc       = display context to choose colors from
2271      ovc_init = initial overlay color index
2272 
2273      func = routine to call when a selection is made:
2274              void func( Widget wpar,XtPointer func_data,MCW_choose_cbs *cbs )
2275      func_data = data to pass to func
2276 
2277      The "ival" stored in the MCW_choose_cbs will be the index into the
2278      DC overlay color table.  The pixel value is thus dc->ovc->pix_ov[cbs->ival].
2279      The color name is dc->ovc->name_ov[cbs->ival].  Etc.
2280 
2281      Note that cbs->ival = 0 means that the user choose the "None" color.
2282 
2283    This routine is coded in such a way that only one color chooser will be
2284    active at a time (per application).  This is a deliberate choice.
2285 --------------------------------------------------------------------------*/
2286 
2287 #define OVC_quit_label   "Quit"
2288 #define OVC_apply_label  "Apply"
2289 #define OVC_done_label   "Set"
2290 #define OVC_clear_label  "Clear"
2291 
2292 #define OVC_quit_help   "Press to close\nthis `chooser'"
2293 #define OVC_apply_help  "Press to apply\nthis choice and\nkeep this `chooser'"
2294 #define OVC_done_help   "Press to apply\nthis choice and\nclose this `chooser'"
2295 #define OVC_clear_help  "Press to clear\nthe entry"
2296 
2297 #define OVC_av_help   "Use arrows to\nsee what choices\nare available"
2298 #define OVC_opt_help  "Click this button\nto pop up a menu\nof overlay colors"
2299 
2300 #define OVC_list_help_1 "Click Button 1 on the\n"   \
2301                         "item of your choice,\n"    \
2302                         "then press one of the\n"   \
2303                         "control buttons below.\n"  \
2304                         "        ** OR **\n"        \
2305                         "Double-click Button 1\n"   \
2306                         "on an item to choose it."
2307 
2308 #define OVC_list_help_2 "Multiple Mode:\n"               \
2309                         "  Click Button 1 on items to\n" \
2310                         "  select or de-select them.\n"  \
2311                         "\n"                             \
2312                         "Extended Mode:\n"               \
2313                         "+ Click and drag Button 1 to\n" \
2314                         "   select ranges of items.\n"   \
2315                         "+ Press Ctrl (on keyboard)\n"   \
2316                         "   at same time to avoid\n"     \
2317                         "   de-selecting items that\n"   \
2318                         "   were selected previously."
2319 
2320 #define NUM_OVC_ACT 3
2321 #define NUM_CLR_ACT 4
2322 
2323 static MCW_action_item OVC_act[] = {
2324  { OVC_quit_label , MCW_choose_CB, NULL, OVC_quit_help ,"Close window"                 ,0 },
2325  { OVC_apply_label, MCW_choose_CB, NULL, OVC_apply_help,"Apply choice and keep window" ,0 },
2326  { OVC_done_label , MCW_choose_CB, NULL, OVC_done_help ,"Apply choice and close window",1 },
2327  { OVC_clear_label, MCW_choose_CB, NULL, OVC_clear_help,"Clear entry"                  ,0 }
2328 } ;
2329 
2330 #define NUM_LIST_MODES 2
2331 static char *list_modes[NUM_LIST_MODES] = { "Multiple" , "Extended" } ;
2332 
MCW_choose_ovcolor(Widget wpar,MCW_DC * dc,int ovc_init,gen_func * func,XtPointer func_data)2333 void MCW_choose_ovcolor( Widget wpar , MCW_DC *dc , int ovc_init ,
2334                          gen_func *func , XtPointer func_data )
2335 {
2336    static Widget wpop = NULL , wrc ;
2337    static MCW_arrowval *  av = NULL ;
2338    static MCW_choose_data cd ;
2339    Position xx,yy ;
2340    int ib ;
2341 
2342 ENTRY("MCW_choose_ovcolor") ;
2343 
2344    /** destructor callback **/
2345 
2346    if( wpar == NULL ){
2347       if( wpop != NULL ){
2348          XtUnmapWidget( wpop ) ;
2349          XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
2350          XtDestroyWidget( wpop ) ;
2351       }
2352       wpop = NULL ; EXRETURN ;
2353    }
2354 
2355    if( ! XtIsRealized(wpar) || dc->ovc->ncol_ov < 2 ){  /* illegal call */
2356       fprintf(stderr,"\n*** illegal call to MCW_choose_ovcolor: %s %d\n",
2357              XtName(wpar) , dc->ovc->ncol_ov ) ;
2358       EXRETURN ;
2359    }
2360 
2361    if( ovc_init < 0 || ovc_init >= dc->ovc->ncol_ov ) ovc_init = 1 ;
2362 
2363    /*--- if popup widget already exists, destroy it ---*/
2364 
2365    if( wpop != NULL ){
2366       XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
2367       XtDestroyWidget( wpop ) ;
2368    }
2369 
2370    if( av != NULL ){
2371      myXtFree( av ) ; av = NULL ;
2372    }
2373 
2374    /*--- create popup widget ---*/
2375 
2376    wpop = XtVaCreatePopupShell(                        /* Popup Shell */
2377              MENU , xmDialogShellWidgetClass , wpar ,
2378                 XmNtraversalOn , True ,
2379                 XmNinitialResourcesPersistent , False ,
2380                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
2381              NULL ) ;
2382 
2383    if( MCW_isitmwm(wpar) ){
2384       XtVaSetValues( wpop ,
2385                         XmNmwmDecorations , MWM_DECOR_BORDER ,
2386                         XmNmwmFunctions   ,  MWM_FUNC_MOVE ,
2387                      NULL ) ;
2388    }
2389 
2390    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
2391 
2392    XmAddWMProtocolCallback(
2393         wpop ,
2394         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
2395         MCW_kill_chooser_CB , wpop ) ;
2396 
2397    wrc  = XtVaCreateWidget(                    /* RowColumn to hold all */
2398              MENU , xmRowColumnWidgetClass , wpop ,
2399                 XmNpacking      , XmPACK_TIGHT ,
2400                 XmNorientation  , XmVERTICAL ,
2401                 XmNtraversalOn , True ,
2402                 XmNinitialResourcesPersistent , False ,
2403              NULL ) ;
2404 
2405    av = new_MCW_colormenu( wrc , "Color " , dc ,
2406                            0 , dc->ovc->ncol_ov - 1 , ovc_init , NULL,NULL ) ;
2407    MCW_reghelp_children( av->wrowcol , OVC_opt_help ) ;
2408    MCW_reghint_children( av->wrowcol , "Overlay colors" ) ;
2409 
2410    cd.dc      = dc ;    /* data to be passed to pushbutton callback */
2411    cd.wpop    = wpop ;
2412    cd.wcaller = wpar ;
2413    cd.av      = av ;
2414    cd.sel_CB  = func ;
2415    cd.sel_cd  = func_data ;
2416    cd.ctype   = mcwCT_ovcolor ;
2417 
2418    for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ;
2419 
2420    (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ;
2421 
2422    RELOCATE(wpar,wpop,5) ; /* 12 Oct 2017 */
2423 
2424    XtManageChild( wrc ) ;
2425    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
2426 
2427    if( av->wtext != NULL )
2428      MCW_set_widget_bg( av->wtext , NULL , dc->ovc->pix_ov[ovc_init] ) ; /* after popup */
2429 
2430    RWC_visibilize_widget( wpop ) ;   /* 09 Nov 1999 */
2431    NORMAL_cursorize( wpop ) ;
2432 
2433    EXRETURN ;
2434 }
2435 
2436 /*-------------------------------------------------------------------------*/
2437 /* Get a bunch of values [19 Mar 2004].
2438    Change initvec from int to float. [21 Sep 2007].
2439 ---------------------------------------------------------------------------*/
2440 
2441 static int            vec_nav = 0 ;
2442 static MCW_arrowval **vec_av  = NULL ;
2443 
2444 /** this function gives access to the array of arrowvals used
2445     in MCW_choose_vector(), in order to let the caller change
2446     the ranges of values allowed from the stupid defaults.   **/
2447 
MCW_choose_vector_avarray(int * nav)2448 MCW_arrowval ** MCW_choose_vector_avarray( int *nav )  /* 03 Aug 2010 */
2449 {
2450    if( nav != NULL ) *nav = vec_nav ;
2451    return vec_av ;
2452 }
2453 
MCW_choose_vector(Widget wpar,char * label,int nvec,char ** labvec,float * initvec,gen_func * func,XtPointer func_data)2454 void MCW_choose_vector( Widget wpar , char *label ,
2455                         int nvec , char **labvec , float *initvec ,
2456                         gen_func *func , XtPointer func_data )
2457 {
2458    static Widget wpop = NULL , wrc ;
2459    static MCW_choose_data cd ;
2460    Position xx,yy ;
2461    int ib , iv ;
2462 
2463 ENTRY("MCW_choose_vector") ;
2464 
2465    /** destructor callback **/
2466 
2467    if( wpar == NULL || nvec <= 0 ){
2468       if( wpop != NULL ){
2469          XtUnmapWidget( wpop ) ;
2470          XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
2471          XtDestroyWidget( wpop ) ;
2472       }
2473       wpop = NULL ; EXRETURN ;
2474    }
2475 
2476    if( ! XtIsRealized(wpar) ){  /* illegal call */
2477       fprintf(stderr,"\n*** illegal call to MCW_choose_vector: %s\n",
2478               XtName(wpar) ) ;
2479       EXRETURN ;
2480    }
2481 
2482    /*--- if popup widget already exists, destroy it ---*/
2483 
2484    if( wpop != NULL ){
2485       XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
2486       XtDestroyWidget( wpop ) ;
2487    }
2488 
2489    if( vec_nav > 0 && vec_av != NULL ){
2490      for( iv=0 ; iv < vec_nav ; iv++ ) myXtFree( vec_av[iv] ) ;
2491      myXtFree(vec_av) ; vec_av = NULL ; vec_nav = 0 ;
2492    }
2493 
2494    /*--- create popup widget ---*/
2495 
2496    wpop = XtVaCreatePopupShell(                           /* Popup Shell */
2497              MENU , xmDialogShellWidgetClass , wpar ,
2498                 XmNtraversalOn , True ,
2499                 XmNinitialResourcesPersistent , False ,
2500                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
2501              NULL ) ;
2502 
2503    if( MCW_isitmwm(wpar) ){
2504       XtVaSetValues( wpop ,
2505                         XmNmwmDecorations , MWM_DECOR_BORDER ,
2506                         XmNmwmFunctions   ,  MWM_FUNC_MOVE ,
2507                      NULL ) ;
2508    }
2509 
2510    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
2511 
2512    XmAddWMProtocolCallback(
2513         wpop ,
2514         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
2515         MCW_kill_chooser_CB , wpop ) ;
2516 
2517    wrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
2518              MENU , xmRowColumnWidgetClass , wpop ,
2519                 XmNpacking      , XmPACK_TIGHT ,
2520                 XmNorientation  , XmVERTICAL ,
2521                 XmNtraversalOn , True ,
2522                 XmNinitialResourcesPersistent , False ,
2523              NULL ) ;
2524 
2525    if( label != NULL ){
2526      wtemp = XtVaCreateManagedWidget(
2527                   MENU , xmLabelWidgetClass , wrc ,
2528                      LABEL_ARG(label) ,
2529                      XmNinitialResourcesPersistent , False ,
2530                   NULL ) ; LABELIZE(wtemp) ;
2531      (void) XtVaCreateManagedWidget(
2532               MENU , xmSeparatorWidgetClass , wrc ,
2533                   XmNseparatorType , XmSHADOW_ETCHED_IN ,
2534                   XmNinitialResourcesPersistent , False ,
2535               NULL ) ;
2536    }
2537 
2538    vec_av  = (MCW_arrowval **) XtMalloc( sizeof(MCW_arrowval *) * nvec ) ;
2539    vec_nav = nvec ;
2540    for( iv=0 ; iv < nvec ; iv++ ){
2541      vec_av[iv] = new_MCW_arrowval( wrc ,
2542                                     (labvec!=NULL) ? labvec[iv] : NULL ,
2543                                     MCW_AV_downup ,
2544                                     -99999,99999,
2545                                     0 ,
2546                                     MCW_AV_edittext , 0 ,
2547                                     NULL , NULL , NULL , NULL ) ;
2548    }
2549 
2550    cd.wpop    = wpop ;  /* data to be passed to pushbutton callback */
2551    cd.wcaller = wpar ;
2552    cd.av      = (MCW_arrowval *)vec_av ;  /* hack hack hack */
2553    cd.sel_CB  = func ;
2554    cd.sel_cd  = func_data ;
2555    cd.ctype   = mcwCT_vector ;
2556    cd.nvec    = nvec ;
2557 
2558    for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ;
2559 
2560    (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ;
2561 
2562    RELOCATE(wpar,wpop,5) ; /* 12 Oct 2017 */
2563 
2564    XtManageChild( wrc ) ;
2565    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
2566 
2567    RWC_visibilize_widget( wpop ) ;
2568    NORMAL_cursorize( wpop ) ;
2569 
2570    if( initvec != NULL ){
2571      for( iv=0 ; iv < nvec ; iv++ ) AV_assign_fval(vec_av[iv],initvec[iv]) ;
2572    }
2573 
2574    EXRETURN ;
2575 }
2576 
2577 /*-------------------------------------------------------------------------
2578    Get an integer:
2579      pops up a shell to let the user make the selection
2580 
2581      wpar         = parent widget (where to popup)
2582      label        = label for chooser
2583      bot,top,init = integers defining range and initial value
2584      func         = routine to call when a selection is made:
2585             void func( Widget wpar,XtPointer func_data,MCW_choose_cbs *cbs )
2586      func_data    = data to pass to func
2587 
2588      The "ival" stored in the MCW_choose_cbs will be the desired result.
2589 
2590    This routine is coded in such a way that only one chooser will be
2591    active at a time (per application).  This is a deliberate choice.
2592 ---------------------------------------------------------------------------*/
2593 
MCW_choose_integer(Widget wpar,char * label,int bot,int top,int init,gen_func * func,XtPointer func_data)2594 void MCW_choose_integer( Widget wpar , char *label ,
2595                          int bot , int top , int init ,
2596                          gen_func *func , XtPointer func_data )
2597 {
2598    static Widget wpop = NULL , wrc ;
2599    static MCW_arrowval *  av = NULL ;
2600    static MCW_choose_data cd ;
2601    Position xx,yy ;
2602    int ib ;
2603 
2604 ENTRY("MCW_choose_integer") ;
2605 
2606    /** destructor callback **/
2607 
2608    if( wpar == NULL ){
2609       if( wpop != NULL ){
2610          XtUnmapWidget( wpop ) ;
2611          XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
2612          XtDestroyWidget( wpop ) ;
2613       }
2614       wpop = NULL ; EXRETURN ;
2615    }
2616 
2617    if( ! XtIsRealized(wpar) ){  /* illegal call */
2618       fprintf(stderr,"\n*** illegal call to MCW_choose_integer: %s\n",
2619               XtName(wpar) ) ;
2620       EXRETURN ;
2621    }
2622 
2623    /*--- if popup widget already exists, destroy it ---*/
2624 
2625    if( wpop != NULL ){
2626       XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
2627       XtDestroyWidget( wpop ) ;
2628    }
2629 
2630    if( av != NULL ){
2631       myXtFree( av ) ; av = NULL ;
2632    }
2633 
2634    /*--- create popup widget ---*/
2635 
2636    wpop = XtVaCreatePopupShell(                           /* Popup Shell */
2637              MENU , xmDialogShellWidgetClass , wpar ,
2638                 XmNtraversalOn , True ,
2639                 XmNinitialResourcesPersistent , False ,
2640                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
2641              NULL ) ;
2642 
2643    if( MCW_isitmwm(wpar) ){
2644       XtVaSetValues( wpop ,
2645                         XmNmwmDecorations , MWM_DECOR_BORDER ,
2646                         XmNmwmFunctions   ,  MWM_FUNC_MOVE ,
2647                      NULL ) ;
2648    }
2649 
2650    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
2651 
2652    XmAddWMProtocolCallback(
2653         wpop ,
2654         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
2655         MCW_kill_chooser_CB , wpop ) ;
2656 
2657    wrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
2658              MENU , xmRowColumnWidgetClass , wpop ,
2659                 XmNpacking      , XmPACK_TIGHT ,
2660                 XmNorientation  , XmVERTICAL ,
2661                 XmNtraversalOn , True ,
2662                 XmNinitialResourcesPersistent , False ,
2663              NULL ) ;
2664 
2665    av = new_MCW_arrowval( wrc ,
2666                           label , MCW_AV_downup ,  /* selection */
2667                           bot,top,init ,
2668                           MCW_AV_edittext , 0 ,
2669                           NULL , NULL , NULL , NULL ) ;
2670 
2671    av->allow_wrap = 1 ;
2672 
2673    MCW_reghelp_children( av->wrowcol , OVC_av_help ) ;
2674    MCW_reghint_children( av->wrowcol , "Pick value" ) ;
2675 
2676    cd.wpop    = wpop ;  /* data to be passed to pushbutton callback */
2677    cd.wcaller = wpar ;
2678    cd.av      = av ;
2679    cd.sel_CB  = func ;
2680    cd.sel_cd  = func_data ;
2681    cd.ctype   = mcwCT_integer ;
2682 
2683    for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ;
2684 
2685    (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ;
2686 
2687    RELOCATE(wpar,wpop,5) ; /* 12 Oct 2017 */
2688 
2689    XtManageChild( wrc ) ;
2690    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
2691 
2692    RWC_visibilize_widget( wpop ) ;   /* 09 Nov 1999 */
2693    NORMAL_cursorize( wpop ) ;
2694 
2695    EXRETURN ;
2696 }
2697 
2698 /*-------------------------------------------------------------------------
2699                                 ^
2700   Create a new MCW_arrowpad:  < O >
2701                                 v
2702     parent  = parent Widget
2703 
2704     press_func = pointer to a function that will be called when an arrow or
2705                    the button at the center is pressed
2706     press_data =  pointer to data to be passed to press_func;
2707                      press_func( apad , press_data ) ;
2708                   where apad is a pointer to the MCW_arrowpad that was hit.
2709 
2710     If press_func is NULL, no callback occurs. You may create the arrowpad and
2711     later set the callback by apad->action_CB = press_func.
2712 ---------------------------------------------------------------------------*/
2713 
new_MCW_arrowpad(Widget parent,gen_func * press_func,XtPointer press_data)2714 MCW_arrowpad * new_MCW_arrowpad( Widget parent ,
2715                                  gen_func *press_func, XtPointer press_data
2716                                )
2717 {
2718    MCW_arrowpad *apad ;
2719    int asizx = 20 , asizy = 20 ;  /* arrow sizes */
2720    int iar ;
2721 
2722 ENTRY("new_MCW_arrowpad") ;
2723 
2724    apad = myXtNew( MCW_arrowpad ) ;
2725 
2726    /*--- form to hold the stuff: everything is tied to rubber positions ---*/
2727 
2728    apad->wform = XtVaCreateWidget(
2729                     DIALOG , xmFormWidgetClass , parent ,
2730                        XmNfractionBase , AP_FBASE ,
2731                        XmNinitialResourcesPersistent , False ,
2732                        XmNtraversalOn , True  ,
2733                     NULL ) ;
2734 
2735    /*--- create the arrowbuttons ---*/
2736 
2737    for( iar = 0 ; iar < 4 ; iar++ ){
2738       apad->wbut[iar] =
2739          XtVaCreateManagedWidget(
2740                   "arrow" , xmArrowButtonWidgetClass , apad->wform ,
2741 
2742                      XmNtopAttachment    , XmATTACH_POSITION ,
2743                      XmNbottomAttachment , XmATTACH_POSITION ,
2744                      XmNleftAttachment   , XmATTACH_POSITION ,
2745                      XmNrightAttachment  , XmATTACH_POSITION ,
2746 
2747                      XmNarrowDirection , AP_but_def[iar].atype ,
2748                      XmNtopPosition    , AP_but_def[iar].atop ,
2749                      XmNbottomPosition , AP_but_def[iar].abottom ,
2750                      XmNleftPosition   , AP_but_def[iar].aleft ,
2751                      XmNrightPosition  , AP_but_def[iar].aright ,
2752 
2753                      XmNheight , asizy ,
2754                      XmNwidth  , asizx ,
2755                      XmNborderWidth , 0 ,
2756 
2757                      XmNinitialResourcesPersistent , False ,
2758                      XmNtraversalOn , True  ,
2759                   NULL ) ;
2760 
2761 
2762       XtAddCallback( apad->wbut[iar], XmNarmCallback   , AP_press_CB, apad ) ;
2763       XtAddCallback( apad->wbut[iar], XmNdisarmCallback, AP_press_CB, apad ) ;
2764    }
2765 
2766    /*--- create the pushbutton in the middle ---*/
2767 
2768    apad->wbut[4] = XtVaCreateManagedWidget(
2769                    "arrow" , xmPushButtonWidgetClass , apad->wform ,
2770 
2771                      XmNtopAttachment    , XmATTACH_POSITION ,
2772                      XmNbottomAttachment , XmATTACH_POSITION ,
2773                      XmNleftAttachment   , XmATTACH_POSITION ,
2774                      XmNrightAttachment  , XmATTACH_POSITION ,
2775 
2776                      XmNtopPosition    , AP_but_def[4].atop ,
2777                      XmNbottomPosition , AP_but_def[4].abottom ,
2778                      XmNleftPosition   , AP_but_def[4].aleft ,
2779                      XmNrightPosition  , AP_but_def[4].aright ,
2780 
2781                      XtVaTypedArg , XmNlabelString , XmRString , " " , 2 ,
2782 
2783                      XmNheight , asizy ,
2784                      XmNwidth  , asizx ,
2785                      XmNborderWidth , 0 ,
2786                      XmNrecomputeSize , False ,
2787 
2788                      XmNinitialResourcesPersistent , False ,
2789                      XmNtraversalOn , True  ,
2790                   NULL ) ;
2791 
2792    XtAddCallback( apad->wbut[4] , XmNactivateCallback , AP_press_CB , apad ) ;
2793 
2794    XtManageChild( apad->wform ) ;
2795 
2796    apad->action_CB   = press_func ;
2797    apad->action_data = press_data ;
2798    apad->fastdelay   = MCW_AV_shortdelay ;  /* default delay on 2nd call */
2799    apad->count       = 0 ;
2800 
2801    apad->parent = apad->aux = NULL ;
2802    RETURN(apad) ;
2803 }
2804 
2805 /*-------------------------------------------------------------------------*/
2806 
AP_press_CB(Widget wbut,XtPointer client_data,XtPointer call_data)2807 void AP_press_CB( Widget wbut , XtPointer client_data , XtPointer call_data )
2808 {
2809    MCW_arrowpad *apad               = (MCW_arrowpad *) client_data ;
2810    XmArrowButtonCallbackStruct *cbs =
2811              (XmArrowButtonCallbackStruct *) call_data ;
2812 
2813    XtIntervalId fake_id = 0 ;
2814 
2815    switch( cbs->reason ){
2816 
2817       /*--- release of button (will only happen for arrows) ---*/
2818 
2819       default:
2820       case XmCR_DISARM:  /* time to stop */
2821          if( apad->timer_id != 0 ) XtRemoveTimeOut( apad->timer_id ) ;
2822          apad->timer_id = 0 ;
2823       break ;
2824 
2825       /*--- press of button ---*/
2826 
2827       case XmCR_ARM:        /* arrow press */
2828       case XmCR_ACTIVATE:{  /* button press */
2829          int iar ;
2830 
2831          for( iar=0 ; iar < 5 ; iar++ )
2832             if( wbut == apad->wbut[iar] ) break ;
2833 
2834          if( iar > 4 ) return ;  /* something wrong, exit */
2835 
2836          apad->which_pressed = iar ;
2837          apad->count         = 0 ;
2838 
2839          if( cbs->reason      == XmCR_ARM &&
2840              cbs->event->type == ButtonPress ) apad->delay = MCW_AV_longdelay;
2841          else                                  apad->delay = 0 ;
2842 
2843          apad->xev = *(cbs->event) ;  /* copy event for user's info */
2844 
2845          AP_timer_CB( apad , &fake_id ) ; /* do the work */
2846       }
2847    }
2848    return;
2849 }
2850 
2851 /*-------------------------------------------------------------------------*/
2852 
AP_timer_CB(XtPointer client_data,XtIntervalId * id)2853 void AP_timer_CB( XtPointer client_data , XtIntervalId *id )
2854 {
2855    MCW_arrowpad *apad = (MCW_arrowpad *) client_data ;
2856 
2857    /* call user callback */
2858 
2859    if( apad->action_CB != NULL )
2860 #if 0
2861       apad->action_CB( apad , apad->action_data ) ;
2862 #else
2863       AFNI_CALL_VOID_2ARG( apad->action_CB ,
2864                            MCW_arrowpad * , apad ,
2865                            XtPointer      , apad->action_data ) ;
2866 #endif
2867 
2868    /* delay and then call again, if desired */
2869 
2870    if( apad->delay <= 0 ) return ;
2871 
2872    (apad->count)++ ;
2873    if( apad->count > AP_MAXCOUNT ){
2874       apad->count = 0 ;
2875       return ;
2876    }
2877 
2878    apad->timer_id = XtAppAddTimeOut(
2879                      XtWidgetToApplicationContext( apad->wform ) ,
2880                      apad->delay , AP_timer_CB , apad ) ;
2881 
2882    if( apad->delay == MCW_AV_longdelay ){
2883       if( apad->fastdelay > 0 ) apad->delay = apad->fastdelay ;
2884       else                      apad->delay = MCW_AV_shortdelay ;
2885    }
2886 
2887    return ;
2888 }
2889 
2890 /*-------------------------------------------------------------------------
2891    Get a string:
2892      pops up a shell to let the user make the selection
2893 
2894      wpar           = parent widget (where to popup)
2895      label          = label for chooser
2896      default_string = initial value
2897      func           = routine to call when a selection is made:
2898             void func( Widget wpar,XtPointer func_data,MCW_choose_cbs *cbs )
2899      func_data      = data to pass to func
2900 
2901      The "cval" stored in the MCW_choose_cbs will be the desired result.
2902 
2903    This routine is coded in such a way that only one chooser will be
2904    active at a time (per application).  This is a deliberate choice.
2905 ---------------------------------------------------------------------------*/
2906 
MCW_choose_string(Widget wpar,char * label,char * default_string,gen_func * func,XtPointer func_data)2907 void MCW_choose_string( Widget wpar , char *label ,
2908                         char *default_string ,
2909                         gen_func *func , XtPointer func_data )
2910 {
2911    static Widget wpop = NULL , wrc , wtf , wlab ;
2912    static MCW_choose_data cd ;
2913    Position xx,yy ;
2914    int ib , ncol=0 ;
2915 
2916 ENTRY("MCW_choose_string") ;
2917 
2918    /** destructor callback **/
2919 
2920    if( wpar == NULL ){
2921      if( wpop != NULL ){
2922        XtUnmapWidget( wpop ) ;
2923        XtRemoveCallback( wpop,XmNdestroyCallback,MCW_destroy_chooser_CB,&wpop );
2924        XtDestroyWidget( wpop ) ;
2925      }
2926      wpop = NULL ; EXRETURN ;
2927    }
2928 
2929    if( ! XtIsWidget(wpar) ) EXRETURN ;
2930 
2931    if( ! XtIsRealized(wpar) ){  /* illegal call */
2932      fprintf(stderr,"\n*** illegal call to MCW_choose_string: %s\n",
2933              XtName(wpar) ) ;
2934      EXRETURN ;
2935    }
2936 
2937    /*--- if popup widget already exists, destroy it ---*/
2938 
2939    if( wpop != NULL ){
2940      XtRemoveCallback( wpop,XmNdestroyCallback,MCW_destroy_chooser_CB,&wpop );
2941      XtDestroyWidget( wpop ) ;
2942    }
2943 
2944    /*--- create popup widget ---*/
2945 
2946    wpop = XtVaCreatePopupShell(                           /* Popup Shell */
2947              MENU , xmDialogShellWidgetClass , wpar ,
2948                 XmNtraversalOn , True ,
2949                 XmNinitialResourcesPersistent , False ,
2950                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
2951              NULL ) ;
2952 
2953    if( MCW_isitmwm(wpar) ){
2954      XtVaSetValues( wpop ,
2955                       XmNmwmDecorations , MWM_DECOR_BORDER ,
2956                       XmNmwmFunctions   ,  MWM_FUNC_MOVE ,
2957                     NULL ) ;
2958    }
2959 
2960    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
2961 
2962    XmAddWMProtocolCallback(
2963         wpop ,
2964         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
2965         MCW_kill_chooser_CB , wpop ) ;
2966 
2967    wrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
2968              MENU , xmRowColumnWidgetClass , wpop ,
2969                 XmNpacking      , XmPACK_TIGHT ,
2970                 XmNorientation  , XmVERTICAL ,
2971                 XmNtraversalOn , True ,
2972                 XmNinitialResourcesPersistent , False ,
2973              NULL ) ;
2974 
2975    if( label != NULL && (ncol=strlen(label)) > 0 ){
2976      char *cpt ;
2977      wlab = XtVaCreateManagedWidget(
2978                MENU , xmLabelWidgetClass , wrc ,
2979                   LABEL_ARG(label) ,
2980                   XmNinitialResourcesPersistent , False ,
2981                NULL ) ;
2982      LABELIZE(wlab) ;
2983 
2984      cpt = strstr(label,"\n") ;
2985      if( cpt != NULL ) ncol = cpt-label ;  /* 01 Nov 2001 */
2986    }
2987 
2988    if( default_string != NULL && default_string[0] != '\0' ){
2989      int qq = strlen(default_string) ;
2990      if( qq > ncol ) ncol = qq ;
2991    }
2992    if( ncol < AV_NCOL ) ncol = AV_NCOL ;
2993 
2994    wtf = XtVaCreateManagedWidget(
2995              MENU , TEXT_CLASS , wrc ,
2996 
2997                  XmNcolumns         , ncol ,
2998                  XmNeditable        , True ,
2999                  XmNmaxLength       , ncol+64 ,
3000                  XmNresizeWidth     , False ,
3001 
3002                  XmNmarginHeight    , 1 ,
3003                  XmNmarginWidth     , 1 ,
3004 
3005                  XmNcursorPositionVisible , True ,
3006                  XmNblinkRate , 0 ,
3007                  XmNautoShowCursorPosition , True ,
3008 
3009                  XmNinitialResourcesPersistent , False ,
3010                  XmNtraversalOn , True ,
3011               NULL ) ;
3012 
3013    if( default_string != NULL && default_string[0] != '\0' ){
3014      int qq  = strlen(default_string) , ii ;
3015      for( ii=0 ; ii < qq ; ii++ ) if( default_string[ii] != ' ' ) break ;
3016      if( ii < qq ) TEXT_SET( wtf , default_string ) ;
3017    }
3018 
3019    cd.wpop    = wpop ;  /* data to be passed to pushbutton callback */
3020    cd.wcaller = wpar ;
3021    cd.wchoice = wtf ;
3022    cd.sel_CB  = func ;
3023    cd.sel_cd  = func_data ;
3024    cd.ctype   = mcwCT_string ;
3025 
3026    XtAddCallback( wtf,XmNactivateCallback,MCW_choose_CB,&cd ) ; /* return key */
3027 
3028    for( ib=0 ; ib < NUM_CLR_ACT ; ib++ ) OVC_act[ib].data = &cd ;
3029 
3030    (void) MCW_action_area( wrc , OVC_act , NUM_CLR_ACT ) ;
3031 
3032    RELOCATE(wpar,wpop,5) ; /* 12 Oct 2017 */
3033 
3034    XtManageChild( wrc ) ;
3035    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
3036 
3037    RWC_visibilize_widget( wpop ) ;   /* 09 Nov 1999 */
3038    NORMAL_cursorize( wpop ) ;
3039 
3040    EXRETURN ;
3041 }
3042 
3043 /*-------------------------------------------------------------------------*/
3044 
3045 static int browse_select = 0 , bcs = 0 , blocked = 0 ;
MCW_set_browse_select(int i)3046 void MCW_set_browse_select(int i){ browse_select = i ; } /* 21 Feb 2007 */
3047 
3048 /*-------------------------------------------------------------------------*/
3049 
3050 static int list_max = -1 , list_maxmax ;
3051 
MCW_set_listmax(Widget wpar)3052 static void MCW_set_listmax( Widget wpar )
3053 {
3054    if( list_max < 0 ){
3055 #if 0
3056       char *xdef = XGetDefault( XtDisplay(wpar) , "AFNI" , "chooser_listmax" ) ;
3057 #else
3058       char *xdef = RWC_getname( XtDisplay(wpar) , "chooser_listmax" ) ;
3059 #endif
3060       if( xdef == NULL ) xdef = getenv("AFNI_MENU_COLSIZE") ;  /* 11 Dec 2001 */
3061       if( xdef != NULL )  list_max = strtol( xdef , NULL , 10 ) ;
3062       if( list_max <= 4 ) list_max = LIST_MAX ;
3063       list_maxmax = list_max + 5 ;
3064    }
3065    return ;
3066 }
3067 
3068 /*-------------------------------------------------------------------------
3069    Get an integer, as an index to an array of strings:
3070      pops up a shell to let the user make the selection, cycling through
3071      the string array
3072 
3073      wpar         = parent widget (where to popup)
3074      label        = label for chooser
3075      num_str      = number of strings
3076      init         = index of initial string
3077      strlist      = array of char *, pointing to strings
3078      func         = routine to call when a selection is made:
3079             void func( Widget wpar,XtPointer func_data,MCW_choose_cbs *cbs )
3080      func_data    = data to pass to func
3081 
3082      The "ival" stored in the MCW_choose_cbs will be the desired result
3083        (from 0 to num_str-1).
3084 
3085    This routine is coded in such a way that only one chooser will be
3086    active at a time (per application).  This is a deliberate choice.
3087 ---------------------------------------------------------------------------*/
3088 
MCW_choose_strlist(Widget wpar,char * label,int num_str,int init,char * strlist[],gen_func * func,XtPointer func_data)3089 void MCW_choose_strlist( Widget wpar , char *label ,
3090                          int num_str , int init , char *strlist[] ,
3091                          gen_func *func , XtPointer func_data )
3092 {
3093    int initar[2] ;
3094    initar[0] = init ;
3095    initar[1] = -666 ;
3096 
3097    MCW_choose_multi_strlist( wpar , label , mcwCT_single_mode ,
3098                              num_str , initar , strlist , func , func_data ) ;
3099    return ;
3100 }
3101 
3102 /*-------------------------------------------------------------------------*/
3103 
MCW_choose_binary(Widget wpar,char * label,int init,char * str0,char * str1,gen_func * func,XtPointer func_data)3104 void MCW_choose_binary( Widget wpar , char *label ,         /* 10 Feb 2012 */
3105                         int init , char *str0 , char *str1 ,
3106                         gen_func *func , XtPointer func_data )
3107 {
3108    char *strlist[2] ;
3109    strlist[0] = (str0 == NULL || *str0 == '\0' ) ? "Off" : str0 ;
3110    strlist[1] = (str1 == NULL || *str1 == '\0' ) ? "On"  : str1 ;
3111    MCW_choose_strlist( wpar, label, 2, (init!=0), strlist, func,func_data ) ;
3112    return ;
3113 }
3114 
3115 /*-------------------------------------------------------------------------*/
3116 
3117 static Widget str_wlist           = NULL ;  /* 12 Oct 2007 */
3118 static int    str_wlist_num       = 0 ;
3119 static MCW_arrowval *str_wlist_av = NULL ;
3120 
MCW_strlist_av_CB(MCW_arrowval * av,XtPointer cd)3121 static void MCW_strlist_av_CB( MCW_arrowval *av , XtPointer cd )
3122 {
3123    int init=1+av->ival , itop=0,nvis=0 ;
3124 
3125    if( str_wlist == NULL || !XtIsRealized(str_wlist) ||
3126        init <= 0         || init > str_wlist_num       ) return ;
3127 
3128    XmListSelectPos( str_wlist , init , False ) ;
3129    XtVaGetValues( str_wlist ,
3130                     XmNtopItemPosition ,&itop ,
3131                     XmNvisibleItemCount,&nvis ,
3132                   NULL ) ;
3133         if( init <  itop      ) XmListSetPos      ( str_wlist , init ) ;
3134    else if( init >= itop+nvis ) XmListSetBottomPos( str_wlist , init ) ;
3135 
3136    if( bcs && !blocked ){
3137      blocked = 1 ;
3138      XtCallCallbacks( str_wlist , XmNbrowseSelectionCallback , NULL ) ;
3139      blocked = 0 ;
3140    }
3141 }
3142 
3143 /*-------------------------------------------------------------------------*/
3144 
MCW_strlist_select_CB(Widget w,XtPointer cd,XtPointer cb)3145 static void MCW_strlist_select_CB( Widget w, XtPointer cd, XtPointer cb )
3146 {
3147    int ns=0 ; unsigned int *sp=NULL ;
3148 
3149    if( str_wlist == NULL || !XtIsRealized(str_wlist) ) return ;
3150 
3151    XtVaGetValues( str_wlist ,
3152                     XmNselectedPositionCount , &ns ,
3153                     XmNselectedPositions     , &sp ,
3154                   NULL ) ;
3155    if( ns <= 0 || sp == NULL ) return ;
3156    AV_assign_ival( str_wlist_av , (int)(sp[0])-1 ) ;
3157    blocked = 1 ;
3158    MCW_strlist_av_CB( str_wlist_av , NULL ) ;
3159    blocked = 0 ;
3160 }
3161 
3162 /*-------------------------------------------------------------------------*/
3163 
MCW_choose_multi_strlist(Widget wpar,char * label,int mode,int num_str,int * init,char * strlist[],gen_func * func,XtPointer func_data)3164 void MCW_choose_multi_strlist( Widget wpar , char *label , int mode ,
3165                                int num_str , int *init , char *strlist[] ,
3166                                gen_func *func , XtPointer func_data )
3167 {
3168    static Widget wpop=NULL , wrc ;
3169    static MCW_choose_data cd ;
3170    Position xx,yy ;
3171    int ib , ll , ltop ;
3172    Widget wlist=NULL , wlab ;
3173    XmStringTable xmstr ;
3174    XmString xms ;
3175    char *lbuf ;
3176    int nvisible ;
3177    MCW_arrowval *wav ;        /* 12 Oct 2007 */
3178 
3179 ENTRY("MCW_choose_multi_strlist") ;
3180 
3181    /** destructor callback **/
3182 
3183    bcs = browse_select ; /* 21 Feb 2007 */
3184    browse_select = 0 ;  /* 21 Feb 2007 */
3185    str_wlist = NULL ;   /* 12 Oct 2007 */
3186 
3187    if( wpop != NULL && old_wpar != NULL ){   /* Apr 2013: save current location */
3188      MCW_widget_geom( wpop , NULL,NULL , &old_xx,&old_yy ) ;
3189    }
3190 
3191    if( wpar == NULL ){
3192      if( wpop != NULL ){
3193        STATUS("destroying chooser") ;
3194        XtUnmapWidget( wpop ) ;
3195        XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
3196        XtDestroyWidget( wpop ) ;
3197        wpop = NULL ;
3198      }
3199      EXRETURN ;
3200    }
3201 
3202    if( ! XtIsRealized(wpar) ){  /* illegal call */
3203      fprintf(stderr,"\n*** illegal call to MCW_choose_strlist %s\n",
3204              XtName(wpar) ) ;
3205      EXRETURN ;
3206    }
3207 
3208    MCW_set_listmax( wpar ) ;
3209 
3210    /*--- if popup widget already exists, destroy it ---*/
3211 
3212    if( wpop != NULL ){
3213      XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
3214      XtDestroyWidget( wpop ) ;
3215    }
3216 
3217    wlist = NULL ;
3218 
3219    /*--- create popup widget ---*/
3220 
3221    wpop = XtVaCreatePopupShell(                           /* Popup Shell */
3222             MENU , xmDialogShellWidgetClass , wpar ,
3223                XmNtraversalOn , True ,
3224                XmNinitialResourcesPersistent , False ,
3225                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
3226             NULL ) ;
3227 
3228    if( MCW_isitmwm(wpar) ){
3229      XtVaSetValues( wpop ,
3230                       XmNmwmDecorations ,  MWM_DECOR_BORDER ,
3231                       XmNmwmFunctions   ,  MWM_FUNC_MOVE
3232                                          | MWM_FUNC_CLOSE ,
3233                     NULL ) ;
3234    }
3235 
3236    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
3237 
3238    XmAddWMProtocolCallback(
3239         wpop ,
3240         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
3241         MCW_kill_chooser_CB , wpop ) ;
3242 
3243    wrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
3244              MENU , xmRowColumnWidgetClass , wpop ,
3245                 XmNpacking     , XmPACK_TIGHT ,
3246                 XmNorientation , XmVERTICAL ,
3247                 XmNtraversalOn , True  ,
3248                 XmNinitialResourcesPersistent , False ,
3249              NULL ) ;
3250 
3251    if( label != NULL && label[0] != '\0' ){
3252      lbuf = (char*)XtMalloc( strlen(label) + 32 ) ;
3253      sprintf( lbuf , "----Choose %s----\n%s" ,
3254               (mode == mcwCT_single_mode) ? "One" : "One or More" , label ) ;
3255    } else {
3256      lbuf = (char*)XtMalloc( 32 ) ;
3257      sprintf( lbuf , "----Choose %s----",
3258               (mode == mcwCT_single_mode) ? "One" : "One or More" ) ;
3259    }
3260    xms = XmStringCreateLtoR( lbuf , XmFONTLIST_DEFAULT_TAG ) ;
3261    wlab = XtVaCreateManagedWidget(
3262                 MENU , xmLabelWidgetClass , wrc ,
3263                    XmNlabelString   , xms  ,
3264                    XmNalignment     , XmALIGNMENT_CENTER ,
3265                    XmNinitialResourcesPersistent , False ,
3266                 NULL ) ;
3267    myXtFree(lbuf) ; XmStringFree(xms) ; LABELIZE(wlab) ;
3268 
3269    (void) XtVaCreateManagedWidget(
3270             MENU , xmSeparatorWidgetClass , wrc ,
3271                 XmNseparatorType , XmSHADOW_ETCHED_IN ,
3272                 XmNinitialResourcesPersistent , False ,
3273             NULL ) ;
3274 
3275    xmstr = (XmStringTable) XtMalloc( num_str * sizeof(XmString *) ) ;
3276    for( ib=0 ; ib < num_str ; ib++ )
3277      xmstr[ib] = XmStringCreateSimple(strlist[ib]) ;
3278 
3279    wlist = XmCreateScrolledList( wrc , MENU , NULL , 0 ) ;
3280 
3281    nvisible = (num_str < list_maxmax ) ? num_str : list_max ;
3282 
3283    str_wlist      = wlist ;  /* 12 Oct 2007 */
3284    str_wlist_num  = num_str ;
3285 
3286    XtVaSetValues( wlist ,
3287                     XmNitems            , xmstr ,
3288                     XmNitemCount        , num_str ,
3289                     XmNvisibleItemCount , nvisible ,
3290                     XmNtraversalOn      , True ,
3291                     XmNselectionPolicy  , (mode == mcwCT_single_mode)
3292                                           ? XmBROWSE_SELECT : XmMULTIPLE_SELECT ,
3293                   NULL ) ;
3294 
3295    if( init != NULL ){
3296      for( ib=0 ; init[ib] >= 0 && init[ib] < num_str ; ib++ )
3297        XmListSelectPos( wlist , init[ib]+1 , False ) ;
3298      if( ib > 0 && init[ib-1] > nvisible )
3299        XmListSetBottomPos( wlist , init[ib-1]+1 ) ;
3300    }
3301 
3302    XtManageChild(wlist) ;
3303 
3304    if( mode == mcwCT_multi_mode ){  /* multiple selections allowed at a time */
3305      MCW_register_help( wlist , OVC_list_help_2 ) ;
3306      MCW_register_help( wlab  , OVC_list_help_2 ) ;
3307    } else {                         /* single selection allowed at a time */
3308      MCW_register_help( wlist , OVC_list_help_1 ) ;
3309      MCW_register_help( wlab  , OVC_list_help_1 ) ;
3310      XtAddCallback( wlist , XmNdefaultActionCallback , MCW_choose_CB , &cd ) ;
3311      if( bcs )  /* 21 Feb 2007 */
3312        XtAddCallback( wlist, XmNbrowseSelectionCallback,MCW_choose_CB, &cd ) ;
3313    }
3314 
3315    cd.wchoice = wlist ;
3316    cd.av      = NULL ;   /* this is NULL --> will use the list widget */
3317 
3318    for( ib=0 ; ib < num_str ; ib++ ) XmStringFree(xmstr[ib]) ;
3319    myXtFree(xmstr) ;
3320 
3321    cd.wpop    = wpop ;  /* data to be passed to pushbutton callback */
3322    cd.wcaller = wpar ;
3323    cd.sel_CB  = func ;
3324    cd.sel_cd  = func_data ;
3325    cd.ctype   = mcwCT_integer ;
3326 
3327    for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ;
3328 
3329    (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ;
3330 
3331    if( mode == mcwCT_multi_mode ){
3332       (void) XtVaCreateManagedWidget(
3333                MENU , xmSeparatorWidgetClass , wrc ,
3334                    XmNseparatorType , XmSINGLE_LINE ,
3335                    XmNinitialResourcesPersistent , False ,
3336                NULL ) ;
3337 
3338       wav = new_MCW_optmenu( wrc , "Selection Mode" , 0,NUM_LIST_MODES-1,0,0 ,
3339                             MCW_list_mode_CB , wlist ,
3340                             MCW_av_substring_CB , list_modes ) ;
3341 
3342       MCW_reghelp_children( wav->wrowcol , OVC_list_help_2 ) ;
3343       MCW_reghint_children( wav->wrowcol , "How list selections work" ) ;
3344 
3345    } else if( mode == mcwCT_single_mode         &&
3346               !AFNI_noenv("AFNI_STRLIST_INDEX") &&
3347               num_str > 1                         ){  /* 12 Oct 2007 */
3348       int ival = 0 ;
3349 
3350       (void) XtVaCreateManagedWidget(
3351                MENU , xmSeparatorWidgetClass , wrc ,
3352                    XmNseparatorType , XmSINGLE_LINE ,
3353                    XmNinitialResourcesPersistent , False ,
3354                NULL ) ;
3355 
3356       if( init != NULL && init[0] > 0 && init[0] < num_str ) ival = init[0] ;
3357 
3358       str_wlist_av = new_MCW_arrowval( wrc , "Index" , MCW_AV_updown ,
3359                                        0 , num_str-1 , ival , MCW_AV_editext , 0 ,
3360                                        MCW_strlist_av_CB , NULL , NULL , NULL ) ;
3361 
3362       XtAddCallback(wlist,XmNbrowseSelectionCallback,MCW_strlist_select_CB,NULL);
3363    }
3364 
3365    if( old_xx < 0 || old_yy < 0 || old_wpar != wpar ){
3366      RELOCATE(wpar,wpop,2) ; /* 12 Oct 2017 */
3367    } else {
3368 #ifdef DARWIN
3369 # define YDEL 20
3370 #else
3371 # define YDEL 0
3372 #endif
3373      XtVaSetValues( wpop , XmNx , old_xx  , XmNy , old_yy-YDEL  , NULL ) ;  /* Apr 2013 */
3374    }
3375 
3376    XtManageChild( wrc ) ;
3377    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
3378 
3379    RWC_visibilize_widget( wpop ) ;   /* 09 Nov 1999 */
3380    NORMAL_cursorize( wpop ) ;
3381 
3382    old_wpar = wpar ;                 /* Apr 2013 */
3383 
3384    EXRETURN ;
3385 }
3386 
3387 /*--------------------------------------------------------------------*/
3388 
MCW_list_mode_CB(MCW_arrowval * av,XtPointer cd)3389 void MCW_list_mode_CB( MCW_arrowval *av , XtPointer cd )
3390 {
3391    Widget wlist = (Widget) cd ;
3392 
3393    if( av == NULL || wlist == NULL ) return ;
3394 
3395    XtVaSetValues( wlist ,
3396                      XmNselectionPolicy ,
3397                      (av->ival == 0) ? XmMULTIPLE_SELECT
3398                                      : XmEXTENDED_SELECT ,
3399                   NULL ) ;
3400 }
3401 
3402 /*==================================================================================*/
3403 
3404 #define TSC_quit_label   "Quit"
3405 #define TSC_plot_label   "Plot"
3406 #define TSC_apply_label  "Apply"
3407 #define TSC_done_label   "Set"
3408 
3409 #define TSC_quit_help   "Press to close\nthis `chooser'"
3410 #define TSC_plot_help   "Press to popup\na graph of the\nselected time series"
3411 #define TSC_apply_help  "Press to apply\nthis choice and\nkeep this `chooser'"
3412 #define TSC_done_help   "Press to apply\nthis choice and\nclose this `chooser'"
3413 
3414 #define TSC_list_help_1  OVC_list_help_1
3415 
3416 #define NUM_TSC_ACT 4
3417 
3418 #undef DONT_USE_COXPLOT  /* for the long-delayed Plot option */
3419 
3420 #undef PCODE
3421 #ifdef DONT_USE_COXPLOT
3422 # define PCODE -1
3423 #else
3424 # define PCODE  0
3425 # include "coxplot.h"
3426 #endif
3427 
3428 static MCW_action_item TSC_act[] = {
3429  { TSC_quit_label , MCW_choose_CB, NULL, TSC_quit_help ,"Close window"              , 0 },
3430  { TSC_plot_label , MCW_choose_CB, NULL, TSC_plot_help ,"Plot data"                 , PCODE },
3431  { TSC_apply_label, MCW_choose_CB, NULL, TSC_apply_help,"Apply choice, keep window" , 0 },
3432  { TSC_done_label , MCW_choose_CB, NULL, TSC_done_help ,"Apply choice, close window", 1 }
3433 } ;
3434 
3435 #undef PCODE
3436 
3437 /*-------------------------------------------------------------------------
3438    Get a time series (1D MRI_IMAGE *) from an array of such things:
3439      pops up a shell to let the user make the selection, with a list
3440      of time series name
3441 
3442      wpar         = parent widget (where to popup)
3443      label        = label for chooser
3444      tsarr        = array of time series (1D images)
3445      init         = index of initial time series to select
3446      func         = routine to call when choice is made
3447             void func( Widget wpar,XtPointer func_data,MCW_choose_cbs *cbs )
3448      func_data    = data to pass to func
3449 
3450      The "ival" stored in the MCW_choose_cbs will the index of the
3451        chosen timeseries in tsarr.  The "imval" be the pointer to the
3452        chosen timeseries itself.  Do NOT mri_free this, since it will just be a
3453        pointer to the correct entry in tsarr (which should not be modified
3454        by any other code during the lifetime of this popup!).
3455 
3456    This routine is coded in such a way that only one chooser will be
3457    active at a time (per application).  This is a deliberate choice.
3458 ---------------------------------------------------------------------------*/
3459 
MCW_choose_timeseries(Widget wpar,char * label,MRI_IMARR * tsarr,int init,gen_func * func,XtPointer func_data)3460 void MCW_choose_timeseries( Widget wpar , char *label ,
3461                             MRI_IMARR *tsarr , int init ,
3462                             gen_func *func , XtPointer func_data )
3463 {
3464    static Widget wpop = NULL , wrc ;
3465    static MCW_choose_data cd ;
3466    Position xx,yy ;
3467    int ib , ll , ltop , num_ts , nvisible , xd,yd ;
3468    Widget wlist = NULL , wlab ;
3469    XmStringTable xmstr ;
3470    XmString xms ;
3471    char *lbuf ;
3472    char pbuf[256] , qbuf[512] ;
3473    MRI_IMAGE *tsim ;
3474 
3475 ENTRY("MCW_choose_timeseries") ;
3476 
3477    /** destructor callback **/
3478 
3479    if( wpar == NULL ){
3480      if( wpop != NULL ){
3481 STATUS("popdown call") ;
3482        XtUnmapWidget( wpop ) ;
3483        XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
3484        XtDestroyWidget( wpop ) ;
3485      }
3486      wpop = NULL ; EXRETURN ;
3487    }
3488 
3489    if( ! XtIsRealized(wpar) ){  /* illegal call */
3490      fprintf(stderr,"\n*** illegal call to MCW_choose_timeseries %s\n",
3491              XtName(wpar) ) ;
3492      EXRETURN ;
3493    }
3494 
3495    MCW_set_listmax( wpar ) ;
3496 
3497    /*--- if popup widget already exists, destroy it ---*/
3498 
3499    if( wpop != NULL ){
3500 STATUS("destroying old widget") ;
3501      XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
3502      XtDestroyWidget( wpop ) ;
3503    }
3504 
3505    wlist = NULL ;
3506 
3507    /*--- sanity checks ---*/
3508 
3509    if( tsarr == NULL || tsarr->num == 0 ) EXRETURN ;
3510    num_ts = tsarr->num ;
3511 
3512 if(PRINT_TRACING){
3513  char str[256]; sprintf(str,"creation with %d choices",num_ts); STATUS(str);
3514 }
3515 
3516    /*--- create popup widget ---*/
3517 
3518    wpop = XtVaCreatePopupShell(                           /* Popup Shell */
3519              MENU , xmDialogShellWidgetClass , wpar ,
3520                 XmNtraversalOn , True ,
3521                 XmNinitialResourcesPersistent , False ,
3522                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
3523              NULL ) ;
3524 
3525    if( MCW_isitmwm(wpar) ){
3526      XtVaSetValues( wpop ,
3527                       XmNmwmDecorations ,  MWM_DECOR_BORDER ,
3528                       XmNmwmFunctions   ,  MWM_FUNC_MOVE
3529                                          | MWM_FUNC_CLOSE ,
3530                     NULL ) ;
3531    }
3532 
3533    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
3534 
3535    XmAddWMProtocolCallback(
3536         wpop ,
3537         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
3538         MCW_kill_chooser_CB , wpop ) ;
3539 
3540    wrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
3541              MENU , xmRowColumnWidgetClass , wpop ,
3542                 XmNpacking     , XmPACK_TIGHT ,
3543                 XmNorientation , XmVERTICAL ,
3544                 XmNtraversalOn , True ,
3545                 XmNinitialResourcesPersistent , False ,
3546              NULL ) ;
3547 
3548    if( label != NULL ){
3549      lbuf = (char*)XtMalloc( strlen(label) + 32 ) ;
3550      sprintf( lbuf , "----Choose One----\n%s" , label ) ;
3551    } else {
3552      lbuf = (char*)XtMalloc( 32 ) ;
3553      sprintf( lbuf , "----Choose One----" ) ;
3554    }
3555    xms = XmStringCreateLtoR( lbuf , XmFONTLIST_DEFAULT_TAG ) ;
3556    wlab = XtVaCreateManagedWidget(
3557                 MENU , xmLabelWidgetClass , wrc ,
3558                    XmNlabelString   , xms  ,
3559                    XmNalignment     , XmALIGNMENT_CENTER ,
3560                    XmNinitialResourcesPersistent , False ,
3561                 NULL ) ;
3562    myXtFree(lbuf) ; XmStringFree(xms) ; LABELIZE(wlab) ;
3563 
3564    (void) XtVaCreateManagedWidget(
3565             MENU , xmSeparatorWidgetClass , wrc ,
3566                 XmNseparatorType , XmSHADOW_ETCHED_IN ,
3567                 XmNinitialResourcesPersistent , False ,
3568             NULL ) ;
3569 
3570    xmstr = (XmStringTable) XtMalloc( num_ts * sizeof(XmString *) ) ;
3571 
3572    xd = yd = ltop = 1 ;
3573    for( ib=0 ; ib < num_ts ; ib++ ){
3574      tsim = IMARR_SUBIMAGE(tsarr,ib) ;
3575      if( tsim == NULL ){
3576        strcpy(pbuf,"** NULL series ??") ;
3577      } else {
3578        if( tsim->name != NULL )
3579          MCW_strncpy(pbuf,IMARR_SUBIMAGE(tsarr,ib)->name,254) ;
3580        else
3581          strcpy(pbuf,"** NO NAME ??") ;
3582 
3583        sprintf(qbuf,"%d",tsim->nx) ; ll = strlen(qbuf) ; xd = MAX(xd,ll) ;
3584        sprintf(qbuf,"%d",tsim->ny) ; ll = strlen(qbuf) ; yd = MAX(yd,ll) ;
3585      }
3586      ll = strlen(pbuf) ; ltop = MAX(ltop,ll) ;
3587    }
3588 
3589    for( ib=0 ; ib < num_ts ; ib++ ){
3590      tsim = IMARR_SUBIMAGE(tsarr,ib) ;
3591      if( tsim == NULL ){
3592        strcpy(qbuf,"** NULL series ??") ;
3593      } else {
3594        if( tsim->name != NULL )
3595          MCW_strncpy(pbuf,IMARR_SUBIMAGE(tsarr,ib)->name,254) ;
3596        else
3597          strcpy(pbuf,"** NO NAME ??") ;
3598 
3599         sprintf(qbuf,"%-*s [%*d x %*d]", ltop,pbuf , xd,tsim->nx , yd,tsim->ny ) ;
3600       }
3601       xmstr[ib] = XmStringCreateSimple( qbuf ) ;
3602    }
3603 
3604    wlist = XmCreateScrolledList( wrc , MENU , NULL , 0 ) ;
3605 
3606    nvisible = (num_ts < list_maxmax ) ? num_ts : list_max ;
3607    XtVaSetValues( wlist ,
3608                     XmNitems            , xmstr ,
3609                     XmNitemCount        , num_ts ,
3610                     XmNvisibleItemCount , nvisible ,
3611                     XmNtraversalOn      , True ,
3612                     XmNselectionPolicy  , XmBROWSE_SELECT ,
3613                   NULL ) ;
3614    if( init >= 0 && init < num_ts ){
3615      XmListSelectPos( wlist , init+1 , False ) ;
3616      if( init+1 > nvisible ) XmListSetBottomPos( wlist , init+1 ) ;
3617    }
3618    XtManageChild(wlist) ;
3619 
3620    XtAddCallback( wlist , XmNdefaultActionCallback , MCW_choose_CB , &cd ) ;
3621 
3622    MCW_register_help( wlist , TSC_list_help_1 ) ;
3623    MCW_register_help( wlab  , TSC_list_help_1 ) ;
3624 
3625    cd.tsarr   = tsarr ;
3626    cd.wchoice = wlist ;
3627    cd.av      = NULL ;
3628 
3629 #if 1
3630    for( ib=0 ; ib < num_ts ; ib++ ) XmStringFree(xmstr[ib]) ;
3631    myXtFree(xmstr) ;
3632 #endif
3633 
3634    cd.wpop    = wpop ;  /* data to be passed to pushbutton callback */
3635    cd.wcaller = wpar ;
3636    cd.sel_CB  = func ;
3637    cd.sel_cd  = func_data ;
3638    cd.ctype   = mcwCT_timeseries ;
3639 
3640    for( ib=0 ; ib < NUM_TSC_ACT ; ib++ ) TSC_act[ib].data = &cd ;
3641 
3642    (void) MCW_action_area( wrc , TSC_act , NUM_TSC_ACT ) ;
3643 
3644    RELOCATE(wpar,wpop,5) ; /* 12 Oct 2017 */
3645 
3646    XtManageChild( wrc ) ;
3647    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
3648 
3649    RWC_visibilize_widget( wpop ) ;   /* 09 Nov 1999 */
3650    NORMAL_cursorize( wpop ) ;
3651 
3652    EXRETURN ;
3653 }
3654 
3655 /*==================================================================================*/
3656 
3657 #define TCV_quit_label   "Quit"
3658 #define TCV_view_label   "View"
3659 #define TCV_apply_label  "Apply"
3660 #define TCV_done_label   "Set"
3661 
3662 #define TCV_quit_help   "Press to close\nthis `chooser'"
3663 #define TCV_view_help   "Press to popup\na view of this\nfile's top"
3664 #define TCV_apply_help  "Press to apply\nthis choice and\nkeep this `chooser'"
3665 #define TCV_done_help   "Press to apply\nthis choice and\nclose this `chooser'"
3666 
3667 #define TCV_list_help_1  OVC_list_help_1
3668 
3669 #define NUM_TCV_ACT 4
3670 
3671 static MCW_action_item TCV_act[] = {
3672  { TCV_quit_label , MCW_choose_CB, NULL, TCV_quit_help ,"Close this window"         , 0 },
3673  { TCV_view_label , MCW_choose_CB, NULL, TCV_view_help ,"View top few lines of data", 0 },
3674  { TCV_apply_label, MCW_choose_CB, NULL, TCV_apply_help,"Apply choice, keep window" , 0 },
3675  { TCV_done_label , MCW_choose_CB, NULL, TCV_done_help ,"Apply choice, close window", 1 }
3676 } ;
3677 
3678 /*-------------------------------------------------------------------------
3679    Get a NI_element from a *.[tc]sv file, from an array of such things:
3680      pops up a shell to let the user make the selection, with a list
3681      of filenames:
3682 
3683      wpar         = parent widget (where to popup)
3684      label        = label for chooser
3685      elarr        = array of NI_elements
3686      init         = index of initial element to select
3687      func         = routine to call when choice is made
3688             void func( Widget wpar,XtPointer func_data,MCW_choose_cbs *cbs )
3689      func_data    = data to pass to func
3690 
3691      The "ival" stored in the MCW_choose_cbs will the index of the
3692        chosen element in elarr.  The "imval" be the pointer to the
3693        chosen NI_element itself (which will have to be cast to the
3694        correct type).  Do NOT NI_free_element this, since it will just be a
3695        pointer to the correct entry in elarr (which should not be modified
3696        by any other code during the lifetime of this popup!).
3697 
3698    This routine is coded in such a way that only one chooser will be
3699    active at a time (per application).  This is a deliberate choice.
3700 ---------------------------------------------------------------------------*/
3701 
MCW_choose_tcsv(Widget wpar,char * label,NI_ELARR * elarr,int init,gen_func * func,XtPointer func_data)3702 void MCW_choose_tcsv( Widget wpar , char *label ,
3703                       NI_ELARR *elarr , int init ,
3704                       gen_func *func , XtPointer func_data )
3705 {
3706    static Widget wpop = NULL , wrc ;
3707    static MCW_choose_data cd ;
3708    Position xx,yy ;
3709    int ib , ll , ltop , num_el , nvisible , xd,yd ;
3710    Widget wlist = NULL , wlab ;
3711    XmStringTable xmstr ;
3712    XmString xms ;
3713    char *lbuf ;
3714    char pbuf[256] , qbuf[512] ;
3715    NI_element *nel ;
3716 
3717 ENTRY("MCW_choose_tcsv") ;
3718 
3719    /** destructor callback **/
3720 
3721    if( wpar == NULL ){
3722      if( wpop != NULL ){
3723 STATUS("popdown call") ;
3724        XtUnmapWidget( wpop ) ;
3725        XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
3726        XtDestroyWidget( wpop ) ;
3727      }
3728      wpop = NULL ; EXRETURN ;
3729    }
3730 
3731    if( ! XtIsRealized(wpar) ){  /* illegal call */
3732      fprintf(stderr,"\n*** illegal call to MCW_choose_tcsv %s\n",
3733              XtName(wpar) ) ;
3734      EXRETURN ;
3735    }
3736 
3737    MCW_set_listmax( wpar ) ;
3738 
3739    /*--- if popup widget already exists, destroy it ---*/
3740 
3741    if( wpop != NULL ){
3742 STATUS("destroying old widget") ;
3743      XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
3744      XtDestroyWidget( wpop ) ;
3745    }
3746 
3747    wlist = NULL ;
3748 
3749    /*--- sanity checks ---*/
3750 
3751    if( elarr == NULL || elarr->num == 0 ) EXRETURN ;
3752    num_el = elarr->num ;
3753 
3754 if(PRINT_TRACING){
3755  char str[256]; sprintf(str,"creation with %d choices",num_el); STATUS(str);
3756 }
3757 
3758    /*--- create popup widget ---*/
3759 
3760    wpop = XtVaCreatePopupShell(                           /* Popup Shell */
3761              MENU , xmDialogShellWidgetClass , wpar ,
3762                 XmNtraversalOn , True ,
3763                 XmNinitialResourcesPersistent , False ,
3764                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
3765              NULL ) ;
3766 
3767    if( MCW_isitmwm(wpar) ){  /* decorate for Motif Window Manager */
3768      XtVaSetValues( wpop ,
3769                       XmNmwmDecorations ,  MWM_DECOR_BORDER ,
3770                       XmNmwmFunctions   ,  MWM_FUNC_MOVE
3771                                          | MWM_FUNC_CLOSE ,
3772                     NULL ) ;
3773    }
3774 
3775    /* what to do when widget is destroyed cruelly */
3776 
3777    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
3778 
3779    /* what to do when window manager shoots widget in the head */
3780 
3781    XmAddWMProtocolCallback(
3782         wpop ,
3783         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
3784         MCW_kill_chooser_CB , wpop ) ;
3785 
3786    /* start creating widgets inside the shell */
3787 
3788    wrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
3789              MENU , xmRowColumnWidgetClass , wpop ,
3790                 XmNpacking     , XmPACK_TIGHT ,
3791                 XmNorientation , XmVERTICAL ,
3792                 XmNtraversalOn , True ,
3793                 XmNinitialResourcesPersistent , False ,
3794              NULL ) ;
3795 
3796    /* top level label describing what's going on */
3797 
3798    if( label != NULL ){
3799      lbuf = (char*)XtMalloc( strlen(label) + 32 ) ;
3800      sprintf( lbuf , "----Choose One----\n%s" , label ) ;
3801    } else {
3802      lbuf = (char*)XtMalloc( 32 ) ;
3803      sprintf( lbuf , "----Choose One----" ) ;
3804    }
3805    xms = XmStringCreateLtoR( lbuf , XmFONTLIST_DEFAULT_TAG ) ;
3806    wlab = XtVaCreateManagedWidget(
3807                 MENU , xmLabelWidgetClass , wrc ,
3808                    XmNlabelString   , xms  ,
3809                    XmNalignment     , XmALIGNMENT_CENTER ,
3810                    XmNinitialResourcesPersistent , False ,
3811                 NULL ) ;
3812    myXtFree(lbuf) ; XmStringFree(xms) ; LABELIZE(wlab) ;
3813 
3814    /* separator, for beauty */
3815 
3816    (void) XtVaCreateManagedWidget(
3817             MENU , xmSeparatorWidgetClass , wrc ,
3818                 XmNseparatorType , XmSHADOW_ETCHED_IN ,
3819                 XmNinitialResourcesPersistent , False ,
3820             NULL ) ;
3821 
3822    /* table of strings from which to choose */
3823 
3824    xmstr = (XmStringTable) XtMalloc( num_el * sizeof(XmString *) ) ;
3825 
3826    /* scan and find max string sizes for element descriptions */
3827 
3828    xd = yd = ltop = 1 ;
3829    for( ib=0 ; ib < num_el ; ib++ ){
3830      nel = ELARR_SUBEL(elarr,ib) ;
3831 
3832      if( nel == NULL ){                  /* should not happen */
3833        strcpy(pbuf,"** NULL file ??") ;
3834      } else {
3835        if( nel->filename != NULL )
3836          MCW_strncpy(pbuf,nel->filename,254) ;  /* filename label */
3837        else
3838          strcpy(pbuf,"** NO NAME ??") ; /* should not happen */
3839 
3840        /* labels for size of data in file (column length, num of columns) */
3841 
3842        sprintf(qbuf,"%d",nel->vec_len) ; ll = strlen(qbuf) ; xd = MAX(xd,ll) ;
3843        sprintf(qbuf,"%d",nel->vec_num) ; ll = strlen(qbuf) ; yd = MAX(yd,ll) ;
3844      }
3845      ll = strlen(pbuf) ; ltop = MAX(ltop,ll) ;
3846    }
3847 
3848    /* repeat above loop to actually make the strings, nicely spaced */
3849 
3850    for( ib=0 ; ib < num_el ; ib++ ){
3851      nel = ELARR_SUBEL(elarr,ib) ;
3852 
3853      if( nel == NULL ){
3854        strcpy(qbuf,"** NULL file ??") ;
3855      } else {
3856        if( nel->filename != NULL )
3857          MCW_strncpy(pbuf,nel->filename,254) ;
3858        else
3859          strcpy(pbuf,"** NO NAME ??") ;
3860 
3861         sprintf(qbuf,"%-*s [%*d x %*d]", ltop,pbuf , xd,nel->vec_len, yd,nel->vec_num ) ;
3862       }
3863       xmstr[ib] = XmStringCreateSimple( qbuf ) ;
3864    }
3865 
3866    /* this is the scrollable list of filenames the user chooses from */
3867 
3868    wlist = XmCreateScrolledList( wrc , MENU , NULL , 0 ) ;
3869 
3870    /* set how many items are visible at once, etc */
3871 
3872    nvisible = (num_el < list_maxmax ) ? num_el : list_max ;
3873    XtVaSetValues( wlist ,
3874                     XmNitems            , xmstr ,
3875                     XmNitemCount        , num_el ,
3876                     XmNvisibleItemCount , nvisible ,
3877                     XmNtraversalOn      , True ,
3878                     XmNselectionPolicy  , XmBROWSE_SELECT ,
3879                   NULL ) ;
3880 
3881    /* set initial highlighted selection */
3882 
3883    if( init >= 0 && init < num_el ){
3884      XmListSelectPos( wlist , init+1 , False ) ;
3885      if( init+1 > nvisible ) XmListSetBottomPos( wlist , init+1 ) ;
3886    }
3887    XtManageChild(wlist) ;
3888 
3889    /* what to do when user actually makes the choice */
3890 
3891    XtAddCallback( wlist , XmNdefaultActionCallback , MCW_choose_CB , &cd ) ;
3892 
3893    /* who the hell needs help? */
3894 
3895    MCW_register_help( wlist , TCV_list_help_1 ) ;
3896    MCW_register_help( wlab  , TCV_list_help_1 ) ;
3897 
3898    cd.tsarr   = (MRI_IMARR *)elarr ;  /* cast to image array for fun */
3899    cd.wchoice = wlist ;
3900    cd.av      = NULL ;
3901 
3902    for( ib=0 ; ib < num_el ; ib++ ) XmStringFree(xmstr[ib]) ;
3903    myXtFree(xmstr) ;
3904 
3905    cd.wpop    = wpop ;  /* data to be passed to pushbutton callback */
3906    cd.wcaller = wpar ;
3907    cd.sel_CB  = func ;
3908    cd.sel_cd  = func_data ;
3909    cd.ctype   = mcwCT_tcsv ;
3910 
3911    for( ib=0 ; ib < NUM_TCV_ACT ; ib++ ) TCV_act[ib].data = &cd ;
3912 
3913    (void) MCW_action_area( wrc , TCV_act , NUM_TCV_ACT ) ;
3914 
3915    RELOCATE(wpar,wpop,5) ; /* 12 Oct 2017 */
3916 
3917    XtManageChild( wrc ) ;
3918    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
3919 
3920    RWC_visibilize_widget( wpop ) ;   /* 09 Nov 1999 */
3921    NORMAL_cursorize( wpop ) ;
3922 
3923    EXRETURN ;
3924 }
3925 
3926 /*==================================================================================*/
3927 
3928 /*-------------------------------------------------------------------------
3929    Get an integer, as an index to an array of strings:
3930    * pops up a shell to let the user make the selection, cycling through
3931      the string array
3932    * allows the user to add to the string array
3933 
3934      wpar         = parent widget (where to popup)
3935      label        = label for chooser
3936      sar          = array of initial strings (see 3ddata.h)
3937                     [may be changed by the user during operations]
3938      init         = index of initial string
3939      func         = routine to call when a selection is made:
3940             void func( Widget wpar,XtPointer func_data,MCW_choose_cbs *cbs )
3941      func_data    = data to pass to func
3942 
3943      The "ival" stored in the MCW_choose_cbs will be the desired result.
3944 
3945    This routine is coded in such a way that only one chooser will be
3946    active at a time (per application).  This is a deliberate choice.
3947 ---------------------------------------------------------------------------*/
3948 
MCW_choose_editable_strlist(Widget wpar,char * label,THD_string_array * sar,int init,gen_func * func,XtPointer func_data)3949 void MCW_choose_editable_strlist( Widget wpar , char *label ,
3950                                   THD_string_array *sar ,
3951                                   int init , gen_func *func , XtPointer func_data )
3952 {
3953    int initar[2] ;
3954    initar[0] = init ;
3955    initar[1] = -666 ;
3956 
3957    MCW_choose_multi_editable_strlist( wpar , label , mcwCT_single_mode ,
3958                                       sar , initar , func , func_data ) ;
3959    return ;
3960 }
3961 
MCW_choose_multi_editable_strlist(Widget wpar,char * label,int mode,THD_string_array * sar,int * init,gen_func * func,XtPointer func_data)3962 void MCW_choose_multi_editable_strlist( Widget wpar , char *label , int mode ,
3963                                         THD_string_array *sar ,
3964                                         int *init ,
3965                                         gen_func *func , XtPointer func_data )
3966 {
3967    static Widget wpop = NULL , wrc , wrc2 ;
3968    static MCW_choose_data cd ;
3969    Position xx,yy ;
3970    int ib , ll , ltop , num_str ;
3971    Widget wlist = NULL , wlab , wtf , wadd ;
3972    XmStringTable xmstr ;
3973    XmString xms ;
3974    char *lbuf ;
3975    int nvisible ;
3976 
3977 ENTRY("MCW_choose_multi_editable_strlist") ;
3978 
3979    /** destructor callback **/
3980 
3981    if( wpar == NULL ){
3982       if( wpop != NULL ){
3983          XtUnmapWidget( wpop ) ;
3984          XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
3985          XtDestroyWidget( wpop ) ;
3986       }
3987       wpop = NULL ; EXRETURN ;
3988    }
3989 
3990    if( ! XtIsRealized(wpar) ){  /* illegal call */
3991       fprintf(stderr,"\n*** illegal call to MCW_choose_strlist %s\n",
3992               XtName(wpar) ) ;
3993       EXRETURN ;
3994    }
3995 
3996    MCW_set_listmax( wpar ) ;
3997 
3998    /*--- if popup widget already exists, destroy it ---*/
3999 
4000    if( wpop != NULL ){
4001       XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ;
4002       XtDestroyWidget( wpop ) ;
4003    }
4004 
4005    wlist = NULL ;
4006 
4007    /*--- create popup widget ---*/
4008 
4009    wpop = XtVaCreatePopupShell(                           /* Popup Shell */
4010              MENU , xmDialogShellWidgetClass , wpar ,
4011                 XmNallowShellResize , True ,
4012                 XmNtraversalOn , True ,
4013                 XmNinitialResourcesPersistent , False ,
4014                 XmNkeyboardFocusPolicy , XmEXPLICIT ,
4015              NULL ) ;
4016 
4017    if( MCW_isitmwm(wpar) ){
4018       XtVaSetValues( wpop ,
4019                         XmNmwmDecorations ,  MWM_DECOR_BORDER ,
4020                         XmNmwmFunctions   ,  MWM_FUNC_MOVE
4021                                            | MWM_FUNC_CLOSE ,
4022                      NULL ) ;
4023    }
4024 
4025    XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ;
4026 
4027    XmAddWMProtocolCallback(
4028         wpop ,
4029         XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) ,
4030         MCW_kill_chooser_CB , wpop ) ;
4031 
4032    /* RowColumn to hold all */
4033 
4034    wrc  = XtVaCreateWidget(
4035              MENU , xmRowColumnWidgetClass , wpop ,
4036                 XmNpacking     , XmPACK_TIGHT ,
4037                 XmNorientation , XmVERTICAL ,
4038                 XmNtraversalOn , True ,
4039                 XmNinitialResourcesPersistent , False ,
4040              NULL ) ;
4041 
4042    /* Label at the top */
4043 
4044    if( label != NULL ){
4045       lbuf = (char*)XtMalloc( strlen(label) + 32 ) ;
4046       sprintf( lbuf , "----Choose %s----\n%s" ,
4047                (mode == mcwCT_single_mode) ? "One" : "One or More" , label ) ;
4048    } else {
4049       lbuf = (char*)XtMalloc( 32 ) ;
4050       sprintf( lbuf , "----Choose %s----",
4051                (mode == mcwCT_single_mode) ? "One" : "One or More" ) ;
4052    }
4053    xms = XmStringCreateLtoR( lbuf , XmFONTLIST_DEFAULT_TAG ) ;
4054    wlab = XtVaCreateManagedWidget(
4055                 MENU , xmLabelWidgetClass , wrc ,
4056                    XmNlabelString   , xms  ,
4057                    XmNalignment     , XmALIGNMENT_CENTER ,
4058                    XmNinitialResourcesPersistent , False ,
4059                 NULL ) ;
4060    myXtFree(lbuf) ; XmStringFree(xms) ; LABELIZE(wlab) ;
4061 
4062    /* Separator line */
4063 
4064    (void) XtVaCreateManagedWidget(
4065             MENU , xmSeparatorWidgetClass , wrc ,
4066                 XmNseparatorType , XmSHADOW_ETCHED_IN ,
4067                 XmNinitialResourcesPersistent , False ,
4068             NULL ) ;
4069 
4070    /* List to choose from */
4071 
4072    wlist = XmCreateScrolledList( wrc , MENU , NULL , 0 ) ;
4073    XtVaSetValues( wlist ,
4074                     XmNtraversalOn      , True ,
4075                     XmNselectionPolicy  , (mode == mcwCT_single_mode)
4076                                           ? XmBROWSE_SELECT : XmMULTIPLE_SELECT ,
4077                   NULL ) ;
4078 
4079    num_str = SARR_NUM(sar) ;
4080 
4081    if( num_str > 0 ){
4082       xmstr = (XmStringTable) XtMalloc( num_str * sizeof(XmString *) ) ;
4083       for( ib=0 ; ib < num_str ; ib++ )
4084          xmstr[ib] = XmStringCreateSimple( SARR_STRING(sar,ib) ) ;
4085 
4086       nvisible = (num_str < list_maxmax ) ? num_str : list_max ;
4087       XtVaSetValues( wlist ,
4088                        XmNitems            , xmstr ,
4089                        XmNitemCount        , num_str ,
4090                        XmNvisibleItemCount , nvisible ,
4091                      NULL ) ;
4092 
4093       if( init != NULL ){
4094          for( ib=0 ; init[ib] >= 0 && init[ib] < num_str ; ib++ )
4095            XmListSelectPos( wlist , init[ib]+1 , False ) ;
4096          if( ib > 0 && init[ib-1] > nvisible )
4097            XmListSetBottomPos( wlist , init[ib-1]+1 ) ;
4098       }
4099 
4100       for( ib=0 ; ib < num_str ; ib++ ) XmStringFree(xmstr[ib]) ;
4101       myXtFree(xmstr) ;
4102    }
4103 
4104    XtManageChild(wlist) ;
4105 
4106    /* Some help? */
4107 
4108    if( mode == mcwCT_multi_mode ){
4109       MCW_register_help( wlist , OVC_list_help_2 ) ;
4110       MCW_register_help( wlab  , OVC_list_help_2 ) ;
4111    } else {
4112       MCW_register_help( wlist , OVC_list_help_1 ) ;
4113       MCW_register_help( wlab  , OVC_list_help_1 ) ;
4114       XtAddCallback( wlist , XmNdefaultActionCallback , MCW_choose_CB , &cd ) ;
4115    }
4116 
4117    cd.wchoice = wlist ;
4118    cd.av      = NULL ;   /* this is NULL --> will use the list widget */
4119 
4120    cd.wpop    = wpop ;  /* data to be passed to pushbutton callback */
4121    cd.wcaller = wpar ;
4122    cd.sel_CB  = func ;
4123    cd.sel_cd  = func_data ;
4124    cd.ctype   = mcwCT_integer ;
4125    cd.sar     = sar ;
4126 
4127    /* action buttons */
4128 
4129    for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ;
4130 
4131    (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ;
4132 
4133    /* choosing mode, for multiple selections */
4134 
4135    if( mode == mcwCT_multi_mode ){
4136       MCW_arrowval *av ;
4137 
4138       (void) XtVaCreateManagedWidget(
4139                MENU , xmSeparatorWidgetClass , wrc ,
4140                    XmNseparatorType , XmSHADOW_ETCHED_IN ,
4141                    XmNinitialResourcesPersistent , False ,
4142                NULL ) ;
4143 
4144       av = new_MCW_optmenu( wrc , "Selection Mode" , 0,NUM_LIST_MODES-1,0,0 ,
4145                             MCW_list_mode_CB , wlist ,
4146                             MCW_av_substring_CB , list_modes ) ;
4147 
4148       MCW_reghelp_children( av->wrowcol , OVC_list_help_2 ) ;
4149       MCW_reghint_children( av->wrowcol , "How list selections work" ) ;
4150    }
4151 
4152    /* Separator line */
4153 
4154    (void) XtVaCreateManagedWidget(
4155             MENU , xmSeparatorWidgetClass , wrc ,
4156                 XmNseparatorType , XmSINGLE_LINE ,
4157                 XmNinitialResourcesPersistent , False ,
4158             NULL ) ;
4159 
4160    /*-- Stuff to string array --*/
4161 
4162    wrc2 = XtVaCreateWidget(                            /* Rowcol for stuff */
4163              MENU , xmRowColumnWidgetClass , wrc ,
4164                 XmNpacking      , XmPACK_TIGHT ,
4165                 XmNorientation  , XmHORIZONTAL ,
4166                 XmNtraversalOn , True ,
4167                 XmNinitialResourcesPersistent , False ,
4168              NULL ) ;
4169 
4170    wtf = XtVaCreateManagedWidget(                      /* String to add */
4171              MENU , TEXT_CLASS , wrc2 ,
4172 
4173                  XmNcolumns         , 24 ,
4174                  XmNeditable        , True ,
4175                  XmNmaxLength       , 128 ,
4176                  XmNresizeWidth     , False ,
4177 
4178                  XmNmarginHeight    , 1 ,
4179                  XmNmarginWidth     , 1 ,
4180 
4181                  XmNcursorPositionVisible , True ,
4182                  XmNblinkRate , 0 ,
4183                  XmNautoShowCursorPosition , True ,
4184 
4185                  XmNinitialResourcesPersistent , False ,
4186                  XmNtraversalOn , True ,
4187               NULL ) ;
4188 
4189    xms = XmStringCreateLtoR( "Add" , XmFONTLIST_DEFAULT_TAG ) ;
4190 
4191    wadd = XtVaCreateManagedWidget(                     /* Button to add it */
4192              MENU , xmPushButtonWidgetClass , wrc2 ,
4193                 XmNlabelString  , xms ,
4194                 XmNtraversalOn , True ,
4195                 XmNinitialResourcesPersistent , False ,
4196              NULL ) ;
4197 
4198    XmStringFree(xms) ;
4199 
4200    MCW_set_widget_bg( wadd , MCW_hotcolor(wadd) , 0 ) ;
4201 
4202    XtAddCallback( wadd, XmNactivateCallback, MCW_stradd_CB, &cd ) ;
4203    XtAddCallback( wtf , XmNactivateCallback, MCW_stradd_CB, &cd ) ;
4204    cd.wtf = wtf ;
4205 
4206    MCW_reghelp_children( wrc2 , "Type an entry and press Add\n"
4207                                 "or hit Enter to make a new\n"
4208                                 "entry in the chooser list."   ) ;
4209 
4210    MCW_reghint_children( wrc2 , "Enter new item into chooser list" ) ;
4211 
4212    XtManageChild( wrc2 ) ;
4213 
4214    /* make it appear, like magic! */
4215 
4216    RELOCATE(wpar,wpop,5) ; /* 12 Oct 2017 */
4217 
4218    XtManageChild( wrc ) ;
4219    XtPopup( wpop , XtGrabNone ) ; RWC_sleep(1);
4220 
4221    RWC_visibilize_widget( wpop ) ;   /* 09 Nov 1999 */
4222    NORMAL_cursorize( wpop ) ;
4223 
4224    EXRETURN ;
4225 }
4226 
4227 /*--------------------------------------------------------------------------*/
4228 
MCW_stradd_CB(Widget w,XtPointer client_data,XtPointer call_data)4229 void MCW_stradd_CB( Widget w, XtPointer client_data, XtPointer call_data )
4230 {
4231    MCW_choose_data *cd = (MCW_choose_data *) client_data ;
4232    char *nstr = TEXT_GET( cd->wtf ) ;
4233    int id , nvisible , num_str ;
4234    XmString xms ;
4235 
4236 ENTRY("MCW_stradd_CB") ;
4237 
4238    if( nstr == NULL || strlen(nstr) == 0 ){
4239      myXtFree(nstr); XBell(XtDisplay(w),100); EXRETURN;
4240    }
4241 
4242    /* see if new string is already in the list */
4243 
4244    for( id=0 ; id < SARR_NUM(cd->sar) ; id++ )
4245       if( strcmp(nstr,SARR_STRING(cd->sar,id)) == 0 ) break ;
4246 
4247    if( id < SARR_NUM(cd->sar) ){ /* found it, so just jump to it in the list */
4248 
4249       XmListSetBottomPos( cd->wchoice , id+1 ) ;      /* put on bottom */
4250       XmListSelectPos( cd->wchoice , id+1 , False ) ; /* select it */
4251 
4252    } else {                      /* is a new string, so add it to the list */
4253 
4254       ADDTO_SARR( cd->sar , nstr ) ;           /* add to internal list */
4255 
4256       xms = XmStringCreateSimple( nstr ) ;
4257       XmListAddItem( cd->wchoice , xms , 0 ) ; /* add to List widget */
4258       XmStringFree(xms) ;
4259 
4260       num_str = SARR_NUM(cd->sar) ;
4261       nvisible = (num_str < list_maxmax) ? num_str : list_max ;
4262       XtVaSetValues( cd->wchoice ,
4263                        XmNvisibleItemCount , nvisible ,
4264                      NULL ) ;
4265 
4266       XmListSetBottomPos( cd->wchoice , 0 ) ;      /* make sure it is visible */
4267       XmListSelectPos( cd->wchoice , 0 , False ) ; /* select it */
4268    }
4269 
4270    myXtFree(nstr) ; EXRETURN ;
4271 }
4272 
4273 /*--------------------------------------------------------------------------*/
4274 
4275 #define LIST_DBCLICK_UNKNOWN   -1
4276 #define LIST_DBCLICK_APPLY      1
4277 #define LIST_DBCLICK_DONE       2
4278 
MCW_choose_CB(Widget w,XtPointer client_data,XtPointer call_data)4279 void MCW_choose_CB( Widget w , XtPointer client_data , XtPointer call_data )
4280 {
4281    MCW_choose_data *cd       = (MCW_choose_data *) client_data ;
4282    char *wname               = XtName(w) ;
4283    XmAnyCallbackStruct *icbs = (XmAnyCallbackStruct *) call_data ;
4284 
4285    static MCW_choose_cbs cbs ;  /* to be passed back to user */
4286    static int list_dbclick_use = LIST_DBCLICK_UNKNOWN ;
4287    RwcBoolean clear ;
4288    XEvent *cbev = (icbs != NULL) ? icbs->event : NULL ;  /* 03 Jun 2009 */
4289 
4290 ENTRY("MCW_choose_CB") ;
4291 
4292    /*--- set up what to do for list double clicks ---*/
4293 
4294    if( list_dbclick_use == LIST_DBCLICK_UNKNOWN ){
4295 #if 0
4296      char *xdef = XGetDefault( XtDisplay(w) , "AFNI" , "chooser_doubleclick" ) ;
4297 #else
4298      char *xdef = RWC_getname( XtDisplay(w) , "chooser_doubleclick" ) ;
4299 #endif
4300      if( xdef != NULL && strcasecmp(xdef,OVC_done_label) != 0 )
4301        list_dbclick_use = LIST_DBCLICK_DONE ;
4302      else
4303        list_dbclick_use = LIST_DBCLICK_APPLY ;
4304    }
4305 
4306    /*--- branch on type of chooser that called this ---*/
4307 
4308    clear = (strcmp(wname,OVC_clear_label) == 0) ;
4309 
4310    if( clear && cd->ctype != mcwCT_string ){   /* bad */
4311       XBell( XtDisplay(cd->wpop) , 100 ) ;
4312       RWC_XtPopdown( cd->wpop ) ;
4313       EXRETURN ;
4314    }
4315 
4316    switch( cd->ctype ){
4317 
4318       default:                                   /* error! */
4319          XBell( XtDisplay(w) , 100 ) ;
4320          fprintf(stderr,
4321                  "\n*** unknown choose type=%d from %s\n", cd->ctype, wname ) ;
4322          EXRETURN ;
4323 
4324       /*.....................*/
4325 
4326       case mcwCT_vector:{                    /* vector chooser [19 Mar 2004] */
4327          RwcBoolean done,call ;
4328          int iv ; float *vec ;
4329          MCW_arrowval **aav = (MCW_arrowval **)cd->av ;
4330 
4331          done = strcmp(wname,OVC_apply_label) != 0 ;
4332          call = strcmp(wname,OVC_quit_label)  != 0 ;
4333 
4334          if( done ) RWC_XtPopdown( cd->wpop ) ;
4335 
4336          if( call && cd->sel_CB != NULL ){
4337             cbs.reason = mcwCR_vector ;  /* set structure for call to user */
4338             cbs.event  = cbev ;
4339             cbs.ival   = cd->nvec ;
4340             vec        = (float *)malloc(sizeof(float)*cd->nvec) ;
4341             cbs.cval   = (char *)vec ;
4342             for( iv=0 ; iv < cd->nvec ; iv++ ) vec[iv] = aav[iv]->fval ;
4343 
4344             if( !done ) MCW_invert_widget(w) ;              /* flash */
4345 #if 0
4346             cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */
4347 #else
4348             AFNI_CALL_VOID_3ARG( cd->sel_CB ,
4349                                  Widget           , cd->wcaller ,
4350                                  XtPointer        , cd->sel_cd  ,
4351                                  MCW_choose_cbs * , &cbs         ) ;
4352 #endif
4353             free((void *)vec) ; cbs.cval = NULL ;
4354             if( !done ) MCW_invert_widget(w) ;              /* flash */
4355          }
4356          EXRETURN ;
4357       }
4358 
4359       /*.....................*/
4360 
4361       case mcwCT_ovcolor:{                       /* color chooser */
4362          RwcBoolean done , call ;
4363 
4364          done = strcmp(wname,OVC_apply_label) != 0 ;
4365          call = strcmp(wname,OVC_quit_label)  != 0 ;
4366 
4367          if( done ) RWC_XtPopdown( cd->wpop ) ;
4368 
4369          if( call && cd->sel_CB != NULL ){
4370             cbs.reason = mcwCR_ovcolor ;  /* set structure for call to user */
4371             cbs.event  = cbev ;
4372             cbs.ival   = cd->av->ival ;
4373 
4374             if( !done ) MCW_invert_widget(w) ;              /* flash */
4375 #if 0
4376             cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */
4377 #else
4378             AFNI_CALL_VOID_3ARG( cd->sel_CB ,
4379                                  Widget           , cd->wcaller ,
4380                                  XtPointer        , cd->sel_cd  ,
4381                                  MCW_choose_cbs * , &cbs         ) ;
4382 #endif
4383             if( !done ) MCW_invert_widget(w) ;              /* flash */
4384          }
4385          EXRETURN ;
4386       }
4387 
4388       /*.....................*/
4389 
4390       case mcwCT_integer:{                       /* integer chooser */
4391          RwcBoolean done , call , flash ;
4392 
4393          done  = strcmp(wname,OVC_apply_label) != 0 ;  /* done unless just "Apply" */
4394          flash = ! done ;                              /* flash if not done */
4395          call  = strcmp(wname,OVC_quit_label)  != 0 ;  /* call unless just "Quit" */
4396          if( w == cd->wchoice ){    /* Double click in List */
4397            done  = (list_dbclick_use == LIST_DBCLICK_DONE) ;
4398            flash = False ;
4399            call  = True ;
4400          }
4401 
4402          if( done ) RWC_XtPopdown( cd->wpop ) ;
4403 
4404          if( call && cd->sel_CB != NULL ){
4405             int pos_count=0 , *pos_list=NULL , ib ;
4406             RwcBoolean any ;
4407 
4408             cbs.reason = mcwCR_integer ;    /* set structure for call to user */
4409             cbs.event  = cbev ;
4410 
4411             if( cd->av != NULL ){           /* chooser was an arrowval */
4412                cbs.ival   = cd->av->ival ;
4413                cbs.fval   = cd->av->fval ;  /* 21 Jan 1997 */
4414                cbs.nilist = 1 ;
4415                cbs.ilist  = &(cbs.ival) ;
4416 
4417             } else {                        /* chooser was a List widget */
4418                any = XmListGetSelectedPos( cd->wchoice, &pos_list, &pos_count ) ;
4419                if( any ){
4420                   for( ib=0 ; ib < pos_count ; ib++ )  /* List indexes */
4421                      pos_list[ib]-- ;                  /* start at 1.  */
4422 
4423                   cbs.ival   = pos_list[0] ;           /* holds the first choice */
4424                   cbs.fval   = cbs.ival ;              /* 21 Jan 1997 */
4425                   cbs.nilist = pos_count ;             /* number of choices */
4426                   cbs.ilist  = pos_list ;              /* holds all choices */
4427                } else {
4428                   EXRETURN ;  /* no choice made */
4429                }
4430             }
4431 
4432             if( flash ) MCW_invert_widget(w) ;              /* flash */
4433 #if 0
4434             cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */
4435 #else
4436             AFNI_CALL_VOID_3ARG( cd->sel_CB ,
4437                                  Widget           , cd->wcaller ,
4438                                  XtPointer        , cd->sel_cd  ,
4439                                  MCW_choose_cbs * , &cbs         ) ;
4440 #endif
4441             if( flash ) MCW_invert_widget(w) ;              /* flash */
4442 
4443             myXtFree(pos_list) ;
4444          }
4445          EXRETURN ;
4446       }
4447 
4448       /*.....................*/
4449 
4450       case mcwCT_string:{                 /* string chooser */
4451          RwcBoolean done , call , istextf ;
4452 
4453          /* special action: "Clear" button */
4454 
4455          if( clear ){ TEXT_SET( cd->wchoice , "" ) ; EXRETURN ; }
4456 
4457          /* find out if called by the text field itself */
4458 
4459          istextf = XtIsSubclass( w , TEXT_CLASS ) ;
4460 
4461          if( istextf == False ){                         /* check button names */
4462             done = strcmp(wname,OVC_apply_label) != 0 ;  /* to decide upon */
4463             call = strcmp(wname,OVC_quit_label)  != 0 ;  /* correct actions */
4464          } else {
4465             done = False ;   /* input from textfield == press "Apply" */
4466             call = True ;
4467          }
4468 
4469          if( done ) RWC_XtPopdown( cd->wpop ) ;
4470 
4471          if( call && cd->sel_CB != NULL ){
4472             cbs.reason = mcwCR_string ;  /* set structure for call to user */
4473             cbs.event  = cbev ;
4474             cbs.cval   = TEXT_GET( cd->wchoice ) ;
4475 
4476             if( !done ) MCW_invert_widget(w) ;              /* flash */
4477 #if 0
4478             cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */
4479 #else
4480             AFNI_CALL_VOID_3ARG( cd->sel_CB ,
4481                                  Widget           , cd->wcaller ,
4482                                  XtPointer        , cd->sel_cd  ,
4483                                  MCW_choose_cbs * , &cbs         ) ;
4484 #endif
4485             if( !done ) MCW_invert_widget(w) ;              /* flash */
4486 
4487             myXtFree( cbs.cval ) ; cbs.cval = NULL ;
4488          }
4489          EXRETURN ;
4490       }
4491 
4492       /*.....................*/
4493 
4494       case mcwCT_timeseries:{                       /* timeseries chooser */
4495          RwcBoolean done , call , flash , any , plot ;
4496          int pos_count , *pos_list ;
4497 
4498 #ifdef AFNI_DEBUG
4499 printf("MCW_choose_CB: timeseries choice made\n") ;
4500 #endif
4501 
4502          if( w == cd->wchoice ){  /* choice is from double click in List widget */
4503             done  = (list_dbclick_use == LIST_DBCLICK_DONE) ;
4504             flash = False ;
4505             plot  = False ;
4506             call  = True ;
4507          } else {                 /* choice is from control buttons */
4508 
4509             done  = (strcmp(wname,TSC_quit_label) == 0) ||   /* are we done with   */
4510                     (strcmp(wname,TSC_done_label) == 0)    ; /* this popup widget? */
4511 
4512             flash = ! done ;                                 /* flash if not done */
4513 
4514             call  = (strcmp(wname,TSC_apply_label) == 0) ||  /* do we call the  */
4515                     (strcmp(wname,TSC_done_label)  == 0)   ; /* user's routine? */
4516 
4517             plot  = (strcmp(wname,TSC_plot_label)  == 0) ;   /* do we plot a graph? */
4518          }
4519 
4520 #ifdef BBOX_DEBUG
4521 printf("MCW_choose_CB: done=%d  call=%d  plot=%d  flash=%d\n",
4522        (int)done , (int)call , (int)plot , (int)flash ) ;
4523 #endif
4524 
4525          if( done ) RWC_XtPopdown( cd->wpop ) ;
4526 
4527          if( call || plot ){  /* must find out what is selected */
4528             int pos_count , *pos_list , first ;
4529             MRI_IMAGE *fim ;
4530 
4531 #ifdef BBOX_DEBUG
4532 printf("MCW_choose_CB: querying list for choice\n") ;
4533 #endif
4534 
4535             any = XmListGetSelectedPos( cd->wchoice , &pos_list , &pos_count ) ;
4536 
4537 #ifdef BBOX_DEBUG
4538 printf("MCW_choose_CB: queryed list for choice\n") ;
4539 #endif
4540 
4541             if( any ){
4542                 first = pos_list[0] - 1 ;                 /* XmList index starts at 1 */
4543                 fim   = IMARR_SUBIMAGE(cd->tsarr,first) ;
4544                 myXtFree(pos_list) ;
4545             } else {  /* no choice made --> nothing to do! */
4546                 if( plot ) XBell( XtDisplay(w) , 100 ) ;
4547                 EXRETURN ;
4548             }
4549 
4550 #ifdef BBOX_DEBUG
4551 printf("MCW_choose_CB: choice index = %d\n",first) ;
4552 #endif
4553 
4554             if( call && cd->sel_CB != NULL ){
4555                cbs.reason = mcwCR_timeseries ;  /* set structure for call to user */
4556                cbs.event  = cbev ;
4557                cbs.ival   = first ;
4558                cbs.imval  = fim ;
4559 
4560 #ifdef BBOX_DEBUG
4561 printf("MCW_choose_CB: calling user supplied routine\n") ;
4562 #endif
4563 
4564                if( flash ) MCW_invert_widget(w) ;              /* flash */
4565 #if 0
4566                cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */
4567 #else
4568                AFNI_CALL_VOID_3ARG( cd->sel_CB ,
4569                                     Widget           , cd->wcaller ,
4570                                     XtPointer        , cd->sel_cd  ,
4571                                     MCW_choose_cbs * , &cbs         ) ;
4572 #endif
4573                if( flash ) MCW_invert_widget(w) ;              /* flash */
4574                EXRETURN ;
4575             }
4576 
4577             if( plot ){
4578 
4579 #ifdef BBOX_DEBUG
4580 printf("MCW_choose_CB: plotting selected timeseries\n") ;
4581 #endif
4582 
4583             /*-- 17 Aug 1998: plotting code (at last!) --*/
4584 
4585 #ifdef DONT_USE_COXPLOT
4586                (void) MCW_popup_message( w , "Plot not yet\nimplemented." ,
4587                                          MCW_USER_KILL | MCW_TIMER_KILL ) ;
4588                EXRETURN ;
4589 #else
4590                if( fim->kind != MRI_float ){
4591                   (void) MCW_popup_message( w , "Can't plot\nnon-float data!" ,
4592                                             MCW_USER_KILL | MCW_TIMER_KILL ) ;
4593                   EXRETURN ;
4594                } else {
4595                   float **yar , *far = MRI_FLOAT_PTR(fim) ;
4596                   char **nar=NULL ;
4597                   int jj ;
4598 
4599 #undef USE_NAR  /* use labels for each column?  (just to test the code) */
4600 
4601                   yar = (float **) malloc( sizeof(float *) * fim->ny ) ;
4602                   for( jj=0 ; jj < fim->ny ; jj++ )
4603                      yar[jj] = far + jj * fim->nx ;
4604 
4605 #ifdef USE_NAR
4606                   nar = (char **)  malloc( sizeof(char * ) * fim->ny ) ;
4607                   for( jj=0 ; jj < fim->ny ; jj++ ){
4608                      nar[jj] = (char *) malloc( sizeof(char) * 32 ) ;
4609                      sprintf(nar[jj],"column %d",jj+1) ;
4610                   }
4611 #endif
4612                   X11_SET_NEW_PLOT ;
4613                   plot_ts_lab( XtDisplay(w) ,
4614                                fim->nx , NULL , fim->ny , yar ,
4615                                "index" , NULL , fim->name , nar , NULL ) ;
4616 
4617                   if( nar != NULL ){
4618                      for( jj=0 ; jj < fim->ny ; jj++ ) free(nar[jj]) ;
4619                      free(nar) ;
4620                   }
4621                   free(yar) ;
4622                   EXRETURN ;
4623                }
4624 #endif /* DONT_USE_COXPLOT */
4625             }
4626 
4627          }
4628          EXRETURN ;
4629       }
4630 
4631       /*.....................*/
4632 
4633       case mcwCT_tcsv:{                       /* *.[tc]sv chooser [19 Jun 2020] */
4634          RwcBoolean done=FALSE , call=FALSE , flash=FALSE , any=FALSE , view=FALSE ;
4635 
4636 #ifdef AFNI_DEBUG
4637 printf("MCW_choose_CB: tcsv choice made\n") ;
4638 #endif
4639 
4640          if( w == cd->wchoice ){  /* choice is from double click in List widget */
4641             done  = (list_dbclick_use == LIST_DBCLICK_DONE) ;
4642             flash = False ;
4643             view  = False ;
4644             call  = True ;
4645          } else {                 /* choice is from control buttons */
4646 
4647             done  = (strcmp(wname,TCV_quit_label) == 0) ||   /* are we done with   */
4648                     (strcmp(wname,TCV_done_label) == 0)    ; /* this popup widget? */
4649 
4650             flash = ! done ;                                 /* flash if not done */
4651 
4652             call  = (strcmp(wname,TCV_apply_label) == 0) ||  /* do we call the  */
4653                     (strcmp(wname,TCV_done_label)  == 0)   ; /* user's routine? */
4654 
4655             view  = (strcmp(wname,TCV_view_label)  == 0) ;   /* do we view data? */
4656          }
4657 
4658 #ifdef BBOX_DEBUG
4659 printf("MCW_choose_CB: done=%d  call=%d  view=%d  flash=%d\n",
4660        (int)done , (int)call , (int)view , (int)flash ) ;
4661 #endif
4662 
4663          if( done ) RWC_XtPopdown( cd->wpop ) ;
4664 
4665          if( call || view ){  /* must find out what item is selected */
4666             int pos_count=0 , *pos_list=NULL , first=0 ;
4667             NI_element *nel=NULL ; NI_ELARR *elarr = (NI_ELARR *)cd->tsarr ;
4668 
4669 #ifdef BBOX_DEBUG
4670 printf("MCW_choose_CB: querying list for choice\n") ;
4671 #endif
4672 
4673             any = XmListGetSelectedPos( cd->wchoice , &pos_list , &pos_count ) ;
4674 
4675 #ifdef BBOX_DEBUG
4676 printf("MCW_choose_CB: queryed list for choice\n") ;
4677 #endif
4678 
4679             if( any && pos_list != NULL ){
4680                 first = pos_list[0] - 1 ;                 /* XmList index starts at 1 */
4681                 nel   = ELARR_SUBEL(elarr,first) ;
4682                 myXtFree(pos_list) ;
4683             } else {  /* no choice made --> nothing to do! */
4684                 if( view ) XBell( XtDisplay(w) , 100 ) ;
4685                 EXRETURN ;
4686             }
4687 
4688 #ifdef BBOX_DEBUG
4689 printf("MCW_choose_CB: choice index = %d\n",first) ;
4690 #endif
4691 
4692             /** call the user function to do something with the choice **/
4693 
4694             if( call && cd->sel_CB != NULL ){
4695                cbs.reason = mcwCR_tcsv ;  /* set structure for call to user */
4696                cbs.event  = cbev ;
4697                cbs.ival   = first ;
4698                cbs.imval  = (MRI_IMAGE *)nel ;
4699 
4700 #ifdef BBOX_DEBUG
4701 printf("MCW_choose_CB: calling user supplied routine\n") ;
4702 #endif
4703 
4704                if( flash ) MCW_invert_widget(w) ;              /* flash */
4705 #if 0
4706                cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */
4707 #else
4708                AFNI_CALL_VOID_3ARG( cd->sel_CB ,
4709                                     Widget           , cd->wcaller ,
4710                                     XtPointer        , cd->sel_cd  ,
4711                                     MCW_choose_cbs * , &cbs         ) ;
4712 #endif
4713                if( flash ) MCW_invert_widget(w) ;              /* flash */
4714                EXRETURN ;
4715             }
4716 
4717             /** popup a text viewer for the first few lines of the file **/
4718 
4719 #define NVIEW_TCSV 4
4720             if( view && nel != NULL ){
4721               int ii , jj , qq , nview ;
4722               char *qpt,*zpt , *vstring ;
4723 
4724               nview = AFNI_numenv("AFNI_TCSV_VIEWNUM") ;
4725               if( nview < 1 ) nview = NVIEW_TCSV ;
4726               vstring = NI_preview_string( nel , nview  , NULL ) ;
4727 
4728               /* popup the "view" window */
4729               if( vstring != NULL ){
4730                 (void) MCW_popup_message( w , vstring , MCW_USER_KILL ) ;
4731                 free( vstring ) ;
4732               }
4733            }
4734          }
4735          EXRETURN ;
4736       }
4737 
4738    }  /* end of switch on ctype */
4739 
4740    EXRETURN ;  /* unreachable */
4741 }
4742 
4743 /*----------------------------------------------------------------------------*/
4744 /*----------------------------------------------------------------------------*/
4745 
4746 #define MSTUF_tofree(ic) \
4747    ( (ic) == MSTUF_INT || (ic) == MSTUF_STRLIST || (ic) == MSTUF_YESNO )
4748 
4749 static int     CS_nsav = 0 ;
4750 static void ** CS_sav  = NULL ;
4751 static int *   CS_scod = NULL ;
4752 
4753 static gen_func *CS_func      = NULL ;
4754 static XtPointer CS_func_data = NULL ;
4755 static Widget    CS_wpop      = NULL ;
4756 static Widget    CS_wpar      = NULL ;
4757 
4758 #define NUM_CSO_ACT 3
4759 static MCW_action_item CSO_act[] = {
4760  { OVC_quit_label , MCW_stuff_CB, NULL, OVC_quit_help ,"Close window"                 ,0 },
4761  { OVC_apply_label, MCW_stuff_CB, NULL, OVC_apply_help,"Apply choice and keep window" ,0 },
4762  { OVC_done_label , MCW_stuff_CB, NULL, OVC_done_help ,"Apply choice and close window",1 },
4763 } ;
4764 
4765 /*----------------------------------------------------------------------------*/
4766 
MCW_stuff_CB(Widget w,XtPointer client_data,XtPointer call_data)4767 void MCW_stuff_CB( Widget w , XtPointer client_data , XtPointer call_data )
4768 {
4769    char *wname = XtName(w) ;
4770    XmAnyCallbackStruct *icbs = (XmAnyCallbackStruct *)call_data ;
4771    XEvent *cbev = (icbs != NULL) ? icbs->event : NULL ;
4772    void **outval ; int iss, done,call ;
4773 
4774 ENTRY("MCW_stuff_CB") ;
4775 
4776    if( CS_wpop == NULL || CS_nsav == 0 ) EXRETURN ;  /* should not happen */
4777 
4778    done = (strcmp(wname,OVC_apply_label) != 0) ;
4779    call = (strcmp(wname,OVC_quit_label)  != 0) ;
4780    if( done  ) RWC_XtPopdown(CS_wpop) ;
4781    if( !call ) EXRETURN ;
4782 
4783    outval = (void **)calloc(CS_nsav,sizeof(void *)) ;
4784 
4785    for( iss=0 ; iss < CS_nsav ; iss++ ){
4786      switch( CS_scod[iss] ){
4787        case MSTUF_INT:{
4788          MCW_arrowval *av = (MCW_arrowval *)CS_sav[iss] ;
4789          outval[iss] = (void *)(intptr_t)(av->ival) ;
4790        }
4791        break ;
4792 
4793        case MSTUF_STRING:{
4794          Widget wtf = (Widget)CS_sav[iss] ;
4795          outval[iss] = (void *)TEXT_GET(wtf) ;
4796        }
4797        break ;
4798 
4799        case MSTUF_STRLIST:{
4800          MCW_arrowval *av = (MCW_arrowval *)CS_sav[iss] ;
4801          outval[iss] = (void *)(av->sval) ;
4802        }
4803 
4804        case MSTUF_YESNO:{
4805          MCW_arrowval *av = (MCW_arrowval *)CS_sav[iss] ;
4806          outval[iss] = (void *)(av->sval) ;
4807        }
4808        break ;
4809      }
4810    }
4811 
4812    AFNI_CALL_VOID_4ARG( CS_func ,
4813                           Widget    , CS_wpar ,
4814                           XtPointer , CS_func_data ,
4815                           int       , CS_nsav ,
4816                           void **   , outval ) ;
4817 
4818    free(outval) ; EXRETURN ;
4819 }
4820 
4821 /*----------------------------------------------------------------------------*/
4822 /* Call this multi-item chooser like
4823       MCW_choose_stuff( parent_widget , "Top Label" ,
4824                         call_func     , call_func_data ,
4825                           ITEM ,
4826                           ITEM , ...
4827                         MSTUF_END    ) ;
4828    where ITEM is one of the following lists specifying something to choose:
4829       MSTUF_INT    , label , bot , top , init
4830       MSTUF_STRING , label
4831       MSTUF_STRLIST, label, nstring , init_index , string_array
4832       MSTUF_YESNO  , label  [like STRLIST with {"No","Yes"} as input array]
4833 
4834    The call_func is called like so
4835 
4836  void call_func( Widget wpar, XtPointer call_func_data, int nval, void **val );
4837 
4838    This function must know what the types to which to cast each val[] result.
4839 *//*--------------------------------------------------------------------------*/
4840 
MCW_choose_stuff(Widget wpar,char * mainlabel,gen_func * func,XtPointer func_data,...)4841 void MCW_choose_stuff( Widget wpar , char *mainlabel ,
4842                        gen_func *func , XtPointer func_data , ... )
4843 {
4844    Widget wrc ;
4845    va_list vararg_ptr ;
4846    Position xx,yy ;
4847    int iss , scode ;
4848 
4849 ENTRY("MCW_choose_stuff") ;
4850 
4851    /** destructor callback **/
4852 
4853    if( wpar == NULL ){
4854      if( CS_wpop != NULL ){
4855        XtUnmapWidget( CS_wpop ) ;
4856        XtRemoveCallback( CS_wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &CS_wpop ) ;
4857        XtDestroyWidget( CS_wpop ) ;
4858      }
4859      CS_wpop = NULL ; CS_wpar = NULL ; EXRETURN ;
4860    }
4861 
4862    if( ! XtIsRealized(wpar) ){  /* illegal call */
4863      fprintf(stderr,"\n*** illegal call to MCW_choose_stuff: %s\n",XtName(wpar)) ;
4864      EXRETURN ;
4865    }
4866 
4867    /*--- if popup widget already exists, destroy it ---*/
4868 
4869    if( CS_wpop != NULL ){
4870       XtRemoveCallback( CS_wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &CS_wpop ) ;
4871       XtDestroyWidget( CS_wpop ) ;
4872    }
4873    if( CS_nsav > 0 ){
4874      for( iss=0 ; iss < CS_nsav ; iss++ ){
4875        if( MSTUF_tofree(CS_scod[iss]) ) myXtFree(CS_sav[iss]) ;
4876      }
4877      free(CS_sav) ; free(CS_scod) ;
4878    }
4879    CS_sav = NULL ; CS_scod = NULL ; CS_nsav = 0 ;
4880 
4881    /*--- create popup widget ---*/
4882 
4883    CS_wpop = XtVaCreatePopupShell(                           /* Popup Shell */
4884                MENU , xmDialogShellWidgetClass , wpar ,
4885                   XmNtraversalOn , True ,
4886                   XmNinitialResourcesPersistent , False ,
4887                   XmNkeyboardFocusPolicy , XmEXPLICIT ,
4888                NULL ) ;
4889 
4890    CS_wpar = wpar ; CS_func = func ; CS_func_data = func_data ;
4891 
4892    if( MCW_isitmwm(CS_wpar) ){
4893       XtVaSetValues( CS_wpop ,
4894                         XmNmwmDecorations , MWM_DECOR_BORDER ,
4895                         XmNmwmFunctions   , MWM_FUNC_MOVE ,
4896                      NULL ) ;
4897    }
4898 
4899    XtAddCallback( CS_wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &CS_wpop ) ;
4900 
4901    XmAddWMProtocolCallback(
4902         CS_wpop ,
4903         XmInternAtom( XtDisplay(CS_wpop) , "WM_DELETE_WINDOW" , False ) ,
4904         MCW_kill_chooser_CB , CS_wpop ) ;
4905 
4906    wrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
4907              MENU , xmRowColumnWidgetClass , CS_wpop ,
4908                 XmNpacking      , XmPACK_TIGHT ,
4909                 XmNorientation  , XmVERTICAL ,
4910                 XmNtraversalOn , True ,
4911                 XmNinitialResourcesPersistent , False ,
4912              NULL ) ;
4913 
4914    if( mainlabel != NULL && *mainlabel != '\0' ){
4915      Widget wlab ;
4916      wlab = XtVaCreateManagedWidget(
4917                MENU , xmLabelWidgetClass , wrc ,
4918                   LABEL_ARG(mainlabel) ,
4919                   XmNinitialResourcesPersistent , False ,
4920                NULL ) ;
4921      LABELIZE(wlab) ;
4922      (void) XtVaCreateManagedWidget(
4923               MENU , xmSeparatorWidgetClass , wrc ,
4924                 XmNseparatorType , XmSHADOW_ETCHED_IN ,
4925                 XmNinitialResourcesPersistent , False ,
4926               NULL ) ;
4927    }
4928 
4929    /* now loop over variable arguments to create selectors */
4930 
4931    va_start( vararg_ptr , func_data ) ;
4932 
4933    do{
4934      scode = va_arg( vararg_ptr , int ) ;   /** get next arg **/
4935      if( scode <= 0 ) break ;               /** no more args **/
4936 
4937      switch( scode ){
4938 
4939        default:  ERROR_message("Illegal code %d in MCW_choose_stuff()",scode) ;
4940                  EXRETURN ;
4941 
4942        case MSTUF_INT:{      /* label, bot, top, init */
4943          int bot, top, init ; char *lab ; MCW_arrowval *av ;
4944          lab  = va_arg( vararg_ptr , char * ) ;
4945          bot  = va_arg( vararg_ptr , int    ) ;
4946          top  = va_arg( vararg_ptr , int    ) ;
4947          init = va_arg( vararg_ptr , int    ) ;
4948          if( bot >= top ) top = bot+1 ;
4949          if( init < bot ) init = bot ; else if( init > top ) init = top ;
4950          av = new_MCW_arrowval( wrc ,
4951                                 lab , MCW_AV_downup ,  /* selection */
4952                                 bot,top,init ,
4953                                 MCW_AV_edittext , 0 ,
4954                                 NULL , NULL , NULL , NULL ) ;
4955          av->allow_wrap = 1 ;
4956          CS_sav = (void **)realloc( CS_sav , sizeof(void *)*(CS_nsav+1) ) ;
4957          CS_sav[CS_nsav] = (void *)av ;
4958          CS_scod = (int *)realloc( CS_scod , sizeof(int)*(CS_nsav+1) ) ;
4959          CS_scod[CS_nsav] = scode ;
4960          CS_nsav++ ;
4961        }
4962        break ;
4963 
4964        case MSTUF_STRING:{   /* label */
4965          char *lab ; Widget hrc, wlab, wtf ; int ncol=16 ;
4966          hrc  = XtVaCreateWidget(                 /* RowColumn to hold all */
4967                   MENU , xmRowColumnWidgetClass , wrc ,
4968                     XmNpacking      , XmPACK_TIGHT ,
4969                     XmNorientation  , XmHORIZONTAL ,
4970                     XmNtraversalOn , True ,
4971                     XmNinitialResourcesPersistent , False ,
4972                   NULL ) ;
4973          lab = va_arg( vararg_ptr , char * ) ;
4974          wlab = XtVaCreateManagedWidget(
4975                   MENU , xmLabelWidgetClass , hrc ,
4976                     LABEL_ARG(lab) ,
4977                     XmNinitialResourcesPersistent , False ,
4978                   NULL ) ;
4979          LABELIZE(wlab) ;
4980          wtf = XtVaCreateManagedWidget(
4981                  MENU , TEXT_CLASS , hrc ,
4982                    XmNcolumns         , ncol ,
4983                    XmNeditable        , True ,
4984                    XmNmaxLength       , 31 ,
4985                    XmNresizeWidth     , False ,
4986                    XmNmarginHeight    , 1 ,
4987                    XmNmarginWidth     , 1 ,
4988                    XmNcursorPositionVisible , True ,
4989                    XmNblinkRate , 0 ,
4990                    XmNautoShowCursorPosition , True ,
4991                    XmNinitialResourcesPersistent , False ,
4992                    XmNtraversalOn , True ,
4993                 NULL ) ;
4994          XtAddCallback( wtf,XmNactivateCallback,MCW_stuff_CB,NULL ) ; /* return key */
4995          XtManageChild(hrc) ;
4996          CS_sav = (void **)realloc( CS_sav , sizeof(void *)*(CS_nsav+1) ) ;
4997          CS_sav[CS_nsav] = (void *)wtf ;
4998          CS_scod = (int *)realloc( CS_scod , sizeof(int)*(CS_nsav+1) ) ;
4999          CS_scod[CS_nsav] = scode ;
5000          CS_nsav++ ;
5001        }
5002        break ;
5003 
5004        case MSTUF_STRLIST:{  /* label, nstring , init_index , string_array */
5005          char *lab ; char **strlist ; MCW_arrowval *av ; int nstr , init ;
5006          lab     = va_arg( vararg_ptr , char *  ) ; if( lab     == NULL ) break ;
5007          nstr    = va_arg( vararg_ptr , int     ) ; if( nstr    <= 1    ) break ;
5008          init    = va_arg( vararg_ptr , int     ) ;
5009          strlist = va_arg( vararg_ptr , char ** ) ; if( strlist == NULL ) break ;
5010 
5011          av = new_MCW_optmenu( wrc , lab ,
5012                                 0 , nstr-1 , init , 0 ,
5013                                 NULL , NULL ,
5014                                 MCW_av_substring_CB , strlist ) ;
5015 
5016          CS_sav = (void **)realloc( CS_sav , sizeof(void *)*(CS_nsav+1) ) ;
5017          CS_sav[CS_nsav] = (void *)av ;
5018          CS_scod = (int *)realloc( CS_scod , sizeof(int)*(CS_nsav+1) ) ;
5019          CS_scod[CS_nsav] = scode ;
5020          CS_nsav++ ;
5021        }
5022        break ;
5023 
5024        case MSTUF_YESNO:{  /* label */
5025          static char *strlist[2] = { "No" , "Yes" } ;
5026          char *lab ; MCW_arrowval *av ;
5027          lab = va_arg( vararg_ptr , char *  ) ; if( lab == NULL ) break ;
5028 
5029          av = new_MCW_optmenu( wrc , lab ,
5030                                 0 , 1 , 0 , 0 ,
5031                                 NULL , NULL ,
5032                                 MCW_av_substring_CB , strlist ) ;
5033 
5034          CS_sav = (void **)realloc( CS_sav , sizeof(void *)*(CS_nsav+1) ) ;
5035          CS_sav[CS_nsav] = (void *)av ;
5036          CS_scod = (int *)realloc( CS_scod , sizeof(int)*(CS_nsav+1) ) ;
5037          CS_scod[CS_nsav] = scode ;
5038          CS_nsav++ ;
5039        }
5040        break ;
5041 
5042      }
5043    }while(1) ;
5044    va_end( vararg_ptr ) ;
5045 
5046    for( iss=0 ; iss < NUM_CSO_ACT ; iss++ ) CSO_act[iss].data = NULL ;
5047    (void) MCW_action_area( wrc , CSO_act , NUM_CSO_ACT ) ;
5048 
5049    RELOCATE(CS_wpar,CS_wpop,2) ; /* 12 Oct 2017 */
5050    XtManageChild( wrc ) ;
5051    XtPopup( CS_wpop , XtGrabNone ) ; RWC_sleep(1);
5052    RWC_visibilize_widget( CS_wpop ) ;
5053    NORMAL_cursorize( CS_wpop ) ;
5054 
5055    EXRETURN ;
5056 }
5057