/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ #include "bbox.h" /*------------------------------------------------------------------------- create a new MCW_bbox: parent = parent Widget num_but = number of buttons (from 1 to MCW_MAX_BB) label_but = array of strings of button labels bb_type = MCW_BB_check -> check box (any may be on) MCW_BB_radio_one -> radio box, exactly one will be on MCW_BB_radio_zero -> radio box, zero or one will be on bb_frame = MCW_BB_noframe -> no frame around box = MCW_BB_frame -> put frame around box cb = Callback procedure for Disarm (NULL for none) cb_data = data to pass to Callback procedure (NULL for none) ---------------------------------------------------------------------------*/ MCW_bbox * new_MCW_bbox( Widget parent , int num_but , char * label_but[] , int bb_type , int bb_frame , XtCallbackProc cb , XtPointer cb_data ) { MCW_bbox * bb ; int ib , initial_value ; Widget rc_parent ; Arg wa[30] ; int na ; Pixel fg_pix ; ENTRY("new_MCW_bbox") ; if( num_but <= 0 || num_but >= 32 ){ fprintf(stderr,"\n*** illegal new_MCW_bbox has %d buttons\n",num_but) ; EXIT(1) ; } bb = (MCW_bbox *) XtMalloc( sizeof(MCW_bbox) ) ; bb->nbut = num_but ; initial_value = 0 ; /***--- create Frame, if desired ---***/ switch( bb_frame ){ case MCW_BB_frame: rc_parent = bb->wtop = bb->wframe = XtVaCreateManagedWidget( "frame" , xmFrameWidgetClass , parent , XmNshadowType , XmSHADOW_ETCHED_IN , XmNinitialResourcesPersistent , False , NULL ) ; break ; case MCW_BB_noframe: default: rc_parent = parent ; bb->wframe = NULL ; break ; } /***--- create RowColumn to hold the buttons ---***/ #define MAX_PER_COL 8 na = 0 ; #ifdef BBOX_COL XtSetArg( wa[na] , XmNpacking , XmPACK_COLUMN ) ; na++ ; XtSetArg( wa[na] , XmNnumColumns , 1 + (num_but-1)/MAX_PER_COL ) ; na++ ; #else XtSetArg( wa[na] , XmNpacking , XmPACK_TIGHT ) ; na++ ; #endif XtSetArg( wa[na] , XmNmarginHeight , 0 ) ; na++ ; /* squash things in */ XtSetArg( wa[na] , XmNmarginWidth , 0 ) ; na++ ; XtSetArg( wa[na] , XmNspacing , 1 ) ; na++ ; XtSetArg( wa[na] , XmNinitialResourcesPersistent , False ) ; na++ ; if( bb_type == MCW_BB_radio_zero || bb_type == MCW_BB_radio_one ){ XtSetArg( wa[na] , XmNradioBehavior , True ) ; na++ ; if( bb_type == MCW_BB_radio_one ){ initial_value = 1 ; XtSetArg( wa[na] , XmNradioAlwaysOne , True ) ; na++ ; } else { XtSetArg( wa[na] , XmNradioAlwaysOne , False ) ; na++ ; } } bb->wrowcol = XtCreateWidget( "dialog" , xmRowColumnWidgetClass , rc_parent , wa , na ) ; if( bb->wframe == NULL ) bb->wtop = bb->wrowcol ; /* topmost widget */ XtVaGetValues( bb->wtop , XmNforeground , &fg_pix , NULL ) ; /***--- create the buttons ---***/ for( ib=0 ; ib < num_but ; ib++ ){ bb->wbut[ib] = XtVaCreateManagedWidget( "dialog" , xmToggleButtonWidgetClass , bb->wrowcol , LABEL_ARG(label_but[ib]) , XmNmarginHeight , 0 , XmNmarginWidth , 0 , XmNselectColor , fg_pix , /* 04 Nov 1996 */ XmNrecomputeSize , False , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( cb != NULL ) XtAddCallback( bb->wbut[ib] , XmNdisarmCallback , cb , cb_data ) ; } for( ib=num_but ; ib < MCW_MAX_BB ; ib++ ) bb->wbut[ib] = NULL ; MCW_set_bbox( bb , initial_value ) ; XtManageChild( bb->wrowcol ) ; bb->parent = bb->aux = NULL ; RETURN(bb) ; } /*------------------------------------------------------------------------*/ void MCW_bbox_hints( MCW_bbox * bb , int nh , char ** hh ) { int ib ; if( bb == NULL || nh == 0 || hh == NULL ) return ; if( nh > bb->nbut ) nh = bb->nbut ; for( ib=0 ; ib < nh ; ib++ ) MCW_register_hint( bb->wbut[ib] , hh[ib] ) ; return ; } /*------------------------------------------------------------------------*/ void MCW_set_bbox( MCW_bbox *bb , int val ) { int ib ; Boolean nset , oset ; ENTRY("MCW_set_bbox") ; if( bb == NULL ) EXRETURN ; /* 01 Feb 2000 */ bb->value = val ; for( ib=0 ; ib < bb->nbut ; ib++ ){ nset = ( val & (1<wbut[ib] ) ; if( nset != oset ){ XmToggleButtonSetState( bb->wbut[ib] , nset , False ) ; XmUpdateDisplay( bb->wbut[ib] ) ; } } EXRETURN ; } /*------------------------------------------------------------------------*/ int MCW_val_bbox( MCW_bbox *bb ) { int ib , val ; Boolean set ; if( bb == NULL ) return 0 ; /* 01 Feb 2000 */ val = 0 ; for( ib=0 ; ib < bb->nbut ; ib++ ){ set = XmToggleButtonGetState( bb->wbut[ib] ) ; if( set ) val |= (1<value = val ; return val ; } /*---------------------------------------------------------------------- Create a new MCW_arrowval: [label] [v][^] [value] parent = parent Widget label = string to put to left of arrows (NULL means none) direc = MCW_AV_downup for down and up arrows MCW_AV_leftright for left and right arrows MCW_AV_optmenu for option menu (completely different style!) minval = smallest value allowed } value is like in Scales: maxval = largest value allowed } an integer inival = initial value } textype = MCW_AV_notext to turn display of value off MCW_AV_editext to allow user to edit the text MCW_AV_noactext like above, but no "activation" when the cursor leaves the window MCW_AV_readtext to make the text display readonly decim = # of decimals to shift to left for display of value (like Scales) delta_value = pointer to a function that will be called when the value changes (due to arrows or text edit); not used if NULL delta_data = pointer to data to be passed to delta_value; delta_value( av , delta_data ) ; where av is a pointer to the MCW_arrowval that changed. (N.B.: the old value is available as av->old_ival or av->old_fval) text_proc = pointer to a function that returns the text to display in the value window; if non-NULL, then textype is forced to be MCW_AV_readtext; the routine is called by string = text_proc( av , text_data ) text_data = pointer to data to be passed to text_proc ---------------------------------------------------------------------------*/ MCW_arrowval * 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 ) { MCW_arrowval * av = NULL ; int asizx = 20 , asizy = 15 ; /* arrow sizes */ ENTRY("new_MCW_arrowval") ; /** July 1996: optmenu capability as a dropin for arrowval **/ if( direc == MCW_AV_optmenu ){ av = new_MCW_optmenu( parent , label , minval,maxval,inival , decim , delta_value , delta_data , text_proc , text_data ) ; RETURN(av) ; } av = myXtNew( MCW_arrowval ) ; av->wrowcol = XtVaCreateWidget( "dialog" , xmRowColumnWidgetClass , parent , XmNpacking , XmPACK_TIGHT , XmNorientation , XmHORIZONTAL , XmNmarginHeight , 0 , XmNmarginWidth , 0 , XmNspacing , 0 , #if 0 XmNresizeHeight , False , XmNresizeWidth , False , #endif XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; if( label != NULL && strlen(label) > 0 ){ XmString xstr = XmStringCreateLtoR( label , XmFONTLIST_DEFAULT_TAG ); XmFontList xflist ; av->wlabel = XtVaCreateManagedWidget( "dialog" , xmLabelWidgetClass , av->wrowcol , XmNlabelString , xstr , XmNrecomputeSize , False , XmNmarginWidth , 0 , XmNinitialResourcesPersistent , False , NULL ) ; XtVaGetValues( av->wlabel , XmNfontList , &xflist , NULL ) ; asizy = XmStringHeight( xflist , xstr ) ; XmStringFree( xstr ) ; } else { av->wlabel = NULL ; } if( asizx < asizy ) asizx = asizy ; else asizy = asizx ; av->wdown = XtVaCreateManagedWidget( "arrow" , xmArrowButtonWidgetClass , av->wrowcol , XmNarrowDirection , (direc==MCW_AV_leftright) ? XmARROW_LEFT : XmARROW_DOWN , XmNheight , asizy , XmNwidth , asizx , XmNborderWidth , 0 , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; av->wup = XtVaCreateManagedWidget( "arrow" , xmArrowButtonWidgetClass , av->wrowcol , XmNarrowDirection , (direc==MCW_AV_leftright) ? XmARROW_RIGHT : XmARROW_UP , XmNheight , asizy , XmNwidth , asizx , XmNborderWidth , 0 , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; XtAddCallback( av->wdown , XmNarmCallback , AV_press_CB , av ) ; XtAddCallback( av->wdown , XmNdisarmCallback , AV_press_CB , av ) ; XtAddCallback( av->wup , XmNarmCallback , AV_press_CB , av ) ; XtAddCallback( av->wup , XmNdisarmCallback , AV_press_CB , av ) ; if( text_proc != NULL && textype != MCW_AV_notext ) textype = MCW_AV_readtext ; switch( textype ){ default: case MCW_AV_notext: av->wtext = NULL ; av->text_CB = NULL ; av->text_data = NULL ; break ; /* Note hardwire of 9 columns of text, here and in AV_fval_to_char; this CANNOT be changed just by changing AV_NCOL below, you must also edit the sprintf formats in AV_fval_to_char. If text_proc is not NULL, then av->wtext could have its dimensions changed later to handle the user supplied string. My point above is that the default text_proc is hardwired to 9 characters wide. */ #ifndef AV_NCOL #define AV_NCOL 9 #endif case MCW_AV_readtext: av->wtext = XtVaCreateManagedWidget( "dialog" , TEXT_CLASS , av->wrowcol , XmNcolumns , AV_NCOL , XmNeditable , False , XmNmaxLength , AV_NCOL , XmNresizeWidth , False , XmNshadowThickness , 0 , #if 0 XmNsensitive , False , /* looks bad */ #endif XmNmarginHeight , 1 , XmNmarginWidth , 1 , XmNcursorPositionVisible , False , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; av->text_CB = (text_proc != NULL ) ? (text_proc) : (AV_default_text_CB) ; av->text_data = text_data ; break ; case MCW_AV_noactext: /* noactext added 08 Feb 1999 */ case MCW_AV_editext:{ Widget wf ; int maxlen ; if( textype == MCW_AV_noactext ){ wf = XtVaCreateWidget( "dialog" , xmFrameWidgetClass , av->wrowcol , XmNshadowType , XmSHADOW_OUT , XmNshadowThickness , 1 , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; maxlen = AV_MAXLEN ; } else { wf = av->wrowcol ; maxlen = AV_NCOL ; } av->wtext = XtVaCreateManagedWidget( "dialog" , TEXT_CLASS , wf , XmNcolumns , AV_NCOL , XmNeditable , True , XmNmaxLength , maxlen , XmNresizeWidth , False , XmNmarginHeight , 1 , XmNmarginWidth , 1 , XmNcursorPositionVisible , True , XmNblinkRate , 0 , XmNautoShowCursorPosition , True , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; if( textype == MCW_AV_noactext ) XtManageChild(wf) ; if( textype == MCW_AV_editext ){ XtAddCallback( av->wtext , XmNactivateCallback , AV_textact_CB , av ) ; /* return key */ XtAddCallback( av->wtext , XmNlosingFocusCallback , AV_textact_CB , av ) ; /* tab key */ XtInsertEventHandler( av->wtext , /* notify when */ LeaveWindowMask , /* pointer leaves */ FALSE , /* this window */ AV_leave_EV , (XtPointer) av , XtListTail ) ; /* last in queue */ } av->text_CB = AV_default_text_CB ; av->text_data = NULL ; } break ; } XtManageChild( av->wrowcol ) ; if( minval < maxval ){ av->fmin = av->imin = minval ; AV_SHIFT_VAL(decim,av->fmin) ; av->fmax = av->imax = maxval ; AV_SHIFT_VAL(decim,av->fmax) ; } else { av->fmin = av->imin = -9999999 ; AV_SHIFT_VAL(decim,av->fmin) ; av->fmax = av->imax = 9999999 ; AV_SHIFT_VAL(decim,av->fmax) ; } av->decimals = decim ; av->timer_id = 0 ; av->fastdelay = MCW_AV_shortdelay ; /* default delay on 2nd call */ av->fval = av->ival = inival ; AV_SHIFT_VAL(decim,av->fval) ; av->sval = av->old_sval = NULL ; /* string values */ av->block_assign_actions = 0 ; /* don't block these actions */ av->wmenu = NULL ; /* signal that this is NOT an optmenu */ AV_assign_ival( av , inival ) ; av->dval_CB = delta_value ; av->dval_data = delta_data ; av->allow_wrap = 0 ; av->parent = av->aux = NULL ; av->fstep = 0.0 ; /* 16 Feb 1999 */ RETURN(av) ; } /*-----------------------------------------------------------------------*/ int AV_colsize() /* 11 Dec 2001 */ { int cc=20 ; char *ee ; ee = getenv("AFNI_MENU_COLSIZE") ; if( ee != NULL ){ cc = (int) strtol(ee,NULL,10) ; if( cc < 9 ) cc = 10 ; } return cc ; } /*----------------------------------------------------------------------- This can be used as a "drop in" replacement for a arrowval with a small fixed number of elements. The textype argument is missing because the only one that makes sense is MCW_AV_readtext (readonly text as button labels). The direc argument is missing because that choice has already been made. -------------------------------------------------------------------------*/ #define COLSIZE AV_colsize() /* 11 Dec 2001: redefined from a constant */ static void optmenu_EV( Widget,XtPointer,XEvent *,Boolean *) ; /* prototype */ static volatile int allow_optmenu_EV = 1 ; void allow_MCW_optmenu_popup( int ii ){ allow_optmenu_EV = ii ; } #undef USE_FIXUP #ifdef USE_FIXUP static void optmenu_EV_fixup( Widget ww ) ; #endif MCW_arrowval * 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 ) { MCW_arrowval * av = myXtNew( MCW_arrowval ) ; Widget wmenu , wbut ; Arg args[5] ; int nargs , ival ; XmString xstr ; char * butlabel , * blab ; ENTRY("new_MCW_optmenu") ; /** create the menu window **/ av->wmenu = wmenu = XmCreatePulldownMenu( parent , "menu" , NULL , 0 ) ; VISIBILIZE_WHEN_MAPPED(wmenu) ; /** create the button that pops down the menu **/ nargs = 0 ; XtSetArg( args[0] , XmNsubMenuId , wmenu ) ; nargs++ ; if( label == NULL ) label = " " ; /* 24 Sep 2001 */ xstr = XmStringCreateLtoR( label , XmFONTLIST_DEFAULT_TAG ) ; XtSetArg( args[1] , XmNlabelString , xstr ) ; nargs++ ; av->wrowcol = XmCreateOptionMenu( parent , "dialog" , args , nargs ) ; XmStringFree(xstr) ; XtVaSetValues( av->wrowcol , XmNmarginWidth , 0 , XmNmarginHeight , 0 , XmNspacing , 2 , NULL ) ; av->wlabel = XmOptionLabelGadget (av->wrowcol) ; av->wdown = XmOptionButtonGadget(av->wrowcol) ; av->wup = NULL ; av->wtext = NULL ; /* signal that this is NOT really an arrowval */ XtVaSetValues( av->wlabel , /* label next to menu button */ XmNmarginWidth , 0 , XmNmarginHeight , 0 , XmNmarginBottom , 0 , XmNmarginTop , 0 , XmNmarginRight , 0 , XmNmarginLeft , 0 , NULL ) ; if( label == NULL || strlen(label) == 0 ){ XtVaSetValues( av->wlabel , XmNwidth , 0 , NULL ) ; XtVaSetValues( av->wrowcol , XmNspacing , 2 , NULL ) ; } XtVaSetValues( av->wdown , /* menu button */ XmNmarginWidth , 0 , XmNmarginHeight , 0 , XmNmarginBottom , 0 , XmNmarginTop , 0 , XmNmarginRight , 0 , XmNmarginLeft , 0 , XmNhighlightThickness , 0 , NULL ) ; av->text_CB = (text_proc != NULL ) ? (text_proc) : (AV_default_text_CB) ; av->text_data = text_data ; av->decimals = decim ; av->fmin = av->imin = minval ; AV_SHIFT_VAL(decim,av->fmin) ; av->fmax = av->imax = maxval ; AV_SHIFT_VAL(decim,av->fmax) ; av->sval = av->old_sval = NULL ; av->block_assign_actions = 1 ; /* temporarily block these actions */ /** create the buttons on the menu window **/ for( ival=minval ; ival <= maxval ; ival++ ){ AV_assign_ival( av , ival ) ; /* just to create label */ blab = butlabel = XtNewString( av->sval ) ; if( av->text_CB==AV_default_text_CB && butlabel[0]==' ' && minval >= 0 ){ blab += 1 ; /* deal with leading blanks in default routine */ } xstr = XmStringCreateLtoR( blab , XmFONTLIST_DEFAULT_TAG ) ; wbut = XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , wmenu , XmNlabelString , xstr , XmNmarginWidth , 0 , XmNmarginHeight , 0 , XmNmarginBottom , 0 , XmNmarginTop , 0 , XmNmarginRight , 0 , XmNmarginLeft , 0 , XmNuserData , (XtPointer) ival , /* Who am I? */ XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XmStringFree(xstr) ; myXtFree(butlabel) ; XtAddCallback( wbut , XmNactivateCallback , AVOPT_press_CB , av ) ; if( ival == inival ) XtVaSetValues( av->wrowcol , XmNmenuHistory , wbut , NULL ) ; } XtManageChild( av->wrowcol ) ; av->timer_id = 0 ; /* won't be used for this type of arrowval! */ av->fastdelay = 0 ; av->block_assign_actions = 0 ; /* unblock these actions */ AV_assign_ival( av , inival ) ; /* actual initial assignment */ av->dval_CB = delta_value ; av->dval_data = delta_data ; av->allow_wrap = 0 ; av->parent = av->aux = NULL ; av->fstep = 0.0 ; /* 16 Feb 1999 */ /* 11 Dec 2001: allow user to choose via Button-3 popup */ if( allow_optmenu_EV ){ XtInsertEventHandler( av->wrowcol , /* handle events in optmenu */ ButtonPressMask , /* button presses */ FALSE , /* nonmaskable events? */ optmenu_EV , /* handler */ (XtPointer) av , /* client data */ XtListTail ) ; /* last in queue */ #ifdef USE_FIXUP optmenu_EV_fixup( av->wrowcol ) ; #endif } RETURN(av) ; } /*---------------------------------------------------------------------------- Relabels all the buttons on an optmenu, adding or unmanaging as needed. The label and action callback remain the same. ------------------------------------------------------------------------------*/ void refit_MCW_optmenu( MCW_arrowval * av , int minval , int maxval , int inival , int decim , str_func * text_proc , XtPointer text_data ) { Widget * children , wbut , wmenu ; int num_children , ic , ival ; char * butlabel , * blab ; XmString xstr ; int maxbut ; /* 23 Aug 2003 */ ENTRY("refit_MCW_optmenu") ; /** sanity check **/ if( av == NULL || av->wmenu == NULL ) EXRETURN ; wmenu = av->wmenu ; /** get all the existing children **/ #if 0 XtUnmanageChild( av->wrowcol ) ; XtUnmanageChild( wmenu ) ; #endif XtVaGetValues( wmenu , XmNchildren , &children , XmNnumChildren , &num_children , NULL ) ; /* 23 Aug 2003: replace hard limit of 255 buttons with maxbut from environment variable */ maxbut = AFNI_numenv( "AFNI_MAX_OPTMENU" ) ; if( maxbut <= 0 ) maxbut = 255 ; else if( maxbut < 99 ) maxbut = 99 ; if( maxval > minval+maxbut ) maxval = minval+maxbut ; /* 23 Mar 2003 */ /** reset some internal parameters **/ av->text_CB = (text_proc != NULL ) ? (text_proc) : (AV_default_text_CB) ; av->text_data = text_data ; av->decimals = decim ; av->fmin = av->imin = minval ; AV_SHIFT_VAL(decim,av->fmin) ; av->fmax = av->imax = maxval ; AV_SHIFT_VAL(decim,av->fmax) ; myXtFree(av->sval) ; myXtFree(av->old_sval) ; /* 09 Mar 1999 */ av->block_assign_actions = 1 ; /* temporarily block these actions */ /** create buttons anew **/ for( ival=minval ; ival <= maxval ; ival++ ){ ic = ival - minval ; /* index into widget list */ AV_assign_ival( av , ival ) ; /* just to create label */ blab = butlabel = XtNewString( av->sval ) ; if( av->text_CB==AV_default_text_CB && butlabel[0]==' ' && minval >= 0 ){ blab += 1 ; /* deal with leading blanks in default routine */ } xstr = XmStringCreateLtoR( blab , XmFONTLIST_DEFAULT_TAG ) ; /** re-use old button if possible, otherwise add a new one **/ if( ic < num_children ){ XtPointer user_old ; int ival_old ; XmString xstr_old ; wbut = children[ic] ; XtVaGetValues( wbut , XmNlabelString , &xstr_old , XmNuserData , &user_old , NULL ) ; ival_old = (int) user_old ; if( ival_old != ival || XmStringCompare(xstr_old,xstr) != True ){ XtVaSetValues( wbut , XmNlabelString , xstr , /* change label */ XmNuserData , (XtPointer) ival , /* Who am I? */ NULL ) ; } XmStringFree( xstr_old ) ; XtManageChild( wbut ) ; /* if not now managed */ } else { wbut = XtVaCreateManagedWidget( "dialog" , xmPushButtonWidgetClass , wmenu , XmNlabelString , xstr , XmNmarginWidth , 0 , XmNmarginHeight , 0 , XmNmarginBottom , 0 , XmNmarginTop , 0 , XmNmarginRight , 0 , XmNmarginLeft , 0 , XmNuserData , (XtPointer) ival , /* Who am I? */ XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XtAddCallback( wbut , XmNactivateCallback , AVOPT_press_CB , av ) ; } XmStringFree(xstr) ; myXtFree(butlabel) ; if( ival == inival ) XtVaSetValues( av->wrowcol , XmNmenuHistory , wbut , NULL ) ; } /** Unmanage extra children from an old incarnation **/ ic = maxval-minval+1 ; /* first child after those used above */ if( ic < num_children ) XtUnmanageChildren( children + ic , num_children - ic ) ; /** set number of columns to see **/ AVOPT_columnize( av , 1+(maxval-minval)/COLSIZE ) ; #if 0 XtManageChild( wmenu ) ; XtManageChild( av->wrowcol ) ; #endif #if 0 RWC_XtPopdown( XtParent(wmenu) ) ; /* 28 Apr 1997 */ #endif av->block_assign_actions = 0 ; /* unblock these actions */ AV_assign_ival( av , inival ) ; /* actual initial assignment */ EXRETURN ; } /*-------------------------------------------------------------------------- 11 Dec 2001: Provide a Button 3 list to choose from for an optmenu ----------------------------------------------------------------------------*/ static void optmenu_finalize( Widget w, XtPointer cd, MCW_choose_cbs * cbs ) { MCW_arrowval *av = (MCW_arrowval *) cd ; int ival ; ENTRY("optmenu_finalize") ; if( av == NULL || av->wmenu == NULL ) EXRETURN ; ival = cbs->ival + av->imin ; AV_assign_ival( av , ival ) ; /* call user callback, if present */ if( av->dval_CB != NULL && av->fval != av->old_fval ) #if 0 av->dval_CB( av , av->dval_data ) ; #else AFNI_CALL_VOID_2ARG( av->dval_CB , MCW_arrowval * , av , XtPointer , av->dval_data ) ; #endif EXRETURN ; } /*--------------------------------------------------------------------------*/ /* 15 Mar 2004: fix the cursors on the optmenus with popups */ #ifdef USE_FIXUP static volatile int nwid = 0 ; static volatile Widget *wid = NULL ; /*- called if an optmenu is destroyed, to remove it from the fixup list -*/ static void optmenu_EV_fixup_CB( Widget ww , XtPointer xp, XtPointer cd ) { int ii ; ENTRY("optmenu_EV_fixup_CB") ; for( ii=0 ; ii < nwid ; ii++ ) if( wid[ii] == ww ) wid[ii] = (Widget)NULL ; EXRETURN ; ; } /*- called occasionally to see if anyone can be fixed yet -*/ static volatile XtIntervalId timer_id = (XtIntervalId)0 ; static volatile XtAppContext timer_cx = (XtAppContext)NULL ; static void optmenu_EV_fixup_timer_CB( XtPointer cd , XtIntervalId *id ) { ENTRY("optmenu_EV_fixup_timer_CB") ; optmenu_EV_fixup((Widget)NULL) ; timer_id = XtAppAddTimeOut( timer_cx, 3033, optmenu_EV_fixup_timer_CB, NULL ) ; EXRETURN ; } /*- called with NULL to fix anything on the current list; called with a Widget to put it on the to-be-fixed-up list -*/ static void optmenu_EV_fixup( Widget ww ) /* 15 Mar 2004 - RWCox */ { int ii , jj ; Widget *qwid ; ENTRY("optmenu_EV_fixup") ; if( ww == (Widget)NULL ){ /* try to fix what's on the list */ if( nwid == 0 ) EXRETURN ; /* that was easy */ if(PRINT_TRACING){ char str[256]; sprintf(str,"scanning %d widgets for fixing",nwid); STATUS(str); } for( ii=jj=0 ; ii < nwid ; ii++ ){ if( wid[ii] != (Widget)NULL && XtIsRealized(wid[ii]) && XtIsManaged(wid[ii]) && MCW_widget_visible(wid[ii]) ){ if(PRINT_TRACING){ char str[256]; sprintf(str," about to fix ii=%d",ii); STATUS(str); } POPUP_cursorize(wid[ii]) ; XtRemoveCallback( wid[ii], XmNdestroyCallback, optmenu_EV_fixup_CB, NULL ) ; wid[ii] = NULL ; jj++ ; if(PRINT_TRACING){ char str[256]; sprintf(str," #%d cursor fixed",ii); STATUS(str); } } else if(PRINT_TRACING){ char str[256]; sprintf(str," #%d not fixable",ii); STATUS(str); } } if( jj == 0 ){ STATUS("nothing to fix"); EXRETURN; } if( jj >= nwid ){ STATUS("fixed them all"); free(wid); wid = NULL; nwid = 0; EXRETURN; } qwid = (Widget *) calloc( nwid , sizeof(Widget) ) ; for( ii=jj=0 ; ii < nwid ; ii++ ) if( wid[ii] != (Widget)NULL ) qwid[jj++] = wid[ii] ; nwid = jj ; for( ii=0 ; ii < nwid ; ii++ ) wid[ii] = qwid[ii] ; free(qwid) ; if(PRINT_TRACING){ char str[256]; sprintf(str," %d left to fix later",nwid); STATUS(str); } } else { /* add to the list */ wid = (Widget *)realloc( (void *)wid , sizeof(Widget)*(nwid+1) ) ; wid[nwid++] = ww ; XtAddCallback( ww, XmNdestroyCallback, optmenu_EV_fixup_CB, NULL ) ; if( timer_cx == (XtAppContext)NULL ){ STATUS(" starting first timer callback") ; timer_cx = XtWidgetToApplicationContext(ww) ; timer_id = XtAppAddTimeOut( timer_cx, 5055, optmenu_EV_fixup_timer_CB, NULL ) ; } if(PRINT_TRACING){ char str[256]; sprintf(str," now have %d to fix",nwid); STATUS(str); } } EXRETURN ; } #endif /* USE_FIXUP */ /*--------------------------------------------------------------------------*/ static void optmenu_EV( Widget w , XtPointer cd , XEvent *ev , Boolean *continue_to_dispatch ) { MCW_arrowval *av = (MCW_arrowval *) cd ; int ic , ival , sval , nstr ; XButtonEvent * bev = (XButtonEvent *) ev ; Dimension lw ; static char **strlist=NULL ; static int nstrlist=0 ; /* 06 Aug 2002 */ char *slab=NULL ; XmString xstr ; /*-- Attempt to fix a Motif problem with Button 2 when the optmenu is itself in a popup menu. The pointer grab is never released, so the X server is effectively frozen forever (or until the afni process is SIGTERM-ed). Here, if we see Button 2, then we manually ungrab the pointer. This has the side-effect of popping down the popup menu. If the optmenu is NOT in a popup menu, it has no side effect. --*/ #ifdef USE_FIXUP optmenu_EV_fixup(NULL) ; #endif if( bev->button == Button2 ){ XUngrabPointer( bev->display , CurrentTime ) ; return ; } /*-- start of actual work --*/ ENTRY("optmenu_EV") ; /** sanity checks **/ if( w == NULL || av == NULL || av->wmenu == NULL ) EXRETURN ; if( bev->button != Button3 ) EXRETURN ; XtVaGetValues( av->wlabel , XmNwidth,&lw , NULL ) ; if( bev->x > lw ) EXRETURN ; /** get ready to popup a new list chooser **/ POPDOWN_strlist_chooser ; av->block_assign_actions = 1 ; /* temporarily block actions */ sval = av->ival ; /* 06 Aug 2002: free old strings, if any */ for( ic=0 ; ic < nstrlist ; ic++ ) free(strlist[ic]) ; /** make a list of strings **/ nstrlist = nstr = av->imax - av->imin + 1 ; strlist = (char **) realloc( strlist , sizeof(char *)*nstr ) ; for( ival=av->imin ; ival <= av->imax ; ival++ ){ AV_assign_ival( av , ival ) ; /* just to create label */ ic = ival - av->imin ; /* index into widget list */ strlist[ic] = strdup( av->sval ) ; /* copy label */ } AV_assign_ival( av , sval ) ; av->block_assign_actions = 0 ; /* back to normal */ /** actually choose something **/ XtVaGetValues( av->wlabel , XmNlabelString , &xstr , NULL ) ; XmStringGetLtoR( xstr , XmFONTLIST_DEFAULT_TAG , &slab ) ; XmStringFree(xstr) ; MCW_choose_strlist( w , slab , nstr , sval - av->imin , strlist , optmenu_finalize , cd ) ; EXRETURN ; } /*-------------------------------------------------------------------------- Create a colormenu -- an optmenu with buttons colorized ----------------------------------------------------------------------------*/ MCW_arrowval * 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 ) { MCW_arrowval * av ; Widget * children ; int num_children , ic , icol ; ENTRY("new_MCW_colormenu") ; av = new_MCW_optmenu( parent , label , min_col , max_col , ini_col , 0 , delta_value , delta_data , MCW_DC_ovcolor_text , (XtPointer) dc ) ; XtVaGetValues( av->wmenu , XmNchildren , &children , XmNnumChildren , &num_children , NULL ) ; for( ic=0 ; ic < num_children ; ic++ ){ icol = min_col + ic ; if( icol > 0 ) MCW_set_widget_bg( children[ic] , 0 , dc->ovc->pix_ov[icol] ) ; else MCW_set_widget_bg( children[ic] , "gray40" , 0 ) ; } if( max_col > COLSIZE ) AVOPT_columnize( av , 1+(max_col-1)/COLSIZE ) ; RETURN(av) ; } char * MCW_av_substring_CB( MCW_arrowval * av , XtPointer cd ) { char ** str = (char **) cd ; return str[av->ival] ; } /*-----------------------------------------------------------------------*/ void AVOPT_press_CB( Widget wbut, XtPointer client_data, XtPointer call_data ) { MCW_arrowval * av = (MCW_arrowval *) client_data ; int newval ; XtPointer xval ; XtVaGetValues( wbut , XmNuserData , &xval , NULL ) ; newval = (int) xval ; AV_assign_ival( av , newval ) ; /* assign */ /* call user callback, if present */ if( av->dval_CB != NULL && av->fval != av->old_fval ) #if 0 av->dval_CB( av , av->dval_data ) ; #else AFNI_CALL_VOID_2ARG( av->dval_CB , MCW_arrowval * , av , XtPointer , av->dval_data ) ; #endif return ; } /*-----------------------------------------------------------------------*/ void AV_press_CB( Widget warrow, XtPointer client_data, XtPointer call_data ) { MCW_arrowval * av = (MCW_arrowval *) client_data ; XmArrowButtonCallbackStruct * cbs = (XmArrowButtonCallbackStruct *) call_data ; XtIntervalId fake_id = 0 ; /* release of button */ switch( cbs->reason ){ default: case XmCR_DISARM: if( av->timer_id != 0 ) XtRemoveTimeOut( av->timer_id ) ; /* stop */ av->timer_id = 0 ; break ; case XmCR_ARM: if( warrow == av->wup ) av->incr = 1 ; /* go up */ else if( warrow == av->wdown ) av->incr = -1 ; /* down */ else return ; if( cbs->event->type == ButtonPress ) av->delay = MCW_AV_longdelay ; else av->delay = 0 ; av->xev = *(cbs->event) ; /* copy event for user's info */ AV_timer_CB( av , &fake_id ) ; /* do the work */ } return; } /*------------------------------------------------------------------------*/ void AV_timer_CB( XtPointer client_data , XtIntervalId * id ) { MCW_arrowval * av = (MCW_arrowval *) client_data ; int newval ; double sval ; if( av->fstep == 0.0 ){ /* 16 Feb 1999: this is the old way */ sval = av->fval ; AV_SHIFT_VAL( -av->decimals , sval ) ; if( av->incr < 0 ){ newval = (int) floor( 0.99 + sval + av->incr ) ; } else { newval = (int) ceil(-0.99 + sval + av->incr ) ; } if( newval > av->imax && av->allow_wrap ){ /* out of range? wrap. */ newval = av->imin ; } else if( newval < av->imin && av->allow_wrap ){ newval = av->imax ; } else if( newval > av->imax || newval < av->imin ){ /* out of range? stop. */ av->timer_id = 0 ; return ; } AV_assign_ival( av , newval ) ; /* assign */ } else { /* 16 Feb 1999: this is the new way, if user sets fstep */ if( av->incr > 0 ) sval = av->fval + av->fstep ; else sval = av->fval - av->fstep ; if( sval > av->fmax || sval < av->fmin ){ /* out of range? stop. */ av->timer_id = 0 ; return ; } AV_assign_fval( av , sval ) ; } /* call user callback, if present */ if( av->dval_CB != NULL && av->fval != av->old_fval ) #if 0 av->dval_CB( av , av->dval_data ) ; #else AFNI_CALL_VOID_2ARG( av->dval_CB , MCW_arrowval * , av , XtPointer , av->dval_data ) ; #endif /* delay and then call again, if desired */ if( av->delay <= 0 ) return ; av->timer_id = XtAppAddTimeOut( XtWidgetToApplicationContext( av->wrowcol ) , av->delay , AV_timer_CB , av ) ; if( av->delay == MCW_AV_longdelay ) if( av->fastdelay > 0 ) av->delay = av->fastdelay ; else av->delay = MCW_AV_shortdelay ; return ; } /*------------------------------------------------------------------------*/ void AV_assign_ival( MCW_arrowval * av , int nval ) { int newival = nval ; char * cval ; ENTRY("AV_assign_ival") ; if( av == NULL ) EXRETURN ; /* 01 Feb 2000 */ if( newival > av->imax ) newival = av->imax ; if( newival < av->imin ) newival = av->imin ; /* assign */ av->old_ival = av->ival ; av->old_fval = av->fval ; av->fval = av->ival = newival ; /* adjust decimal point */ AV_SHIFT_VAL( av->decimals , av->fval ) ; /* change text display, if present */ if( av->text_CB != NULL ){ #if 0 cval = av->text_CB( av , av->text_data ) ; /* save */ #else AFNI_CALL_VALU_2ARG( av->text_CB , char * , cval , MCW_arrowval * , av , XtPointer , av->text_data ) ; #endif myXtFree( av->old_sval ) ; av->old_sval = av->sval ; /* string */ av->sval = XtNewString( cval ) ; /* values */ if( av->wtext != NULL && ! av->block_assign_actions ) TEXT_SET( av->wtext , cval ) ; } /* if an option menu, change display */ if( av->wmenu != NULL && ! av->block_assign_actions ){ Widget * children , wbut ; int num_children , ic ; XtVaGetValues( av->wmenu , XmNchildren , &children , XmNnumChildren , &num_children , NULL ) ; XtVaGetValues( av->wrowcol , XmNmenuHistory , &wbut , NULL ) ; ic = newival - av->imin ; if( ic >= 0 && ic < num_children && wbut != children[ic] ) XtVaSetValues( av->wrowcol , XmNmenuHistory , children[ic] , NULL ) ; } EXRETURN ; } /*------------------------------------------------------------------------- format a floating value for output ---------------------------------------------------------------------------*/ char * AV_default_text_CB( MCW_arrowval * av , XtPointer junk ) { static char buf[32] ; if( av == NULL ) buf[0] = '\0' ; else AV_fval_to_char( av->fval , buf ) ; return &(buf[0]) ; } /*------------------------------------------------------------------------*/ void AV_fval_to_char( float qval , char * buf ) { float aval = fabs(qval) ; int lv ; char lbuf[16] ; int il ; /* special case if the value is an integer */ lv = (fabs(qval) < 9999999.0) ? (int)qval : 10000001 ; if( qval == lv && abs(lv) < 10000000 ){ if( lv >= 0 ) sprintf( buf , " %d" , lv ) ; else sprintf( buf , "%d" , lv ) ; return ; } /* macro to strip trailing zeros from output */ #define BSTRIP \ for( il=AV_NCOL-1 ; il>1 && lbuf[il]=='0' ; il-- ) lbuf[il] = '\0' /* noninteger: choose floating format based on magnitude */ lv = (int) (10.0001 + log10(aval)) ; switch( lv ){ default: if( qval > 0.0 ) sprintf( lbuf , "%9.3e" , qval ) ; else sprintf( lbuf , "%9.2e" , qval ) ; break ; case 6: /* 0.0001-0.001 */ case 7: /* 0.001 -0.01 */ case 8: /* 0.01 -0.1 */ case 9: /* 0.1 -1 */ case 10: /* 1 -9.99 */ sprintf( lbuf , "%9.6f" , qval ) ; BSTRIP ; break ; case 11: /* 10-99.9 */ sprintf( lbuf , "%9.5f" , qval ) ; BSTRIP ; break ; case 12: /* 100-999.9 */ sprintf( lbuf , "%9.4f" , qval ) ; BSTRIP ; break ; case 13: /* 1000-9999.9 */ sprintf( lbuf , "%9.3f" , qval ) ; BSTRIP ; break ; case 14: /* 10000-99999.9 */ sprintf( lbuf , "%9.2f" , qval ) ; BSTRIP ; break ; case 15: /* 100000-999999.9 */ sprintf( lbuf , "%9.1f" , qval ) ; BSTRIP ; break ; case 16: /* 1000000-9999999.9 */ sprintf( lbuf , "%9.0f" , qval ) ; break ; } lv = strlen(lbuf) ; /* length of result at this stage */ if( lv <= AV_NCOL ){ /* length OK */ strcpy(buf,lbuf) ; } else { /* too long (should not occur!) */ sprintf( lbuf , "%%%d.%dg" , AV_NCOL , AV_NCOL-7 ) ; sprintf( buf , lbuf , qval ) ; } return ; } /*------------------------------------------------------------------------*/ char * AV_format_fval( float fval ) { static char buf[32] ; AV_fval_to_char( fval , buf ) ; return buf ; } /*------------------------------------------------------------------------*/ char * AV_uformat_fval( float fval ) { static char buf[32] ; AV_fval_to_char( fval , buf ) ; if( buf[0] == ' ' ) return (buf+1) ; return buf ; } /*------------------------------------------------------------------------*/ void AV_assign_fval( MCW_arrowval * av , float qval ) { double newfval = qval ; char * cval ; if( av == NULL ) return ; /* 01 Feb 2000 */ if( newfval > av->fmax ) newfval = av->fmax ; if( newfval < av->fmin ) newfval = av->fmin ; /* assign */ av->old_ival = av->ival ; av->old_fval = av->fval ; av->fval = newfval ; /* adjust decimal point */ AV_SHIFT_VAL( -av->decimals , newfval ) ; av->ival = (int) floor(newfval) ; /* change text display, if present */ if( av->text_CB != NULL ){ #if 0 cval = av->text_CB( av , av->text_data ) ; /* save */ #else AFNI_CALL_VALU_2ARG( av->text_CB , char * , cval , MCW_arrowval * , av , XtPointer , av->text_data ) ; #endif myXtFree( av->old_sval ) ; av->old_sval = av->sval ; /* string */ av->sval = XtNewString( cval ) ; /* values */ if( av->wtext != NULL && ! av->block_assign_actions ) TEXT_SET( av->wtext , cval ) ; } return ; } /*----------------------------------------------------------------------*/ void AV_leave_EV( Widget w , XtPointer client_data , XEvent * ev , Boolean * continue_to_dispatch ) { MCW_arrowval * av = (MCW_arrowval *) client_data ; XLeaveWindowEvent * lev = (XLeaveWindowEvent *) ev ; XmAnyCallbackStruct cbs ; if( lev->type != LeaveNotify || av == NULL ) return ; cbs.reason = XmCR_ACTIVATE ; /* simulate a return press */ AV_textact_CB( av->wtext , (XtPointer) av , &cbs ) ; } /*----------------------------------------------------------------------*/ void AV_textact_CB( Widget wtex, XtPointer client_data, XtPointer call_data ) { MCW_arrowval * av = (MCW_arrowval *) client_data ; XmAnyCallbackStruct * cbs = (XmAnyCallbackStruct *) call_data ; float sval ; int ii ; char * str ; ENTRY("AV_textact_CB") ; if( (cbs->reason != XmCR_ACTIVATE && cbs->reason != XmCR_LOSING_FOCUS ) || wtex != av->wtext ){ fprintf(stderr,"\n*** Illegal call to AV_textact_CB ***\n") ; EXRETURN ; } str = TEXT_GET( wtex ) ; /* get the new text */ /* check if new text is any different from last value */ if( av->sval != NULL && strcmp( av->sval , str ) == 0 ){ myXtFree(str) ; EXRETURN ; } MCW_invert_widget( wtex ) ; /* start flash */ ii = sscanf( str , "%f" , &sval ) ; /* convert to float in sval */ if( ii == 0 ) sval = av->fval ; /* bad float conversion */ AV_assign_fval( av , sval ) ; /* will alter ival,fval,sval in av */ if( av->dval_CB != NULL && av->fval != av->old_fval ) /* value changed */ #if 0 av->dval_CB( av , av->dval_data ) ; #else AFNI_CALL_VOID_2ARG( av->dval_CB , MCW_arrowval * , av , XtPointer , av->dval_data ) ; #endif myXtFree(str) ; /* give it back */ MCW_invert_widget( wtex ) ; /* end flash */ EXRETURN ; } /*---------------------------------------------------------------------- NULL out the pointer to a popup widget when the widget is destroyed ------------------------------------------------------------------------*/ void MCW_destroy_chooser_CB( Widget wpop , XtPointer client_data, XtPointer call_data ) { Widget *wpointer = (Widget *) client_data ; ENTRY("MCW_destroy_chooser_CB") ; *wpointer = NULL ; EXRETURN ; } void MCW_kill_chooser_CB( Widget w , XtPointer client_data, XtPointer call_data ) { Widget wpop = (Widget) client_data ; ENTRY("MCW_kill_chooser_CB") ; XtDestroyWidget(wpop) ; EXRETURN ; } /*-----------------------------------------------------------------------*/ #undef RECOLOR_OPTMENU char * MCW_DC_ovcolor_text( MCW_arrowval * av , MCW_DC * dc ) { int ii = av->ival ; Widget wfix ; if( ii < 0 ) ii = 0 ; else if( ii > dc->ovc->ncol_ov - 1 ) ii = dc->ovc->ncol_ov - 1 ; wfix = av->wtext ; if( wfix != NULL ){ if( ii > 0 ) MCW_set_widget_bg( wfix , 0 , dc->ovc->pix_ov[ii] ) ; else MCW_set_widget_bg( wfix , "gray40" , 0 ) ; } #ifdef RECOLOR_OPTMENU /** make the option menu cascade button gadget be outlined in color **/ else if( av->wmenu != NULL && XtIsRealized(av->wrowcol) ){ Pixel ptop , pbot ; wfix = av->wrowcol ; if( ii > 0 ) pbot = ptop = dc->ovc->pix_ov[ii] ; else XtVaGetValues( XtParent(wfix) , XmNtopShadowColor , &ptop , XmNbottomShadowColor , &pbot , NULL ) ; XtVaSetValues( wfix , XmNtopShadowColor , ptop , XmNbottomShadowColor , pbot , NULL ) ; } #endif return dc->ovc->label_ov[ii] ; } /*------------------------------------------------------------------------ Get a table index for a DC overlay color: pops up a shell to let the user make the selection wpar = parent widget (where to popup) dc = display context to choose colors from ovc_init = initial overlay color index func = routine to call when a selection is made: void func( Widget wpar,XtPointer func_data,MCW_choose_cbs * cbs ) func_data = data to pass to func The "ival" stored in the MCW_choose_cbs will be the index into the DC overlay color table. The pixel value is thus dc->ovc->pix_ov[cbs->ival]. The color name is dc->ovc->name_ov[cbs->ival]. Etc. Note that cbs->ival = 0 means that the user choose the "None" color. This routine is coded in such a way that only one color chooser will be active at a time (per application). This is a deliberate choice. --------------------------------------------------------------------------*/ #define OVC_quit_label "Quit" #define OVC_apply_label "Apply" #define OVC_done_label "Set" #define OVC_clear_label "Clear" #define OVC_quit_help "Press to close\nthis `chooser'" #define OVC_apply_help "Press to apply\nthis choice and\nkeep this `chooser'" #define OVC_done_help "Press to apply\nthis choice and\nclose this `chooser'" #define OVC_clear_help "Press to clear\nthe entry" #define OVC_av_help "Use arrows to\nsee what choices\nare available" #define OVC_opt_help "Click this button\nto pop up a menu\nof overlay colors" #define OVC_list_help_1 "Click Button 1 on the\n" \ "item of your choice,\n" \ "then press one of the\n" \ "control buttons below.\n" \ " ** OR **\n" \ "Double-click Button 1\n" \ "on an item to choose it." #define OVC_list_help_2 "Multiple Mode:\n" \ " Click Button 1 on items to\n" \ " select or de-select them.\n" \ "\n" \ "Extended Mode:\n" \ "+ Click and drag Button 1 to\n" \ " select ranges of items.\n" \ "+ Press Ctrl (on keyboard)\n" \ " at same time to avoid\n" \ " de-selecting items that\n" \ " were selected previously." #define NUM_OVC_ACT 3 #define NUM_CLR_ACT 4 static MCW_action_item OVC_act[] = { { OVC_quit_label , MCW_choose_CB, NULL, OVC_quit_help ,"Close window" ,0 }, { OVC_apply_label, MCW_choose_CB, NULL, OVC_apply_help,"Apply choice and keep window" ,0 }, { OVC_done_label , MCW_choose_CB, NULL, OVC_done_help ,"Apply choice and close window",1 }, { OVC_clear_label, MCW_choose_CB, NULL, OVC_clear_help,"Clear entry" ,0 } } ; #define NUM_LIST_MODES 2 static char * list_modes[NUM_LIST_MODES] = { "Multiple" , "Extended" } ; void MCW_choose_ovcolor( Widget wpar , MCW_DC * dc , int ovc_init , gen_func * func , XtPointer func_data ) { static Widget wpop = NULL , wrc ; static MCW_arrowval * av = NULL ; static MCW_choose_data cd ; Position xx,yy ; int ib ; ENTRY("MCW_choose_ovcolor") ; /** destructor callback **/ if( wpar == NULL ){ if( wpop != NULL ){ XtUnmapWidget( wpop ) ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wpop = NULL ; EXRETURN ; } if( ! XtIsRealized(wpar) || dc->ovc->ncol_ov < 2 ){ /* illegal call */ fprintf(stderr,"\n*** illegal call to MCW_choose_ovcolor: %s %d\n", XtName(wpar) , dc->ovc->ncol_ov ) ; EXRETURN ; } if( ovc_init < 0 || ovc_init >= dc->ovc->ncol_ov ) ovc_init = 1 ; /*--- if popup widget already exists, destroy it ---*/ if( wpop != NULL ){ XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } if( av != NULL ){ myXtFree( av ) ; av = NULL ; } /*--- create popup widget ---*/ wpop = XtVaCreatePopupShell( /* Popup Shell */ "menu" , xmDialogShellWidgetClass , wpar , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( MCW_isitmwm(wpar) ){ XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE , NULL ) ; } XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ; XmAddWMProtocolCallback( wpop , XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) , MCW_kill_chooser_CB , wpop ) ; wrc = XtVaCreateWidget( /* RowColumn to hold all */ "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; av = new_MCW_colormenu( wrc , "Color " , dc , 0 , dc->ovc->ncol_ov - 1 , ovc_init , NULL,NULL ) ; MCW_reghelp_children( av->wrowcol , OVC_opt_help ) ; MCW_reghint_children( av->wrowcol , "Overlay colors" ) ; cd.dc = dc ; /* data to be passed to pushbutton callback */ cd.wpop = wpop ; cd.wcaller = wpar ; cd.av = av ; cd.sel_CB = func ; cd.sel_cd = func_data ; cd.ctype = mcwCT_ovcolor ; for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ; (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ; XtTranslateCoords( wpar , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; if( av->wtext != NULL ) MCW_set_widget_bg( av->wtext , NULL , dc->ovc->pix_ov[ovc_init] ) ; /* after popup */ RWC_visibilize_widget( wpop ) ; /* 09 Nov 1999 */ NORMAL_cursorize( wpop ) ; EXRETURN ; } /*-------------------------------------------------------------------------*/ /*! Get a bunch of values [19 Mar 2004]. ---------------------------------------------------------------------------*/ void MCW_choose_vector( Widget wpar , char *label , int nvec , char **labvec , int *initvec , gen_func *func , XtPointer func_data ) { static Widget wpop = NULL , wrc ; static MCW_arrowval **av = NULL ; static int nav = 0 ; static MCW_choose_data cd ; Position xx,yy ; int ib , iv ; ENTRY("MCW_choose_vector") ; /** destructor callback **/ if( wpar == NULL || nvec <= 0 ){ if( wpop != NULL ){ XtUnmapWidget( wpop ) ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wpop = NULL ; EXRETURN ; } if( ! XtIsRealized(wpar) ){ /* illegal call */ fprintf(stderr,"\n*** illegal call to MCW_choose_vector: %s\n", XtName(wpar) ) ; EXRETURN ; } /*--- if popup widget already exists, destroy it ---*/ if( wpop != NULL ){ XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } if( nav > 0 && av != NULL ){ for( iv=0 ; iv < nav ; iv++ ) myXtFree( av[iv] ) ; myXtFree(av) ; av = NULL ; nav = 0 ; } /*--- create popup widget ---*/ wpop = XtVaCreatePopupShell( /* Popup Shell */ "menu" , xmDialogShellWidgetClass , wpar , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( MCW_isitmwm(wpar) ){ XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE , NULL ) ; } XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ; XmAddWMProtocolCallback( wpop , XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) , MCW_kill_chooser_CB , wpop ) ; wrc = XtVaCreateWidget( /* RowColumn to hold all */ "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( label != NULL ){ (void) XtVaCreateManagedWidget( "menu" , xmLabelWidgetClass , wrc , LABEL_ARG(label) , XmNinitialResourcesPersistent , False , NULL ) ; (void) XtVaCreateManagedWidget( "menu" , xmSeparatorWidgetClass , wrc , XmNseparatorType , XmSHADOW_ETCHED_IN , XmNinitialResourcesPersistent , False , NULL ) ; } av = (MCW_arrowval **) XtMalloc( sizeof(MCW_arrowval *) * nvec ) ; for( iv=0 ; iv < nvec ; iv++ ){ av[iv] = new_MCW_arrowval( wrc , (labvec!=NULL) ? labvec[iv] : NULL , MCW_AV_downup , -99999,99999, (initvec!=NULL) ? initvec[iv] : 0 , MCW_AV_edittext , 0 , NULL , NULL , NULL , NULL ) ; } cd.wpop = wpop ; /* data to be passed to pushbutton callback */ cd.wcaller = wpar ; cd.av = (MCW_arrowval *)av ; /* hack hack hack */ cd.sel_CB = func ; cd.sel_cd = func_data ; cd.ctype = mcwCT_vector ; cd.nvec = nvec ; for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ; (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ; XtTranslateCoords( wpar , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; RWC_visibilize_widget( wpop ) ; NORMAL_cursorize( wpop ) ; EXRETURN ; } /*------------------------------------------------------------------------- Get an integer: pops up a shell to let the user make the selection wpar = parent widget (where to popup) label = label for chooser bot,top,init = integers defining range and initial value func = routine to call when a selection is made: void func( Widget wpar,XtPointer func_data,MCW_choose_cbs * cbs ) func_data = data to pass to func The "ival" stored in the MCW_choose_cbs will be the desired result. This routine is coded in such a way that only one chooser will be active at a time (per application). This is a deliberate choice. ---------------------------------------------------------------------------*/ void MCW_choose_integer( Widget wpar , char *label , int bot , int top , int init , gen_func *func , XtPointer func_data ) { static Widget wpop = NULL , wrc ; static MCW_arrowval * av = NULL ; static MCW_choose_data cd ; Position xx,yy ; int ib ; ENTRY("MCW_choose_integer") ; /** destructor callback **/ if( wpar == NULL ){ if( wpop != NULL ){ XtUnmapWidget( wpop ) ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wpop = NULL ; EXRETURN ; } if( ! XtIsRealized(wpar) ){ /* illegal call */ fprintf(stderr,"\n*** illegal call to MCW_choose_integer: %s\n", XtName(wpar) ) ; EXRETURN ; } /*--- if popup widget already exists, destroy it ---*/ if( wpop != NULL ){ XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } if( av != NULL ){ myXtFree( av ) ; av = NULL ; } /*--- create popup widget ---*/ wpop = XtVaCreatePopupShell( /* Popup Shell */ "menu" , xmDialogShellWidgetClass , wpar , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( MCW_isitmwm(wpar) ){ XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE , NULL ) ; } XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ; XmAddWMProtocolCallback( wpop , XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) , MCW_kill_chooser_CB , wpop ) ; wrc = XtVaCreateWidget( /* RowColumn to hold all */ "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; av = new_MCW_arrowval( wrc , label , MCW_AV_downup , /* selection */ bot,top,init , MCW_AV_edittext , 0 , NULL , NULL , NULL , NULL ) ; av->allow_wrap = 1 ; MCW_reghelp_children( av->wrowcol , OVC_av_help ) ; MCW_reghint_children( av->wrowcol , "Pick value" ) ; cd.wpop = wpop ; /* data to be passed to pushbutton callback */ cd.wcaller = wpar ; cd.av = av ; cd.sel_CB = func ; cd.sel_cd = func_data ; cd.ctype = mcwCT_integer ; for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ; (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ; XtTranslateCoords( wpar , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; RWC_visibilize_widget( wpop ) ; /* 09 Nov 1999 */ NORMAL_cursorize( wpop ) ; EXRETURN ; } /*------------------------------------------------------------------------- ^ Create a new MCW_arrowpad: < O > v parent = parent Widget press_func = pointer to a function that will be called when an arrow or the button at the center is pressed press_data = pointer to data to be passed to press_func; press_func( apad , press_data ) ; where apad is a pointer to the MCW_arrowpad that was hit. If press_func is NULL, no callback occurs. You may create the arrowpad and later set the callback by apad->action_CB = press_func. ---------------------------------------------------------------------------*/ MCW_arrowpad * new_MCW_arrowpad( Widget parent , gen_func * press_func, XtPointer press_data ) { MCW_arrowpad * apad ; int asizx = 20 , asizy = 20 ; /* arrow sizes */ int iar ; ENTRY("new_MCW_arrowpad") ; apad = myXtNew( MCW_arrowpad ) ; /*--- form to hold the stuff: everything is tied to rubber positions ---*/ apad->wform = XtVaCreateWidget( "dialog" , xmFormWidgetClass , parent , XmNfractionBase , AP_FBASE , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; /*--- create the arrowbuttons ---*/ for( iar = 0 ; iar < 4 ; iar++ ){ apad->wbut[iar] = XtVaCreateManagedWidget( "arrow" , xmArrowButtonWidgetClass , apad->wform , XmNtopAttachment , XmATTACH_POSITION , XmNbottomAttachment , XmATTACH_POSITION , XmNleftAttachment , XmATTACH_POSITION , XmNrightAttachment , XmATTACH_POSITION , XmNarrowDirection , AP_but_def[iar].atype , XmNtopPosition , AP_but_def[iar].atop , XmNbottomPosition , AP_but_def[iar].abottom , XmNleftPosition , AP_but_def[iar].aleft , XmNrightPosition , AP_but_def[iar].aright , XmNheight , asizy , XmNwidth , asizx , XmNborderWidth , 0 , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; XtAddCallback( apad->wbut[iar], XmNarmCallback , AP_press_CB, apad ) ; XtAddCallback( apad->wbut[iar], XmNdisarmCallback, AP_press_CB, apad ) ; } /*--- create the pushbutton in the middle ---*/ apad->wbut[4] = XtVaCreateManagedWidget( "arrow" , xmPushButtonWidgetClass , apad->wform , XmNtopAttachment , XmATTACH_POSITION , XmNbottomAttachment , XmATTACH_POSITION , XmNleftAttachment , XmATTACH_POSITION , XmNrightAttachment , XmATTACH_POSITION , XmNtopPosition , AP_but_def[4].atop , XmNbottomPosition , AP_but_def[4].abottom , XmNleftPosition , AP_but_def[4].aleft , XmNrightPosition , AP_but_def[4].aright , XtVaTypedArg , XmNlabelString , XmRString , " " , 2 , XmNheight , asizy , XmNwidth , asizx , XmNborderWidth , 0 , XmNrecomputeSize , False , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; XtAddCallback( apad->wbut[4] , XmNactivateCallback , AP_press_CB , apad ) ; XtManageChild( apad->wform ) ; apad->action_CB = press_func ; apad->action_data = press_data ; apad->fastdelay = MCW_AV_shortdelay ; /* default delay on 2nd call */ apad->count = 0 ; apad->parent = apad->aux = NULL ; RETURN(apad) ; } /*-------------------------------------------------------------------------*/ void AP_press_CB( Widget wbut , XtPointer client_data , XtPointer call_data ) { MCW_arrowpad * apad = (MCW_arrowpad *) client_data ; XmArrowButtonCallbackStruct * cbs = (XmArrowButtonCallbackStruct *) call_data ; XtIntervalId fake_id = 0 ; switch( cbs->reason ){ /*--- release of button (will only happen for arrows) ---*/ default: case XmCR_DISARM: /* time to stop */ if( apad->timer_id != 0 ) XtRemoveTimeOut( apad->timer_id ) ; apad->timer_id = 0 ; break ; /*--- press of button ---*/ case XmCR_ARM: /* arrow press */ case XmCR_ACTIVATE:{ /* button press */ int iar ; for( iar=0 ; iar < 5 ; iar++ ) if( wbut == apad->wbut[iar] ) break ; if( iar > 4 ) return ; /* something wrong, exit */ apad->which_pressed = iar ; apad->count = 0 ; if( cbs->reason == XmCR_ARM && cbs->event->type == ButtonPress ) apad->delay = MCW_AV_longdelay; else apad->delay = 0 ; apad->xev = *(cbs->event) ; /* copy event for user's info */ AP_timer_CB( apad , &fake_id ) ; /* do the work */ } } return; } /*-------------------------------------------------------------------------*/ void AP_timer_CB( XtPointer client_data , XtIntervalId * id ) { MCW_arrowpad * apad = (MCW_arrowpad *) client_data ; /* call user callback */ if( apad->action_CB != NULL ) #if 0 apad->action_CB( apad , apad->action_data ) ; #else AFNI_CALL_VOID_2ARG( apad->action_CB , MCW_arrowpad * , apad , XtPointer , apad->action_data ) ; #endif /* delay and then call again, if desired */ if( apad->delay <= 0 ) return ; (apad->count)++ ; if( apad->count > AP_MAXCOUNT ){ apad->count = 0 ; return ; } apad->timer_id = XtAppAddTimeOut( XtWidgetToApplicationContext( apad->wform ) , apad->delay , AP_timer_CB , apad ) ; if( apad->delay == MCW_AV_longdelay ) if( apad->fastdelay > 0 ) apad->delay = apad->fastdelay ; else apad->delay = MCW_AV_shortdelay ; return ; } /*------------------------------------------------------------------------- Get a string: pops up a shell to let the user make the selection wpar = parent widget (where to popup) label = label for chooser default_string = initial value func = routine to call when a selection is made: void func( Widget wpar,XtPointer func_data,MCW_choose_cbs * cbs ) func_data = data to pass to func The "cval" stored in the MCW_choose_cbs will be the desired result. This routine is coded in such a way that only one chooser will be active at a time (per application). This is a deliberate choice. ---------------------------------------------------------------------------*/ void MCW_choose_string( Widget wpar , char * label , char * default_string , gen_func * func , XtPointer func_data ) { static Widget wpop = NULL , wrc , wtf , wlab ; static MCW_choose_data cd ; Position xx,yy ; int ib , ncol=0 ; ENTRY("MCW_choose_string") ; /** destructor callback **/ if( wpar == NULL ){ if( wpop != NULL ){ XtUnmapWidget( wpop ) ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wpop = NULL ; EXRETURN ; } if( ! XtIsWidget(wpar) ) EXRETURN ; if( ! XtIsRealized(wpar) ){ /* illegal call */ fprintf(stderr,"\n*** illegal call to MCW_choose_string: %s\n", XtName(wpar) ) ; EXRETURN ; } /*--- if popup widget already exists, destroy it ---*/ if( wpop != NULL ){ XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } /*--- create popup widget ---*/ wpop = XtVaCreatePopupShell( /* Popup Shell */ "menu" , xmDialogShellWidgetClass , wpar , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( MCW_isitmwm(wpar) ){ XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE , NULL ) ; } XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ; XmAddWMProtocolCallback( wpop , XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) , MCW_kill_chooser_CB , wpop ) ; wrc = XtVaCreateWidget( /* RowColumn to hold all */ "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( label != NULL && (ncol=strlen(label)) > 0 ){ char *cpt ; wlab = XtVaCreateManagedWidget( "menu" , xmLabelWidgetClass , wrc , LABEL_ARG(label) , XmNinitialResourcesPersistent , False , NULL ) ; cpt = strstr(label,"\n") ; if( cpt != NULL ) ncol = cpt-label ; /* 01 Nov 2001 */ } if( default_string != NULL && default_string[0] != '\0' ){ int qq = strlen(default_string) ; if( qq > ncol ) ncol = qq ; } if( ncol < AV_NCOL ) ncol = AV_NCOL ; wtf = XtVaCreateManagedWidget( "menu" , TEXT_CLASS , wrc , XmNcolumns , ncol , XmNeditable , True , XmNmaxLength , ncol+64 , XmNresizeWidth , False , XmNmarginHeight , 1 , XmNmarginWidth , 1 , XmNcursorPositionVisible , True , XmNblinkRate , 0 , XmNautoShowCursorPosition , True , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; if( default_string != NULL && default_string[0] != '\0' ){ int qq = strlen(default_string) , ii ; for( ii=0 ; ii < qq ; ii++ ) if( default_string[ii] != ' ' ) break ; if( ii < qq ) TEXT_SET( wtf , default_string ) ; } cd.wpop = wpop ; /* data to be passed to pushbutton callback */ cd.wcaller = wpar ; cd.wchoice = wtf ; cd.sel_CB = func ; cd.sel_cd = func_data ; cd.ctype = mcwCT_string ; XtAddCallback( wtf, XmNactivateCallback, MCW_choose_CB, &cd ) ; /* return key */ for( ib=0 ; ib < NUM_CLR_ACT ; ib++ ) OVC_act[ib].data = &cd ; (void) MCW_action_area( wrc , OVC_act , NUM_CLR_ACT ) ; XtTranslateCoords( wpar , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; RWC_visibilize_widget( wpop ) ; /* 09 Nov 1999 */ NORMAL_cursorize( wpop ) ; EXRETURN ; } /*-------------------------------------------------------------------------*/ static int list_max = -1 , list_maxmax ; static void MCW_set_listmax( Widget wpar ) { if( list_max < 0 ){ #if 0 char * xdef = XGetDefault( XtDisplay(wpar) , "AFNI" , "chooser_listmax" ) ; #else char * xdef = RWC_getname( XtDisplay(wpar) , "chooser_listmax" ) ; #endif if( xdef == NULL ) xdef = getenv("AFNI_MENU_COLSIZE") ; /* 11 Dec 2001 */ if( xdef != NULL ) list_max = strtol( xdef , NULL , 10 ) ; if( list_max <= 4 ) list_max = LIST_MAX ; list_maxmax = list_max + 5 ; } return ; } /*------------------------------------------------------------------------- Get an integer, as an index to an array of strings: pops up a shell to let the user make the selection, cycling through the string array wpar = parent widget (where to popup) label = label for chooser num_str = number of strings init = index of initial string strlist = array of char *, pointing to strings func = routine to call when a selection is made: void func( Widget wpar,XtPointer func_data,MCW_choose_cbs * cbs ) func_data = data to pass to func The "ival" stored in the MCW_choose_cbs will be the desired result (from 0 to num_str-1). This routine is coded in such a way that only one chooser will be active at a time (per application). This is a deliberate choice. ---------------------------------------------------------------------------*/ void MCW_choose_strlist( Widget wpar , char * label , int num_str , int init , char * strlist[] , gen_func * func , XtPointer func_data ) { int initar[2] ; initar[0] = init ; initar[1] = -666 ; MCW_choose_multi_strlist( wpar , label , mcwCT_single_mode , num_str , initar , strlist , func , func_data ) ; return ; } void MCW_choose_multi_strlist( Widget wpar , char * label , int mode , int num_str , int * init , char * strlist[] , gen_func * func , XtPointer func_data ) { static Widget wpop = NULL , wrc ; static MCW_choose_data cd ; Position xx,yy ; int ib , ll , ltop ; Widget wlist = NULL , wlab ; XmStringTable xmstr ; XmString xms ; char * lbuf ; int nvisible ; ENTRY("MCW_choose_multi_strlist") ; /** destructor callback **/ if( wpar == NULL ){ if( wpop != NULL ){ XtUnmapWidget( wpop ) ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } STATUS("destroying chooser") ; wpop = NULL ; EXRETURN ; } if( ! XtIsRealized(wpar) ){ /* illegal call */ fprintf(stderr,"\n*** illegal call to MCW_choose_strlist %s\n", XtName(wpar) ) ; EXRETURN ; } MCW_set_listmax( wpar ) ; /*--- if popup widget already exists, destroy it ---*/ if( wpop != NULL ){ XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wlist = NULL ; /*--- create popup widget ---*/ wpop = XtVaCreatePopupShell( /* Popup Shell */ "menu" , xmDialogShellWidgetClass , wpar , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( MCW_isitmwm(wpar) ){ XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE | MWM_FUNC_CLOSE , NULL ) ; } XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ; XmAddWMProtocolCallback( wpop , XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) , MCW_kill_chooser_CB , wpop ) ; wrc = XtVaCreateWidget( /* RowColumn to hold all */ "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( label != NULL && label[0] != '\0' ){ lbuf = (char*)XtMalloc( strlen(label) + 32 ) ; sprintf( lbuf , "----Choose %s----\n%s" , (mode == mcwCT_single_mode) ? "One" : "One or More" , label ) ; } else { lbuf = (char*)XtMalloc( 32 ) ; sprintf( lbuf , "----Choose %s----", (mode == mcwCT_single_mode) ? "One" : "One or More" ) ; } xms = XmStringCreateLtoR( lbuf , XmFONTLIST_DEFAULT_TAG ) ; wlab = XtVaCreateManagedWidget( "menu" , xmLabelWidgetClass , wrc , XmNlabelString , xms , XmNalignment , XmALIGNMENT_CENTER , XmNinitialResourcesPersistent , False , NULL ) ; myXtFree(lbuf) ; XmStringFree(xms) ; (void) XtVaCreateManagedWidget( "menu" , xmSeparatorWidgetClass , wrc , XmNseparatorType , XmSHADOW_ETCHED_IN , XmNinitialResourcesPersistent , False , NULL ) ; xmstr = (XmStringTable) XtMalloc( num_str * sizeof(XmString *) ) ; for( ib=0 ; ib < num_str ; ib++ ) xmstr[ib] = XmStringCreateSimple(strlist[ib]) ; wlist = XmCreateScrolledList( wrc , "menu" , NULL , 0 ) ; nvisible = (num_str < list_maxmax ) ? num_str : list_max ; XtVaSetValues( wlist , XmNitems , xmstr , XmNitemCount , num_str , XmNvisibleItemCount , nvisible , XmNtraversalOn , True , XmNselectionPolicy , (mode == mcwCT_single_mode) ? XmSINGLE_SELECT : XmMULTIPLE_SELECT , NULL ) ; if( init != NULL ){ for( ib=0 ; init[ib] >= 0 && init[ib] < num_str ; ib++ ){ XmListSelectPos( wlist , init[ib]+1 , False ) ; } if( ib > 0 && init[ib-1] > nvisible ) XmListSetBottomPos( wlist , init[ib-1]+1 ) ; } XtManageChild(wlist) ; if( mode == mcwCT_multi_mode ){ MCW_register_help( wlist , OVC_list_help_2 ) ; MCW_register_help( wlab , OVC_list_help_2 ) ; } else { MCW_register_help( wlist , OVC_list_help_1 ) ; MCW_register_help( wlab , OVC_list_help_1 ) ; XtAddCallback( wlist , XmNdefaultActionCallback , MCW_choose_CB , &cd ) ; } cd.wchoice = wlist ; cd.av = NULL ; /* this is NULL --> will use the list widget */ for( ib=0 ; ib < num_str ; ib++ ) XmStringFree(xmstr[ib]) ; myXtFree(xmstr) ; cd.wpop = wpop ; /* data to be passed to pushbutton callback */ cd.wcaller = wpar ; cd.sel_CB = func ; cd.sel_cd = func_data ; cd.ctype = mcwCT_integer ; for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ; (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ; if( mode == mcwCT_multi_mode ){ MCW_arrowval * av ; (void) XtVaCreateManagedWidget( "menu" , xmSeparatorWidgetClass , wrc , XmNseparatorType , XmSHADOW_ETCHED_IN , XmNinitialResourcesPersistent , False , NULL ) ; av = new_MCW_optmenu( wrc , "Selection Mode" , 0,NUM_LIST_MODES-1,0,0 , MCW_list_mode_CB , wlist , MCW_av_substring_CB , list_modes ) ; MCW_reghelp_children( av->wrowcol , OVC_list_help_2 ) ; MCW_reghint_children( av->wrowcol , "How list selections work" ) ; } XtTranslateCoords( wpar , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; RWC_visibilize_widget( wpop ) ; /* 09 Nov 1999 */ NORMAL_cursorize( wpop ) ; EXRETURN ; } void MCW_list_mode_CB( MCW_arrowval * av , XtPointer cd ) { Widget wlist = (Widget) cd ; if( av == NULL || wlist == NULL ) return ; XtVaSetValues( wlist , XmNselectionPolicy , (av->ival == 0) ? XmMULTIPLE_SELECT : XmEXTENDED_SELECT , NULL ) ; } /*==================================================================================*/ #define TSC_quit_label "Quit" #define TSC_plot_label "Plot" #define TSC_apply_label "Apply" #define TSC_done_label "Set" #define TSC_quit_help "Press to close\nthis `chooser'" #define TSC_plot_help "Press to popup\na graph of the\nselected time series" #define TSC_apply_help "Press to apply\nthis choice and\nkeep this `chooser'" #define TSC_done_help "Press to apply\nthis choice and\nclose this `chooser'" #define TSC_list_help_1 OVC_list_help_1 #define NUM_TSC_ACT 4 #undef DONT_USE_COXPLOT /* for the long-delayed Plot option */ #undef PCODE #ifdef DONT_USE_COXPLOT # define PCODE -1 #else # define PCODE 0 # include "coxplot.h" #endif static MCW_action_item TSC_act[] = { { TSC_quit_label , MCW_choose_CB, NULL, TSC_quit_help ,"Close window" , 0 }, { TSC_plot_label , MCW_choose_CB, NULL, TSC_plot_help ,"Plot data" , PCODE }, { TSC_apply_label, MCW_choose_CB, NULL, TSC_apply_help,"Apply choice, keep window" , 0 }, { TSC_done_label , MCW_choose_CB, NULL, TSC_done_help ,"Apply choice, close window", 1 } } ; #undef PCODE /*------------------------------------------------------------------------- Get a time series (1D MRI_IMAGE *) from an array of such things: pops up a shell to let the user make the selection, with a list of time series name wpar = parent widget (where to popup) label = label for chooser tsarr = array of time series (1D images) init = index of initial time series to select func = routine to call when choice is made void func( Widget wpar,XtPointer func_data,MCW_choose_cbs * cbs ) func_data = data to pass to func The "ival" stored in the MCW_choose_cbs will the the index of the chosen timeseries in tsarr. The "imval" be the pointer to the chosen timeseries itself. Do NOT mri_free this, since it will just be a pointer to the correct entry in tsarr (which should not be modified by any other code during the lifetime of this popup!). This routine is coded in such a way that only one chooser will be active at a time (per application). This is a deliberate choice. ---------------------------------------------------------------------------*/ void MCW_choose_timeseries( Widget wpar , char *label , MRI_IMARR *tsarr , int init , gen_func *func , XtPointer func_data ) { static Widget wpop = NULL , wrc ; static MCW_choose_data cd ; Position xx,yy ; int ib , ll , ltop , num_ts , nvisible , xd,yd ; Widget wlist = NULL , wlab ; XmStringTable xmstr ; XmString xms ; char *lbuf ; char pbuf[256] , qbuf[512] ; MRI_IMAGE *tsim ; ENTRY("MCW_choose_timeseries") ; /** destructor callback **/ if( wpar == NULL ){ if( wpop != NULL ){ STATUS("popdown call") ; XtUnmapWidget( wpop ) ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wpop = NULL ; EXRETURN ; } if( ! XtIsRealized(wpar) ){ /* illegal call */ fprintf(stderr,"\n*** illegal call to MCW_choose_timeseries %s\n", XtName(wpar) ) ; EXRETURN ; } MCW_set_listmax( wpar ) ; /*--- if popup widget already exists, destroy it ---*/ if( wpop != NULL ){ STATUS("destroying old widget") ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wlist = NULL ; /*--- sanity checks ---*/ if( tsarr == NULL || tsarr->num == 0 ) EXRETURN ; num_ts = tsarr->num ; if(PRINT_TRACING){ char str[256]; sprintf(str,"creation with %d choices",num_ts); STATUS(str); } /*--- create popup widget ---*/ wpop = XtVaCreatePopupShell( /* Popup Shell */ "menu" , xmDialogShellWidgetClass , wpar , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( MCW_isitmwm(wpar) ){ XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE | MWM_FUNC_CLOSE , NULL ) ; } XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ; XmAddWMProtocolCallback( wpop , XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) , MCW_kill_chooser_CB , wpop ) ; wrc = XtVaCreateWidget( /* RowColumn to hold all */ "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( label != NULL ){ lbuf = (char*)XtMalloc( strlen(label) + 32 ) ; sprintf( lbuf , "----Choose One----\n%s" , label ) ; } else { lbuf = (char*)XtMalloc( 32 ) ; sprintf( lbuf , "----Choose One----" ) ; } xms = XmStringCreateLtoR( lbuf , XmFONTLIST_DEFAULT_TAG ) ; wlab = XtVaCreateManagedWidget( "menu" , xmLabelWidgetClass , wrc , XmNlabelString , xms , XmNalignment , XmALIGNMENT_CENTER , XmNinitialResourcesPersistent , False , NULL ) ; myXtFree(lbuf) ; XmStringFree(xms) ; (void) XtVaCreateManagedWidget( "menu" , xmSeparatorWidgetClass , wrc , XmNseparatorType , XmSHADOW_ETCHED_IN , XmNinitialResourcesPersistent , False , NULL ) ; xmstr = (XmStringTable) XtMalloc( num_ts * sizeof(XmString *) ) ; xd = yd = ltop = 1 ; for( ib=0 ; ib < num_ts ; ib++ ){ tsim = IMARR_SUBIMAGE(tsarr,ib) ; if( tsim == NULL ){ strcpy(pbuf,"** NULL series ??") ; } else { if( tsim->name != NULL ) MCW_strncpy(pbuf,IMARR_SUBIMAGE(tsarr,ib)->name,254) ; else strcpy(pbuf,"** NO NAME ??") ; sprintf(qbuf,"%d",tsim->nx) ; ll = strlen(qbuf) ; xd = MAX(xd,ll) ; sprintf(qbuf,"%d",tsim->ny) ; ll = strlen(qbuf) ; yd = MAX(yd,ll) ; } ll = strlen(pbuf) ; ltop = MAX(ltop,ll) ; } for( ib=0 ; ib < num_ts ; ib++ ){ tsim = IMARR_SUBIMAGE(tsarr,ib) ; if( tsim == NULL ){ strcpy(qbuf,"** NULL series ??") ; } else { if( tsim->name != NULL ) MCW_strncpy(pbuf,IMARR_SUBIMAGE(tsarr,ib)->name,254) ; else strcpy(pbuf,"** NO NAME ??") ; sprintf(qbuf,"%-*s [%*d x %*d]", ltop,pbuf , xd,tsim->nx , yd,tsim->ny ) ; } xmstr[ib] = XmStringCreateSimple( qbuf ) ; } wlist = XmCreateScrolledList( wrc , "menu" , NULL , 0 ) ; nvisible = (num_ts < list_maxmax ) ? num_ts : list_max ; XtVaSetValues( wlist , XmNitems , xmstr , XmNitemCount , num_ts , XmNvisibleItemCount , nvisible , XmNtraversalOn , True , XmNselectionPolicy , XmSINGLE_SELECT , NULL ) ; if( init >= 0 && init < num_ts ){ XmListSelectPos( wlist , init+1 , False ) ; if( init+1 > nvisible ) XmListSetBottomPos( wlist , init+1 ) ; } XtManageChild(wlist) ; XtAddCallback( wlist , XmNdefaultActionCallback , MCW_choose_CB , &cd ) ; MCW_register_help( wlist , TSC_list_help_1 ) ; MCW_register_help( wlab , TSC_list_help_1 ) ; cd.tsarr = tsarr ; cd.wchoice = wlist ; cd.av = NULL ; #if 1 for( ib=0 ; ib < num_ts ; ib++ ) XmStringFree(xmstr[ib]) ; myXtFree(xmstr) ; #endif cd.wpop = wpop ; /* data to be passed to pushbutton callback */ cd.wcaller = wpar ; cd.sel_CB = func ; cd.sel_cd = func_data ; cd.ctype = mcwCT_timeseries ; for( ib=0 ; ib < NUM_TSC_ACT ; ib++ ) TSC_act[ib].data = &cd ; (void) MCW_action_area( wrc , TSC_act , NUM_TSC_ACT ) ; XtTranslateCoords( wpar , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; RWC_visibilize_widget( wpop ) ; /* 09 Nov 1999 */ NORMAL_cursorize( wpop ) ; EXRETURN ; } /*------------------------------------------------------------------------- Get an integer, as an index to an array of strings: * pops up a shell to let the user make the selection, cycling through the string array * allows the user to add to the string array wpar = parent widget (where to popup) label = label for chooser sar = array of initial strings (see 3ddata.h) [may be changed by the user during operations] init = index of initial string func = routine to call when a selection is made: void func( Widget wpar,XtPointer func_data,MCW_choose_cbs * cbs ) func_data = data to pass to func The "ival" stored in the MCW_choose_cbs will be the desired result. This routine is coded in such a way that only one chooser will be active at a time (per application). This is a deliberate choice. ---------------------------------------------------------------------------*/ void MCW_choose_editable_strlist( Widget wpar , char * label , THD_string_array * sar , int init , gen_func * func , XtPointer func_data ) { int initar[2] ; initar[0] = init ; initar[1] = -666 ; MCW_choose_multi_editable_strlist( wpar , label , mcwCT_single_mode , sar , initar , func , func_data ) ; return ; } void MCW_choose_multi_editable_strlist( Widget wpar , char * label , int mode , THD_string_array * sar , int * init , gen_func * func , XtPointer func_data ) { static Widget wpop = NULL , wrc , wrc2 ; static MCW_choose_data cd ; Position xx,yy ; int ib , ll , ltop , num_str ; Widget wlist = NULL , wlab , wtf , wadd ; XmStringTable xmstr ; XmString xms ; char * lbuf ; int nvisible ; ENTRY("MCW_choose_multi_editable_strlist") ; /** destructor callback **/ if( wpar == NULL ){ if( wpop != NULL ){ XtUnmapWidget( wpop ) ; XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wpop = NULL ; EXRETURN ; } if( ! XtIsRealized(wpar) ){ /* illegal call */ fprintf(stderr,"\n*** illegal call to MCW_choose_strlist %s\n", XtName(wpar) ) ; EXRETURN ; } MCW_set_listmax( wpar ) ; /*--- if popup widget already exists, destroy it ---*/ if( wpop != NULL ){ XtRemoveCallback( wpop, XmNdestroyCallback, MCW_destroy_chooser_CB, &wpop ) ; XtDestroyWidget( wpop ) ; } wlist = NULL ; /*--- create popup widget ---*/ wpop = XtVaCreatePopupShell( /* Popup Shell */ "menu" , xmDialogShellWidgetClass , wpar , XmNallowShellResize , True , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; if( MCW_isitmwm(wpar) ){ XtVaSetValues( wpop , XmNmwmDecorations , MWM_DECOR_BORDER , XmNmwmFunctions , MWM_FUNC_MOVE | MWM_FUNC_CLOSE , NULL ) ; } XtAddCallback( wpop , XmNdestroyCallback , MCW_destroy_chooser_CB , &wpop ) ; XmAddWMProtocolCallback( wpop , XmInternAtom( XtDisplay(wpop) , "WM_DELETE_WINDOW" , False ) , MCW_kill_chooser_CB , wpop ) ; /* RowColumn to hold all */ wrc = XtVaCreateWidget( "menu" , xmRowColumnWidgetClass , wpop , XmNpacking , XmPACK_TIGHT , XmNorientation , XmVERTICAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; /* Label at the top */ if( label != NULL ){ lbuf = (char*)XtMalloc( strlen(label) + 32 ) ; sprintf( lbuf , "----Choose %s----\n%s" , (mode == mcwCT_single_mode) ? "One" : "One or More" , label ) ; } else { lbuf = (char*)XtMalloc( 32 ) ; sprintf( lbuf , "----Choose %s----", (mode == mcwCT_single_mode) ? "One" : "One or More" ) ; } xms = XmStringCreateLtoR( lbuf , XmFONTLIST_DEFAULT_TAG ) ; wlab = XtVaCreateManagedWidget( "menu" , xmLabelWidgetClass , wrc , XmNlabelString , xms , XmNalignment , XmALIGNMENT_CENTER , XmNinitialResourcesPersistent , False , NULL ) ; myXtFree(lbuf) ; XmStringFree(xms) ; /* Separator line */ (void) XtVaCreateManagedWidget( "menu" , xmSeparatorWidgetClass , wrc , XmNseparatorType , XmSHADOW_ETCHED_IN , XmNinitialResourcesPersistent , False , NULL ) ; /* List to choose from */ wlist = XmCreateScrolledList( wrc , "menu" , NULL , 0 ) ; XtVaSetValues( wlist , XmNtraversalOn , True , XmNselectionPolicy , (mode == mcwCT_single_mode) ? XmSINGLE_SELECT : XmMULTIPLE_SELECT , NULL ) ; num_str = SARR_NUM(sar) ; if( num_str > 0 ){ xmstr = (XmStringTable) XtMalloc( num_str * sizeof(XmString *) ) ; for( ib=0 ; ib < num_str ; ib++ ) xmstr[ib] = XmStringCreateSimple( SARR_STRING(sar,ib) ) ; nvisible = (num_str < list_maxmax ) ? num_str : list_max ; XtVaSetValues( wlist , XmNitems , xmstr , XmNitemCount , num_str , XmNvisibleItemCount , nvisible , NULL ) ; if( init != NULL ){ for( ib=0 ; init[ib] >= 0 && init[ib] < num_str ; ib++ ){ XmListSelectPos( wlist , init[ib]+1 , False ) ; } if( ib > 0 && init[ib-1] > nvisible ) XmListSetBottomPos( wlist , init[ib-1]+1 ) ; } for( ib=0 ; ib < num_str ; ib++ ) XmStringFree(xmstr[ib]) ; myXtFree(xmstr) ; } XtManageChild(wlist) ; /* Some help? */ if( mode == mcwCT_multi_mode ){ MCW_register_help( wlist , OVC_list_help_2 ) ; MCW_register_help( wlab , OVC_list_help_2 ) ; } else { MCW_register_help( wlist , OVC_list_help_1 ) ; MCW_register_help( wlab , OVC_list_help_1 ) ; XtAddCallback( wlist , XmNdefaultActionCallback , MCW_choose_CB , &cd ) ; } cd.wchoice = wlist ; cd.av = NULL ; /* this is NULL --> will use the list widget */ cd.wpop = wpop ; /* data to be passed to pushbutton callback */ cd.wcaller = wpar ; cd.sel_CB = func ; cd.sel_cd = func_data ; cd.ctype = mcwCT_integer ; cd.sar = sar ; /* action buttons */ for( ib=0 ; ib < NUM_OVC_ACT ; ib++ ) OVC_act[ib].data = &cd ; (void) MCW_action_area( wrc , OVC_act , NUM_OVC_ACT ) ; /* choosing mode, for multiple selections */ if( mode == mcwCT_multi_mode ){ MCW_arrowval * av ; (void) XtVaCreateManagedWidget( "menu" , xmSeparatorWidgetClass , wrc , XmNseparatorType , XmSHADOW_ETCHED_IN , XmNinitialResourcesPersistent , False , NULL ) ; av = new_MCW_optmenu( wrc , "Selection Mode" , 0,NUM_LIST_MODES-1,0,0 , MCW_list_mode_CB , wlist , MCW_av_substring_CB , list_modes ) ; MCW_reghelp_children( av->wrowcol , OVC_list_help_2 ) ; MCW_reghint_children( av->wrowcol , "How list selections work" ) ; } /* Separator line */ (void) XtVaCreateManagedWidget( "menu" , xmSeparatorWidgetClass , wrc , XmNseparatorType , XmSINGLE_LINE , XmNinitialResourcesPersistent , False , NULL ) ; /*-- Stuff to string array --*/ wrc2 = XtVaCreateWidget( /* Rowcol for stuff */ "menu" , xmRowColumnWidgetClass , wrc , XmNpacking , XmPACK_TIGHT , XmNorientation , XmHORIZONTAL , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; wtf = XtVaCreateManagedWidget( /* String to add */ "menu" , TEXT_CLASS , wrc2 , XmNcolumns , 24 , XmNeditable , True , XmNmaxLength , 128 , XmNresizeWidth , False , XmNmarginHeight , 1 , XmNmarginWidth , 1 , XmNcursorPositionVisible , True , XmNblinkRate , 0 , XmNautoShowCursorPosition , True , XmNinitialResourcesPersistent , False , XmNtraversalOn , False , NULL ) ; xms = XmStringCreateLtoR( "Add" , XmFONTLIST_DEFAULT_TAG ) ; wadd = XtVaCreateManagedWidget( /* Button to add it */ "menu" , xmPushButtonWidgetClass , wrc2 , XmNlabelString , xms , XmNtraversalOn , False , XmNinitialResourcesPersistent , False , NULL ) ; XmStringFree(xms) ; MCW_set_widget_bg( wadd , MCW_hotcolor(wadd) , 0 ) ; XtAddCallback( wadd, XmNactivateCallback, MCW_stradd_CB, &cd ) ; XtAddCallback( wtf , XmNactivateCallback, MCW_stradd_CB, &cd ) ; cd.wtf = wtf ; MCW_reghelp_children( wrc2 , "Type an entry and press Add\n" "or hit Enter to make a new\n" "entry in the chooser list." ) ; MCW_reghint_children( wrc2 , "Enter new item into chooser list" ) ; XtManageChild( wrc2 ) ; /* make it appear, like magic! */ XtTranslateCoords( wpar , 15,15 , &xx , &yy ) ; XtVaSetValues( wpop , XmNx , (int) xx , XmNy , (int) yy , NULL ) ; XtManageChild( wrc ) ; XtPopup( wpop , XtGrabNone ) ; RWC_visibilize_widget( wpop ) ; /* 09 Nov 1999 */ NORMAL_cursorize( wpop ) ; EXRETURN ; } /*--------------------------------------------------------------------------*/ void MCW_stradd_CB( Widget w, XtPointer client_data, XtPointer call_data ) { MCW_choose_data * cd = (MCW_choose_data *) client_data ; char *nstr = TEXT_GET( cd->wtf ) ; int id , nvisible , num_str ; XmString xms ; ENTRY("MCW_stradd_CB") ; if( nstr == NULL || strlen(nstr) == 0 ){ myXtFree(nstr); XBell(XtDisplay(w),100); EXRETURN; } /* see if new string is already in the list */ for( id=0 ; id < SARR_NUM(cd->sar) ; id++ ) if( strcmp(nstr,SARR_STRING(cd->sar,id)) == 0 ) break ; if( id < SARR_NUM(cd->sar) ){ /* found it, so just jump to it in the list */ XmListSetBottomPos( cd->wchoice , id+1 ) ; /* put on bottom */ XmListSelectPos( cd->wchoice , id+1 , False ) ; /* select it */ } else { /* is a new string, so add it to the list */ ADDTO_SARR( cd->sar , nstr ) ; /* add to internal list */ xms = XmStringCreateSimple( nstr ) ; XmListAddItem( cd->wchoice , xms , 0 ) ; /* add to List widget */ XmStringFree(xms) ; num_str = SARR_NUM(cd->sar) ; nvisible = (num_str < list_maxmax) ? num_str : list_max ; XtVaSetValues( cd->wchoice , XmNvisibleItemCount , nvisible , NULL ) ; XmListSetBottomPos( cd->wchoice , 0 ) ; /* make sure it is visible */ XmListSelectPos( cd->wchoice , 0 , False ) ; /* select it */ } myXtFree(nstr) ; EXRETURN ; } /*--------------------------------------------------------------------------*/ #define LIST_DBCLICK_UNKNOWN -1 #define LIST_DBCLICK_APPLY 1 #define LIST_DBCLICK_DONE 2 void MCW_choose_CB( Widget w , XtPointer client_data , XtPointer call_data ) { MCW_choose_data *cd = (MCW_choose_data *) client_data ; char *wname = XtName(w) ; XmAnyCallbackStruct *icbs = (XmAnyCallbackStruct *) call_data ; static MCW_choose_cbs cbs ; /* to be passed back to user */ static int list_dbclick_use = LIST_DBCLICK_UNKNOWN ; Boolean clear ; ENTRY("MCW_choose_CB") ; /*--- set up what to do for list double clicks ---*/ if( list_dbclick_use == LIST_DBCLICK_UNKNOWN ){ #if 0 char *xdef = XGetDefault( XtDisplay(w) , "AFNI" , "chooser_doubleclick" ) ; #else char *xdef = RWC_getname( XtDisplay(w) , "chooser_doubleclick" ) ; #endif if( xdef != NULL && strcmp(xdef,OVC_apply_label) == 0 ) list_dbclick_use = LIST_DBCLICK_APPLY ; else list_dbclick_use = LIST_DBCLICK_DONE ; } /*--- branch on type of chooser that called this ---*/ clear = (strcmp(wname,OVC_clear_label) == 0) ; if( clear && cd->ctype != mcwCT_string ){ XBell( XtDisplay(cd->wpop) , 100 ) ; RWC_XtPopdown( cd->wpop ) ; EXRETURN ; } switch( cd->ctype ){ default: /* error! */ XBell( XtDisplay(w) , 100 ) ; fprintf(stderr, "\n*** unknown choose type=%d from %s\n", cd->ctype, wname ) ; EXRETURN ; /*.....................*/ case mcwCT_vector:{ /* vector chooser [19 Mar 2004] */ Boolean done,call ; int iv ; float *vec ; MCW_arrowval **aav = (MCW_arrowval **)cd->av ; done = strcmp(wname,OVC_apply_label) != 0 ; call = strcmp(wname,OVC_quit_label) != 0 ; if( done ) RWC_XtPopdown( cd->wpop ) ; if( call ){ cbs.reason = mcwCR_vector ; /* set structure for call to user */ cbs.event = icbs->event ; cbs.ival = cd->nvec ; vec = (float *)malloc(sizeof(float)*cd->nvec) ; cbs.cval = (char *)vec ; for( iv=0 ; iv < cd->nvec ; iv++ ) vec[iv] = aav[iv]->fval ; if( !done ) MCW_invert_widget(w) ; /* flash */ #if 0 cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */ #else AFNI_CALL_VOID_3ARG( cd->sel_CB , Widget , cd->wcaller , XtPointer , cd->sel_cd , MCW_choose_cbs * , &cbs ) ; #endif free((void *)vec) ; cbs.cval = NULL ; if( !done ) MCW_invert_widget(w) ; /* flash */ } EXRETURN ; } /*.....................*/ case mcwCT_ovcolor:{ /* color chooser */ Boolean done , call ; done = strcmp(wname,OVC_apply_label) != 0 ; call = strcmp(wname,OVC_quit_label) != 0 ; if( done ) RWC_XtPopdown( cd->wpop ) ; if( call ){ cbs.reason = mcwCR_ovcolor ; /* set structure for call to user */ cbs.event = icbs->event ; cbs.ival = cd->av->ival ; if( !done ) MCW_invert_widget(w) ; /* flash */ #if 0 cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */ #else AFNI_CALL_VOID_3ARG( cd->sel_CB , Widget , cd->wcaller , XtPointer , cd->sel_cd , MCW_choose_cbs * , &cbs ) ; #endif if( !done ) MCW_invert_widget(w) ; /* flash */ } EXRETURN ; } /*.....................*/ case mcwCT_integer:{ /* integer chooser */ Boolean done , call , flash ; done = strcmp(wname,OVC_apply_label) != 0 ; /* done unless just "Apply" */ flash = ! done ; /* flash if not done */ call = strcmp(wname,OVC_quit_label) != 0 ; /* call unless just "Quit" */ if( w == cd->wchoice ){ /* Double click in List */ done = (list_dbclick_use == LIST_DBCLICK_DONE) ; flash = False ; call = True ; } if( done ) RWC_XtPopdown( cd->wpop ) ; if( call ){ int pos_count=0 , * pos_list=NULL , ib ; Boolean any ; cbs.reason = mcwCR_integer ; /* set structure for call to user */ cbs.event = icbs->event ; if( cd->av != NULL ){ /* chooser was an arrowval */ cbs.ival = cd->av->ival ; cbs.fval = cd->av->fval ; /* 21 Jan 1997 */ cbs.nilist = 1 ; cbs.ilist = &(cbs.ival) ; } else { /* chooser was a List widget */ any = XmListGetSelectedPos( cd->wchoice, &pos_list, &pos_count ) ; if( any ){ for( ib=0 ; ib < pos_count ; ib++ ) /* List indexes */ pos_list[ib]-- ; /* start at 1. */ cbs.ival = pos_list[0] ; /* holds the first choice */ cbs.fval = cbs.ival ; /* 21 Jan 1997 */ cbs.nilist = pos_count ; /* number of choices */ cbs.ilist = pos_list ; /* holds all choices */ } else { EXRETURN ; /* no choice made */ } } if( flash ) MCW_invert_widget(w) ; /* flash */ #if 0 cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */ #else AFNI_CALL_VOID_3ARG( cd->sel_CB , Widget , cd->wcaller , XtPointer , cd->sel_cd , MCW_choose_cbs * , &cbs ) ; #endif if( flash ) MCW_invert_widget(w) ; /* flash */ myXtFree(pos_list) ; } EXRETURN ; } /*.....................*/ case mcwCT_string:{ /* string chooser */ Boolean done , call , istextf ; /* special action: "Clear" button */ if( clear ){ TEXT_SET( cd->wchoice , "" ) ; EXRETURN ; } /* find out if called by the text field itself */ istextf = XtIsSubclass( w , TEXT_CLASS ) ; if( istextf == False ){ /* check button names */ done = strcmp(wname,OVC_apply_label) != 0 ; /* to decide upon */ call = strcmp(wname,OVC_quit_label) != 0 ; /* correct actions */ } else { done = False ; /* input from textfield == press "Apply" */ call = True ; } if( done ) RWC_XtPopdown( cd->wpop ) ; if( call ){ cbs.reason = mcwCR_string ; /* set structure for call to user */ cbs.event = icbs->event ; cbs.cval = TEXT_GET( cd->wchoice ) ; if( !done ) MCW_invert_widget(w) ; /* flash */ #if 0 cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */ #else AFNI_CALL_VOID_3ARG( cd->sel_CB , Widget , cd->wcaller , XtPointer , cd->sel_cd , MCW_choose_cbs * , &cbs ) ; #endif if( !done ) MCW_invert_widget(w) ; /* flash */ myXtFree( cbs.cval ) ; cbs.cval = NULL ; } EXRETURN ; } /*.....................*/ case mcwCT_timeseries:{ /* timeseries chooser */ Boolean done , call , flash , any , plot ; int pos_count , * pos_list ; #ifdef AFNI_DEBUG printf("MCW_choose_CB: timeseries choice made\n") ; #endif if( w == cd->wchoice ){ /* choice is from double click in List widget */ done = (list_dbclick_use == LIST_DBCLICK_DONE) ; flash = False ; plot = False ; call = True ; } else { /* choice is from control buttons */ done = (strcmp(wname,TSC_quit_label) == 0) || /* are we done with */ (strcmp(wname,TSC_done_label) == 0) ; /* this popup widget? */ flash = ! done ; /* flash if not done */ call = (strcmp(wname,TSC_apply_label) == 0) || /* do we call the */ (strcmp(wname,TSC_done_label) == 0) ; /* user's routine? */ plot = (strcmp(wname,TSC_plot_label) == 0) ; /* do we plot a graph? */ } #ifdef BBOX_DEBUG printf("MCW_choose_CB: done=%d call=%d plot=%d flash=%d\n", (int)done , (int)call , (int)plot , (int)flash ) ; #endif if( done ) RWC_XtPopdown( cd->wpop ) ; if( call || plot ){ /* must find out what is selected */ int pos_count , * pos_list , first ; MRI_IMAGE * fim ; #ifdef BBOX_DEBUG printf("MCW_choose_CB: querying list for choice\n") ; #endif any = XmListGetSelectedPos( cd->wchoice , &pos_list , &pos_count ) ; #ifdef BBOX_DEBUG printf("MCW_choose_CB: queryed list for choice\n") ; #endif if( any ){ first = pos_list[0] - 1 ; /* XmList index starts at 1 */ fim = IMARR_SUBIMAGE(cd->tsarr,first) ; myXtFree(pos_list) ; } else { /* no choice made --> nothing to do! */ if( plot ) XBell( XtDisplay(w) , 100 ) ; EXRETURN ; } #ifdef BBOX_DEBUG printf("MCW_choose_CB: choice index = %d\n",first) ; #endif if( call ){ cbs.reason = mcwCR_timeseries ; /* set structure for call to user */ cbs.event = icbs->event ; cbs.ival = first ; cbs.imval = fim ; #ifdef BBOX_DEBUG printf("MCW_choose_CB: calling user supplied routine\n") ; #endif if( flash ) MCW_invert_widget(w) ; /* flash */ #if 0 cd->sel_CB( cd->wcaller , cd->sel_cd , &cbs ) ; /* call user */ #else AFNI_CALL_VOID_3ARG( cd->sel_CB , Widget , cd->wcaller , XtPointer , cd->sel_cd , MCW_choose_cbs * , &cbs ) ; #endif if( flash ) MCW_invert_widget(w) ; /* flash */ EXRETURN ; } if( plot ){ #ifdef BBOX_DEBUG printf("MCW_choose_CB: plotting selected timeseries\n") ; #endif /*-- 17 Aug 1998: plotting code (at last!) --*/ #ifdef DONT_USE_COXPLOT (void) MCW_popup_message( w , "Plot not yet\nimplemented." , MCW_USER_KILL | MCW_TIMER_KILL ) ; EXRETURN ; #else if( fim->kind != MRI_float ){ (void) MCW_popup_message( w , "Can't plot\nnon-float data!" , MCW_USER_KILL | MCW_TIMER_KILL ) ; EXRETURN ; } else { float ** yar , * far = MRI_FLOAT_PTR(fim) ; char ** nar=NULL ; int jj ; #undef USE_NAR /* use labels for each column? (just to test the code) */ yar = (float **) malloc( sizeof(float *) * fim->ny ) ; for( jj=0 ; jj < fim->ny ; jj++ ) yar[jj] = far + jj * fim->nx ; #ifdef USE_NAR nar = (char **) malloc( sizeof(char * ) * fim->ny ) ; for( jj=0 ; jj < fim->ny ; jj++ ){ nar[jj] = (char *) malloc( sizeof(char) * 32 ) ; sprintf(nar[jj],"column %d",jj+1) ; } #endif plot_ts_lab( XtDisplay(w) , fim->nx , NULL , fim->ny , yar , "index" , NULL , fim->name , nar , NULL ) ; if( nar != NULL ){ for( jj=0 ; jj < fim->ny ; jj++ ) free(nar[jj]) ; free(nar) ; } free(yar) ; EXRETURN ; } #endif /* DONT_USE_COXPLOT */ } } EXRETURN ; } } /* end of switch on ctype */ EXRETURN ; /* unreachable */ }