Skip to content

AFNI/NIfTI Server

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

Doxygen Source Code Documentation


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

SUMA_display.c

Go to the documentation of this file.
00001 #include "SUMA_suma.h"
00002  
00003 /* the method for hiding a surface viewer (and other controllers), used to have three options prior to Fri Jan  3 10:21:52 EST 2003
00004 Now only SUMA_USE_WITHDRAW and NOT SUMA_USE_DESTROY should be used*/
00005 #define SUMA_USE_WITHDRAW
00006 
00007 extern SUMA_SurfaceViewer *SUMAg_SVv; /*!< Global pointer to the vector containing the various Surface Viewer Structures 
00008                                     SUMAg_SVv contains SUMA_MAX_SURF_VIEWERS structures */
00009 extern int SUMAg_N_SVv; /*!< Number of SVs realized by X  */
00010 /* extern SUMA_SurfaceViewer *SUMAg_cSV; */ /* This variable is no longer used in this file Tue Aug 13 15:27:53 EDT 2002*/ 
00011 extern int SUMAg_N_DOv; 
00012 extern SUMA_DO *SUMAg_DOv;
00013 extern SUMA_CommonFields *SUMAg_CF; 
00014 
00015 /*! Parts of the code in this file are based on code from the motif programming manual.
00016     This fact is mentioned at relevant spots in the code but the complete copyright 
00017     notice is only copied here for brevity:
00018        * Written by Dan Heller and Paula Ferguson.  
00019        * Copyright 1994, O'Reilly & Associates, Inc.
00020        * Permission to use, copy, and modify this program without
00021        * restriction is hereby granted, as long as this copyright
00022        * notice appears in each copy of the program source code.
00023        * This program is freely distributable without licensing fees and
00024        * is provided without guarantee or warrantee expressed or implied.
00025        * This program is -not- in the public domain.
00026 */
00027 
00028 /*! Widget initialization */
00029 static int snglBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16,
00030    GLX_RED_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_GREEN_SIZE, 1,  None};
00031 static int dblBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16,
00032   GLX_RED_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_DOUBLEBUFFER, None};
00033 
00034 static String fallbackResources_default[] = {
00035    "*glxarea*width: 300", "*glxarea*height: 300",
00036    "*frame*x: 20", "*frame*y: 20",
00037    "*frame*topOffset: 20", "*frame*bottomOffset: 20",
00038    "*frame*rightOffset: 20", "*frame*leftOffset: 20",
00039    "*frame*shadowType: SHADOW_IN", 
00040    "*fontList:              9x15bold=charset1"    ,
00041    "*pbar*fontList:         6x10=charset1"        ,
00042    "*imseq*fontList:        7x13=charset1"        ,
00043    "*background:            gray50"               ,
00044    "*menu*background:       gray30"               ,
00045    "*borderColor:           gray30"               ,
00046    "*foreground:            black"               ,
00047    "*borderWidth:           0"                    ,
00048    "*troughColor:           green"                ,
00049    "*XmLabel.translations:  #override<Btn2Down>:" , /* Motif 2.0 bug */
00050    "*help*background:       black"                ,
00051    "*help*foreground:       yellow"               ,
00052    "*help*helpborder:       False"                ,
00053    "*help*waitPeriod:       1066"                 ,
00054    "*help*fontList:         9x15bold=charset1"    ,
00055    "*cluefont:              9x15bold"             ,
00056    "*help*cancelWaitPeriod: 50"                   ,
00057   NULL
00058 }; /* if you change default width and height, make sure you change SV->X->WIDTH & SV->X->HEIGHT in SUMA_SVmanip */
00059 
00060 static String fallbackResources_AFNI[] = {
00061    "*glxarea*width: 300", "*glxarea*height: 300",
00062    "*frame*x: 20", "*frame*y: 20",
00063    "*frame*topOffset: 20", "*frame*bottomOffset: 20",
00064    "*frame*rightOffset: 20", "*frame*leftOffset: 20",
00065    "*frame*shadowType: SHADOW_IN", 
00066    "*fontList:              9x15bold=charset1"    ,
00067    "*pbar*fontList:         6x10=charset1"        ,
00068    "*imseq*fontList:        7x13=charset1"        ,
00069    "*background:            gray30"               ,
00070    "*menu*background:       gray30"               ,
00071    "*borderColor:           gray30"               ,
00072    "*foreground:            yellow"               ,
00073    "*borderWidth:           0"                    ,
00074    "*troughColor:           green"                ,
00075    "*XmLabel.translations:  #override<Btn2Down>:" , /* Motif 2.0 bug */
00076    "*help*background:       black"                ,
00077    "*help*foreground:       yellow"               ,
00078    "*help*helpborder:       False"                ,
00079    "*help*waitPeriod:       1066"                 ,
00080    "*help*fontList:         9x15bold=charset1"    ,
00081    "*cluefont:              9x15bold"             ,
00082    "*help*cancelWaitPeriod: 50"                   ,
00083   NULL
00084 }; /* if you change default width and height, make sure you change SV->X->WIDTH & SV->X->HEIGHT in SUMA_SVmanip */
00085 
00086 static String fallbackResources_EURO[] = {
00087    "*glxarea*width: 300", "*glxarea*height: 300",
00088    "*frame*x: 20", "*frame*y: 20",
00089    "*frame*topOffset: 20", "*frame*bottomOffset: 20",
00090    "*frame*rightOffset: 20", "*frame*leftOffset: 20",
00091    "*frame*shadowType: SHADOW_IN", 
00092    "*fontList:              9x15=charset1"    ,
00093    "*pbar*fontList:         6x10=charset1"        ,
00094    "*imseq*fontList:        7x13=charset1"        ,
00095    "*background:            black"               ,
00096    "*menu*background:       gray70"               ,
00097    "*borderColor:           gray70"               ,
00098    "*foreground:            white"               ,
00099    "*borderWidth:           0"                    ,
00100    "*troughColor:           LightCyan2"                ,
00101    "*XmLabel.translations:  #override<Btn2Down>:" , /* Motif 2.0 bug */
00102    "*help*background:       black"                ,
00103    "*help*foreground:       yellow"               ,
00104    "*help*helpborder:       False"                ,
00105    "*help*waitPeriod:       1066"                 ,
00106    "*help*fontList:         9x15=charset1"    ,
00107    "*cluefont:              9x15"             ,
00108    "*help*cancelWaitPeriod: 50"                   ,
00109    "*hotcolor:              blue2"               , 
00110   NULL
00111 }; /* if you change default width and height, make sure you change SV->X->WIDTH & SV->X->HEIGHT in SUMA_SVmanip */
00112 
00113 static String fallbackResources_Bonaire[] = {
00114    "*glxarea*width: 300", "*glxarea*height: 300",
00115    "*frame*x: 20", "*frame*y: 20",
00116    "*frame*topOffset: 20", "*frame*bottomOffset: 20",
00117    "*frame*rightOffset: 20", "*frame*leftOffset: 20",
00118    "*frame*shadowType: SHADOW_IN", 
00119    "*fontList:              9x15bold=charset1"    ,
00120    "*pbar*fontList:         6x10=charset1"        ,
00121    "*imseq*fontList:        7x13=charset1"        ,
00122    "*background:            navy"               ,
00123    "*menu*background:       gray30"               ,
00124    "*borderColor:           gray30"               ,
00125    "*foreground:            LightCyan2"               ,
00126    "*borderWidth:           0"                    ,
00127    "*troughColor:           green"                ,
00128    "*XmLabel.translations:  #override<Btn2Down>:" , /* Motif 2.0 bug */
00129    "*help*background:       black"                ,
00130    "*help*foreground:       yellow"               ,
00131    "*help*helpborder:       False"                ,
00132    "*help*waitPeriod:       1066"                 ,
00133    "*help*fontList:         9x15bold=charset1"    ,
00134    "*cluefont:              9x15bold"             ,
00135    "*help*cancelWaitPeriod: 50"                   ,
00136    "*hotcolor:              azure"               , 
00137   NULL
00138 }; /* if you change default width and height, make sure you change SV->X->WIDTH & SV->X->HEIGHT in SUMA_SVmanip */
00139 
00140 /*!
00141 
00142 - use matlab script readXcol to choose different color settings
00143 */
00144 
00145 String *SUMA_get_fallbackResources ()
00146 {
00147    static char FuncName[]={"SUMA_get_fallbackResources"};
00148    
00149    SUMA_ENTRY;
00150 
00151    switch (SUMAg_CF->X->X_Resources) {
00152       case SXR_Afni:
00153          SUMA_RETURN (fallbackResources_AFNI);
00154          break;
00155       case SXR_Euro:
00156          SUMA_RETURN (fallbackResources_EURO);
00157          break;
00158       case SXR_Bonaire:
00159          SUMA_RETURN (fallbackResources_Bonaire);
00160          break;
00161       case SXR_default:
00162       default:
00163          SUMA_RETURN (fallbackResources_default);
00164    }
00165 
00166 }
00167 
00168 static SUMA_Boolean PleaseDoMakeCurrent;
00169 
00170 void SUMA_SiSi_I_Insist(void)
00171 {
00172    PleaseDoMakeCurrent = YUP;
00173 }
00174 
00175 Boolean
00176 SUMA_handleRedisplay(XtPointer closure)
00177 {
00178    static char FuncName[]={"SUMA_handleRedisplay"};
00179    static int Last_isv = -1;
00180    int isv;
00181    SUMA_SurfaceViewer *sv;
00182    SUMA_Boolean LocalHead = NOPE;
00183    
00184    SUMA_ENTRY;
00185 
00186    if (LocalHead) {
00187       SUMA_REPORT_WICH_WIDGET_SV ((Widget)closure);
00188    }
00189    
00190    /* determine the surface viewer that the widget belongs to */
00191    SUMA_ANY_WIDGET2SV((Widget)closure, sv, isv);
00192    if (isv < 0) {
00193       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
00194       SUMA_RETURN(NOPE);
00195    }
00196    
00197    if (Last_isv >= 0) { /* first time function is called, no use for this variable yet */
00198       if (isv != Last_isv) {/* need to call glXMakeCurrent */
00199          if (!sv->Open) {
00200             if (LocalHead) fprintf (SUMA_STDERR, "%s: Redisplay request for a closed window. Skipping.\n", FuncName);
00201             SUMA_RETURN(NOPE);
00202          }else {
00203             PleaseDoMakeCurrent = YUP;
00204          }
00205       }
00206    } 
00207    
00208    if (PleaseDoMakeCurrent) {
00209       /* An OpenGL rendering context is a port through which all OpenGL commands pass. */
00210       /* Before rendering, a rendering context must be bound to the desired drawable using glXMakeCurrent. OpenGL rendering commands implicitly use the current bound rendering context and one drawable. Just as a
00211          program can create multiple windows, a program can create multiple OpenGL rendering contexts. But a thread can only be bound to one rendering context and drawable at a time. Once bound, OpenGL rendering can begin.
00212          glXMakeCurrent can be called again to bind to a different window and/or rendering context. */
00213       if (!glXMakeCurrent (sv->X->DPY, XtWindow((Widget)closure), sv->X->GLXCONTEXT)) {
00214                fprintf (SUMA_STDERR, "Error %s: Failed in glXMakeCurrent.\n \tContinuing ...\n", FuncName);
00215       }
00216       PleaseDoMakeCurrent = NOPE;
00217    }
00218    
00219    Last_isv = isv; /* store last surface viewer to call display */
00220    /* call display for the proper surface viewer*/
00221    if (LocalHead) fprintf (SUMA_STDERR, "%s: Calling SUMA_display with SV[%d], Pointer %p.\n", FuncName, isv, sv); 
00222    SUMA_display(sv, SUMAg_DOv);
00223    sv->X->REDISPLAYPENDING = 0;
00224    
00225    if (SUMAg_N_SVv > 1) {
00226       if (LocalHead) fprintf (SUMA_STDERR, "%s: Forcing display to finish.\n", FuncName);
00227       /* When multiple viewers are open, the picking does not work at times if you click around rapidly.
00228       The problem seems to be caused by OpenGL being in a state corresponding to that of the last viewer 
00229       visited before coming to the current viewer. Forcing gl to render after a redisplay pending for a 
00230       certain viewer is placed seems to reduce this problem significantly so this fix will be adopted
00231       until a better one comes along. This call does reduce the apparent speed of the display and might
00232       cause momentum motion to be more blocky but the overload is minimal for regular use.*/
00233       glFinish();
00234    }
00235 
00236    SUMA_RETURN(YUP);
00237 }
00238 
00239 /*!
00240 
00241 Only w is used consistently, the other input varaibles may be null at times
00242 always send GLXAREA widget in w otherwise you won't know what pointer to use with 
00243 SUMA_remove_workproc2's data
00244 \sa SUMA_remove_workproc2
00245 */
00246 void
00247 SUMA_postRedisplay(Widget w,
00248   XtPointer clientData, XtPointer call)
00249 {
00250    static char FuncName[]={"SUMA_postRedisplay"};
00251    static XtPointer elvis;
00252    int isv;
00253    SUMA_SurfaceViewer *sv;
00254    SUMA_Boolean LocalHead = NOPE;
00255    
00256    SUMA_ENTRY;
00257 
00258    /* determine the surface viewer that the widget belongs to */
00259    SUMA_ANY_WIDGET2SV(w, sv, isv);
00260    if (isv < 0) {
00261       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
00262       SUMA_RETURNe;
00263    } else {
00264       if (LocalHead) fprintf (SUMA_STDERR, "%s: Redisplay Pending registered for viewer %d.\n", FuncName, isv);
00265    }
00266 
00267    if(!sv->X->REDISPLAYPENDING) {
00268     /*sv->X->REDISPLAYID = XtAppAddWorkProc(sv->X->APP, handleRedisplay, 0);*/
00269     SUMA_register_workproc( SUMA_handleRedisplay , (XtPointer)sv->X->GLXAREA );
00270     sv->X->REDISPLAYPENDING = 1;
00271    }
00272    
00273    SUMA_RETURNe;
00274 }
00275 
00276 void SUMA_LoadSegDO (char *s, void *csvp)
00277 {
00278    static char FuncName[]={"SUMA_LoadSegDO"};
00279    SUMA_SegmentDO *SDO = NULL;
00280    SUMA_SurfaceViewer *sv;
00281    
00282    SUMA_ENTRY;
00283    
00284    sv = (SUMA_SurfaceViewer *)csvp;
00285    
00286    if (!s) { SUMA_RETURNe; }
00287    
00288    if (!(SDO = SUMA_ReadSegDO(s))) {
00289       SUMA_SL_Err("Failed to read segment file.\n");
00290       SUMA_RETURNe;
00291    }
00292    
00293    /* addDO */
00294    if (!SUMA_AddDO(SUMAg_DOv, &SUMAg_N_DOv, (void *)SDO, LS_type, SUMA_LOCAL)) {
00295       fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
00296       SUMA_RETURNe;
00297    }
00298 
00299    /* register DO with viewer */
00300    if (!SUMA_RegisterDO(SUMAg_N_DOv-1, sv)) {
00301       fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_RegisterDO.\n", FuncName);
00302       SUMA_RETURNe;
00303    }
00304 
00305    /* redisplay curent only*/
00306    sv->ResetGLStateVariables = YUP;
00307    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
00308                
00309    SUMA_RETURNe;
00310 }
00311 
00312 /*!
00313    \brief, retrieves an vector attribute
00314    and decodes it into m_fv. It is your 
00315    job to make sure m_fv is big enough 
00316    for the endeavour 
00317    m_fail is 1 if no such attribute is found
00318             2 if the number of values read is not = m_n
00319 */
00320 #define SUMA_S2FV_ATTR(m_nel, m_attr, m_fv, m_n, m_fail) {\
00321    char *m_atmp = NULL; \
00322    int m_nr = 0; \
00323    m_fail = 0; \
00324    m_atmp = NI_get_attribute(m_nel, m_attr); \
00325    if (!m_atmp) {   \
00326       fprintf(SUMA_STDERR,"Error %s:\nNo such attribute (%s).", FuncName, m_attr);  \
00327       m_fail = 1; \
00328    }  \
00329    m_nr = SUMA_StringToNum(m_atmp, m_fv, m_n);  \
00330    if (m_nr != m_n) {  \
00331       fprintf(SUMA_STDERR,"Error %s:\nBad attribute (%s) length.\nExpected %d, found %d\n",   \
00332                            FuncName, m_attr, m_n, m_nr);  \
00333       m_fail = 2; \
00334    }  \
00335 }
00336 
00337 #define SUMA_FV2S_ATTR_TMP_STR   3000
00338 /*!
00339    \brief turns a vector into a string of floats
00340    The macro will fail if your vector ends up
00341    being more than SUMA_FV2S_ATTR_TMP_STR characters long.
00342    This macro is slow and stupid, don't use it for
00343    long vectors.
00344 */
00345 #define SUMA_FV2S_ATTR(m_nel, m_attr, m_fv, m_n, m_fail) {\
00346    int m_i; \
00347    char m_stmp[SUMA_FV2S_ATTR_TMP_STR], m_val[50];   \
00348    m_fail = 0; \
00349    m_i = 0; \
00350    m_stmp[0] = '\0'; \
00351    while (m_i < m_n && !(m_fail)) { \
00352       sprintf(m_val,"%f ", m_fv[m_i]); \
00353       if (strlen(m_stmp) + strlen(m_val) >= SUMA_FV2S_ATTR_TMP_STR -1) {   \
00354          fprintf(SUMA_STDERR,"Error %s\nVector exceeded buffer length.\n", FuncName);  \
00355          m_fail = 1; \
00356       } else { \
00357          strcat (m_stmp, m_val); \
00358          ++ m_i;  \
00359       }\
00360    }  \
00361    NI_set_attribute (m_nel, m_attr, m_stmp);      \
00362 }
00363       
00364 
00365 /*!
00366    \brief   A function to save the settings of a surface viewer
00367             for later recall 
00368 */
00369 void SUMA_SaveVisualState(char *fname, void *csvp )
00370 {
00371    static char FuncName[]={"SUMA_SaveVisualState"};
00372    NI_element *nel = NULL;
00373    NI_stream nstdout;
00374    char stmp[500];
00375    char *fnamestmp=NULL, *fnamestmp2=NULL;
00376    int feyl;
00377    SUMA_SurfaceViewer *csv;
00378    SUMA_Boolean LocalHead = NOPE;
00379    
00380    SUMA_ENTRY;
00381    
00382    csv = (SUMA_SurfaceViewer *)csvp;
00383    
00384    if (!csv) { SUMA_RETURNe; }
00385    
00386    if (csv->StdView < 0 || csv->iState < 0 ) { SUMA_RETURNe; }
00387    
00388    SUMA_allow_nel_use(1);
00389    nel = SUMA_NewNel (  SUMA_VIEWER_SETTING, /* one of SUMA_DSET_TYPE */
00390                         NULL, /* idcode of Domain Parent */
00391                         NULL, /* idcode of geometry parent, not useful here*/
00392                         0,
00393                         NULL,
00394                         NULL); /* Number of elements */
00395    if (!nel) {
00396       SUMA_SL_Err("Failed to create nel.");
00397       SUMA_RETURNe;
00398    }
00399    
00400    /* Save the relevant parameters */
00401    SUMA_FV2S_ATTR(nel, "currentQuat", csv->GVS[csv->StdView].currentQuat, 4, feyl); if (feyl) { SUMA_RETURNe; }
00402    SUMA_FV2S_ATTR(nel, "translateVec", csv->GVS[csv->StdView].translateVec, 2, feyl); if (feyl) { SUMA_RETURNe; }
00403    SUMA_FV2S_ATTR(nel, "clear_color", csv->clear_color, 4, feyl); if (feyl) { SUMA_RETURNe; }
00404    sprintf(stmp, "%f", csv->FOV[csv->iState]);
00405    NI_set_attribute (nel, "FOV", stmp);
00406    sprintf(stmp, "%f", csv->Aspect);
00407    NI_set_attribute (nel, "Aspect", stmp);
00408    sprintf(stmp, "%d", csv->WindWidth);
00409    NI_set_attribute (nel, "WindWidth", stmp);
00410    sprintf(stmp, "%d", csv->WindHeight);
00411    NI_set_attribute (nel, "WindHeight", stmp);
00412    sprintf(stmp, "%d", (int)csv->BF_Cull);
00413    NI_set_attribute (nel, "BF_Cull", stmp);
00414    sprintf(stmp, "%f", csv->Back_Modfact);
00415    NI_set_attribute (nel, "Back_Modfact", stmp);
00416    sprintf(stmp, "%d", (int)csv->PolyMode);
00417    NI_set_attribute (nel, "PolyMode", stmp);
00418    sprintf(stmp, "%d", csv->ShowEyeAxis);
00419    NI_set_attribute (nel, "ShowEyeAxis", stmp);
00420    sprintf(stmp, "%d", csv->ShowMeshAxis);
00421    NI_set_attribute (nel, "ShowMeshAxis", stmp);
00422    sprintf(stmp, "%d", csv->ShowWorldAxis);
00423    NI_set_attribute (nel, "ShowWorldAxis", stmp);
00424    sprintf(stmp, "%d", csv->ShowCrossHair);
00425    NI_set_attribute (nel, "ShowCrossHair", stmp);
00426    sprintf(stmp, "%d", (int)csv->ShowForeground);
00427    NI_set_attribute (nel, "ShowForeground", stmp);
00428    sprintf(stmp, "%d", (int)csv->ShowBackground);
00429    NI_set_attribute (nel, "ShowBackground", stmp);
00430    
00431    /* write element */
00432    if (!fname) {
00433       nstdout = NI_stream_open( "file:test.niml.vvs","w");
00434    } else {
00435       fnamestmp = SUMA_append_string("file:", fname);
00436       fnamestmp2 = SUMA_Extension(fnamestmp, ".niml.vvs", NOPE);
00437       nstdout = NI_stream_open( fnamestmp2,"w");
00438       SUMA_free(fnamestmp); fnamestmp = NULL;
00439       SUMA_free(fnamestmp2); fnamestmp2 = NULL;
00440    }
00441    if( nstdout == NULL ){ 
00442       fprintf(stderr,"%s: Can't open file\n", FuncName); 
00443       SUMA_RETURNe; 
00444    }
00445    NI_write_element( nstdout , nel , NI_TEXT_MODE | NI_HEADERSHARP_FLAG) ;               
00446    NI_stream_close(nstdout);
00447    NI_free_element(nel) ; nel = NULL;
00448     
00449    SUMA_RETURNe;
00450 }
00451 
00452 /*!
00453    \brief function to load a viewer's visual state
00454 */
00455 void SUMA_LoadVisualState(char *fname, void *csvp)
00456 {
00457    static char FuncName[]={"SUMA_LoadVisualState"};
00458    NI_element *nel = NULL;
00459    int feyl;
00460    char *fnamestmp=NULL, *fnamestmp2=NULL;
00461    float quat[4], Aspect[1], FOV[1], tran[2],
00462          WindWidth[1], WindHeight[1], clear_color[4], 
00463          BF_Cull[1], Back_Modfact[1], PolyMode[1], ShowEyeAxis[1], ShowWorldAxis[1],
00464          ShowMeshAxis[1], ShowCrossHair[1], ShowForeground[1], 
00465          ShowBackground[1];   char *atmp;
00466    NI_stream nstdin;
00467    SUMA_SurfaceViewer *csv;
00468    SUMA_Boolean LocalHead = NOPE;
00469    
00470    SUMA_ENTRY;
00471    
00472    csv = (SUMA_SurfaceViewer *)csvp;
00473    if (!csv) { SUMA_RETURNe; }
00474    
00475    if (!fname) {
00476       nstdin = NI_stream_open( "file:test.niml.vvs","r");
00477    } else {
00478       fnamestmp = SUMA_append_string("file:", fname);
00479       fnamestmp2 = SUMA_Extension(fnamestmp, ".niml.vvs", NOPE);
00480       nstdin = NI_stream_open( fnamestmp2,"r");
00481       SUMA_free(fnamestmp); fnamestmp = NULL;
00482       SUMA_free(fnamestmp2); fnamestmp2 = NULL;
00483    }
00484    if( nstdin == NULL ){ 
00485       fprintf(stderr,"%s: Can't open file\n", FuncName); 
00486       SUMA_RETURNe; 
00487    }
00488    nel = NI_read_element (nstdin, 1);
00489    if (!nel) {
00490       SUMA_SL_Err("Failed to read nel.\n");
00491       SUMA_RETURNe;
00492    }
00493 
00494    /* don't crash if you fail here and there, try your best ...*/
00495    SUMA_S2FV_ATTR(nel, "currentQuat", quat, 4, feyl); if (feyl) {SUMA_BEEP};
00496    SUMA_S2FV_ATTR(nel, "translateVec", tran, 2, feyl); if (feyl) {SUMA_BEEP};
00497    SUMA_S2FV_ATTR(nel, "FOV", FOV, 1, feyl); if (feyl) {SUMA_BEEP};
00498    SUMA_S2FV_ATTR(nel, "Aspect", Aspect, 1, feyl); if (feyl) {SUMA_BEEP};
00499    SUMA_S2FV_ATTR(nel, "WindWidth", WindWidth, 1, feyl); if (feyl) {SUMA_BEEP};
00500    SUMA_S2FV_ATTR(nel, "WindHeight", WindHeight, 1, feyl); if (feyl) {SUMA_BEEP};
00501    SUMA_S2FV_ATTR(nel, "clear_color", clear_color, 4, feyl); if (feyl) {SUMA_BEEP};
00502    SUMA_S2FV_ATTR(nel, "BF_Cull", BF_Cull, 1, feyl); if (feyl) {SUMA_BEEP};
00503    SUMA_S2FV_ATTR(nel, "Back_Modfact", Back_Modfact, 1, feyl); if (feyl) {SUMA_BEEP};
00504    SUMA_S2FV_ATTR(nel, "PolyMode", PolyMode, 1, feyl); if (feyl) {SUMA_BEEP};
00505    SUMA_S2FV_ATTR(nel, "ShowEyeAxis", ShowEyeAxis, 1, feyl); if (feyl) {SUMA_BEEP};
00506    SUMA_S2FV_ATTR(nel, "ShowMeshAxis", ShowMeshAxis, 1, feyl); if (feyl) {SUMA_BEEP};
00507    SUMA_S2FV_ATTR(nel, "ShowWorldAxis", ShowWorldAxis, 1, feyl); if (feyl) {SUMA_BEEP};
00508    SUMA_S2FV_ATTR(nel, "ShowCrossHair", ShowCrossHair, 1, feyl); if (feyl) {SUMA_BEEP};
00509    SUMA_S2FV_ATTR(nel, "ShowForeground", ShowForeground, 1, feyl); if (feyl) {SUMA_BEEP};
00510    SUMA_S2FV_ATTR(nel, "ShowBackground", ShowBackground, 1, feyl); if (feyl) {SUMA_BEEP};
00511    
00512    NI_free_element(nel); nel = NULL;
00513    NI_stream_close(nstdin); 
00514    
00515    /* set the values */
00516    SUMA_COPY_VEC(quat, csv->GVS[csv->StdView].currentQuat, 4, float, float);
00517    SUMA_COPY_VEC(tran, csv->GVS[csv->StdView].translateVec, 2, float, float);
00518    csv->FOV[csv->iState] = FOV[0];
00519    csv->Aspect = Aspect[0]; /* That gets recalculated when SUMA_resize is called */
00520    csv->WindWidth = (int)WindWidth[0]; /* That gets recalculated when SUMA_resize is called */
00521    csv->WindHeight = (int)WindHeight[0]; /* That gets recalculated when SUMA_resize is called */
00522    SUMA_COPY_VEC(clear_color, csv->clear_color, 4, float, float);
00523    csv->BF_Cull = (SUMA_Boolean)BF_Cull[0];
00524    csv->Back_Modfact = Back_Modfact[0];
00525    csv->PolyMode = (SUMA_RENDER_MODES)PolyMode[0];
00526    csv->ShowEyeAxis = (int)ShowEyeAxis[0];
00527    csv->ShowMeshAxis = (int)ShowMeshAxis[0];
00528    csv->ShowWorldAxis = (int)ShowWorldAxis[0];
00529    csv->ShowCrossHair = (int)ShowCrossHair[0];
00530    csv->ShowForeground = (SUMA_Boolean)ShowForeground[0];
00531    csv->ShowForeground = (SUMA_Boolean)ShowForeground[0];
00532    
00533    /* do a resize (does not matter if dimensions did not change, call is simple.
00534    This call will also generate a SUMA_resize call */
00535    SUMA_WidgetResize (csv->X->TOPLEVEL , csv->WindWidth, csv->WindHeight); 
00536 
00537 
00538    SUMA_RETURNe;
00539 }
00540 
00541 void SUMA_display(SUMA_SurfaceViewer *csv, SUMA_DO *dov)
00542 {   
00543    int i;
00544    static int xList[1], yList[1];
00545    SUMA_SurfaceObject *SO=NULL;
00546    GLfloat rotationMatrix[4][4];
00547    static char FuncName[]={"SUMA_display"};
00548    SUMA_Boolean LocalHead = NOPE; /* local headline debugging messages */   
00549     
00550    SUMA_ENTRY;
00551    
00552    /* now you need to set the clear_color since it can be changed per viewer Thu Dec 12 2002 */
00553    glClearColor (csv->clear_color[0], csv->clear_color[1], csv->clear_color[2], csv->clear_color[3]);
00554    
00555    if (csv->NewGeom) { 
00556       /* This function makes calls that are repeated in SUMA_OpenGLStateReset */
00557       SUMA_NewGeometryInViewer(SUMAg_DOv, SUMAg_N_DOv, csv);
00558       csv->NewGeom = NOPE;
00559       csv->ResetGLStateVariables = NOPE; /*  SUMA_NewGeometryInViewer contains SUMA_OpenGLStateReset
00560                                              stuff and lots more ...*/
00561    } else {
00562       /* You cannot just rely on csv->ResetGLStateVariables because it is hard to set 
00563       for all conditions. For example, if you have multiple viewers open and you have surfaces 
00564       moving on momentum in all viewers, then you will have to call SUMA_OpenGLStateReset before
00565       each display otherwise the openGL settings for one of them will affect the others.
00566       At any rate, that function is not costly to run so there's no harm in running it anytime
00567       you have a display call and more than one viewer open */ 
00568 
00569       if (SUMAg_N_SVv > 1 || csv->ResetGLStateVariables) {
00570          if (LocalHead) fprintf(SUMA_STDERR, "%s: Calling SUMA_OpenGLStateReset.\n", FuncName);
00571          SUMA_OpenGLStateReset (SUMAg_DOv, SUMAg_N_DOv, csv);
00572          csv->ResetGLStateVariables = NOPE;
00573       }
00574    }
00575    
00576    /* calculate Pcenter_close for the axis positioning */
00577    if (csv->ShowMeshAxis || csv->ShowWorldAxis) {
00578       yList[0] = csv->WindHeight;
00579       xList[0] = 0;
00580       SUMA_GetSelectionLine (csv, csv->WindWidth/2, csv->WindHeight/2, csv->Pcenter_close, csv->Pcenter_far, 1, xList, yList, csv->Plist_close);
00581    }
00582    /* decide on color mixing needs */
00583    if (!SUMA_MixColors (csv)) {
00584       fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_MixColors. Aborting.\n", FuncName);
00585       exit(1);
00586    }
00587    
00588    if (LocalHead) fprintf (SUMA_STDOUT,"%s: Building Rotation matrix ...\n", FuncName);
00589    SUMA_build_rotmatrix(rotationMatrix, csv->GVS[csv->StdView].currentQuat);
00590     
00591    if (LocalHead) fprintf (SUMA_STDOUT,"%s: performing glClear ...\n", FuncName);
00592    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* clear the Color Buffer and the depth buffer */
00593    
00594    SUMA_SET_GL_PROJECTION(csv);
00595    
00596 
00597    /* cycle through csv->RegisteredDO and display those things that have a fixed CoordType*/
00598    if (LocalHead) fprintf (SUMA_STDOUT,"%s: Creating objects with fixed coordinates ...\n", FuncName);
00599    i = 0;
00600    while (i < csv->N_DO) {
00601       if (dov[csv->RegisteredDO[i]].CoordType == SUMA_SCREEN) {
00602          switch (dov[csv->RegisteredDO[i]].ObjectType) {
00603             case SO_type:
00604                break;
00605             case AO_type:
00606                if (csv->ShowEyeAxis){
00607                   if (!SUMA_DrawAxis ((SUMA_Axis*)dov[csv->RegisteredDO[i]].OP, csv)) {
00608                      fprintf(SUMA_STDERR,"Error %s: Could not display EYE AXIS\n", FuncName);
00609                   }
00610                }
00611                break;
00612             case GO_type:
00613                break;
00614             case ROIdO_type:
00615                /* those are drawn by SUMA_DrawMesh */
00616                break;
00617             case ROIO_type:
00618                /* those are drawn by SUMA_DrawMesh */
00619                break;
00620             case LS_type:
00621                if (!SUMA_DrawSegmentDO ((SUMA_SegmentDO *)dov[csv->RegisteredDO[i]].OP)) {
00622                   fprintf(SUMA_STDERR, "Error %s: Failed in SUMA_DrawSegmentDO.\n", FuncName);
00623                }
00624                break;
00625          }
00626       }
00627       ++i;
00628    }
00629    
00630    SUMA_SET_GL_MODELVIEW(csv);
00631 
00632    /* cycle through csv->RegisteredDO and display those things that have a Local CoordType*/
00633    if (LocalHead) fprintf (SUMA_STDOUT,"%s: Creating objects with local coordinates ...\n", FuncName);
00634 
00635    i = 0;
00636    while (i < csv->N_DO) {
00637       if (dov[csv->RegisteredDO[i]].CoordType == SUMA_LOCAL) {
00638          switch (dov[csv->RegisteredDO[i]].ObjectType) {
00639             case SO_type:
00640                SO = (SUMA_SurfaceObject *)dov[csv->RegisteredDO[i]].OP;
00641                if (SO->Show) {
00642                   if (  (SO->Side == SUMA_LEFT && csv->ShowLeft) || 
00643                         (SO->Side == SUMA_RIGHT && csv->ShowRight) ||
00644                         SO->Side == SUMA_NO_SIDE) {
00645                         SUMA_DrawMesh(SO, csv); /* create the surface */
00646                   }
00647                }
00648                break;
00649             case AO_type:
00650                if (csv->ShowMeshAxis) {
00651                   if (!SUMA_DrawAxis ((SUMA_Axis*)dov[csv->RegisteredDO[i]].OP, csv)) {
00652                      fprintf(stderr,"display error: Could not display Mesh AXIS\n");
00653                   }
00654                }
00655                break;
00656             case GO_type:
00657                break;
00658             case ROIdO_type:
00659                /* those are drawn by SUMA_DrawMesh */
00660                break;
00661             case ROIO_type:
00662                /* those are drawn by SUMA_DrawMesh */
00663                break;
00664             case LS_type:
00665                if (!SUMA_DrawSegmentDO ((SUMA_SegmentDO *)dov[csv->RegisteredDO[i]].OP)) {
00666                   fprintf(SUMA_STDERR, "Error %s: Failed in SUMA_DrawSegmentDO.\n", FuncName);
00667                }
00668                break;
00669          }
00670       }
00671       ++i;
00672    }
00673    
00674    /* Show the Cross Hair, if required */
00675    if (csv->ShowCrossHair) {
00676       /*fprintf(SUMA_STDOUT,"Showing Cross Hair \n");*/
00677       if (!SUMA_DrawCrossHair (csv->Ch)) {
00678          fprintf(stderr,"display error: Failed to Create Cross Hair\n");
00679       }
00680    }
00681    
00682    /* Show the World Axis if required */
00683    if (csv->ShowWorldAxis) {
00684       /* fprintf(SUMA_STDOUT,"Showing World Axis \n");  */
00685       if (!SUMA_DrawAxis (csv->WAx, csv)) {
00686          fprintf(stderr,"display error: Failed to Create WAx\n");
00687       }
00688    }
00689 
00690 
00691    #if 0
00692    /* Show the pick line, you may want place this as a DO later on */
00693     {
00694       static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
00695       static GLfloat LineColor[] = {1.0, 0.0, 1.0, 0.0};
00696       glLineWidth(1.0);
00697       glEnable(GL_LINE_STIPPLE);
00698       glLineStipple (1, 0x1C47); /* dashed, see OpenGL Prog guide, page 55 */
00699       glBegin(GL_LINES);
00700       glMaterialfv(GL_FRONT, GL_EMISSION, LineColor); /*turn on emissivity for axis*/
00701       glVertex3f(csv->Pick0[0], csv->Pick0[1], csv->Pick0[2]);
00702       glVertex3f(csv->Pick1[0], csv->Pick1[1], csv->Pick1[2]);
00703       glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity for axis*/
00704       glEnd();
00705       glDisable(GL_LINE_STIPPLE);
00706    }
00707    #endif
00708       
00709    glPopMatrix();   
00710 
00711    if (LocalHead) fprintf (SUMA_STDOUT,"%s: Flushing or swapping ...\n", FuncName);
00712    if (csv->X->DOUBLEBUFFER)
00713     glXSwapBuffers(csv->X->DPY, XtWindow(csv->X->GLXAREA));
00714    else
00715     glFlush();
00716 
00717   /* Avoid indirect rendering latency from queuing. */
00718   if (!glXIsDirect(csv->X->DPY, csv->X->GLXCONTEXT))
00719     glFinish();
00720   
00721   /* if recording, take a snap */
00722   if (csv->Record) {
00723       if (csv->rdc < SUMA_RDC_X_START || csv->rdc > SUMA_RDC_X_END) {
00724          glFinish();
00725          glXWaitX();
00726       #ifdef DARWIN
00727          { GLvoid *pixels;
00728            pixels = SUMA_grabPixels(1, csv->X->WIDTH, csv->X->HEIGHT);
00729            if (pixels) {
00730              ISQ_snapsave( csv->X->WIDTH, -csv->X->HEIGHT,
00731                            (unsigned char *)pixels, csv->X->GLXAREA );
00732              SUMA_free(pixels);
00733            }
00734          }
00735       #else
00736          ISQ_snapshot ( csv->X->GLXAREA );
00737       #endif
00738       }
00739   }
00740   
00741   /* reset rdc, if it is the last thing you'll ever do */
00742   csv->rdc = SUMA_RDC_NOT_SET;
00743   
00744    SUMA_RETURNe;
00745 }
00746 
00747 void
00748 SUMA_graphicsInit(Widget w, XtPointer clientData, XtPointer call)
00749 {
00750    
00751    XVisualInfo *SUMAg_cVISINFO;
00752    static char FuncName[]={"SUMA_graphicsInit"};
00753    int isv;
00754    SUMA_SurfaceViewer *sv;
00755    
00756    SUMA_ENTRY;
00757 
00758    /* determine the surface viewer that the widget belongs to */
00759    SUMA_ANY_WIDGET2SV((Widget)w, sv, isv);
00760    if (isv < 0) {
00761       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
00762       SUMA_RETURNe;
00763    }
00764 
00765    /* Create OpenGL rendering context. */
00766    XtVaGetValues(w, GLwNvisualInfo, &SUMAg_cVISINFO, NULL);
00767    sv->X->GLXCONTEXT = glXCreateContext(XtDisplay(w), SUMAg_cVISINFO,
00768     0,                  /* No sharing. */
00769     True);              /* Direct rendering if possible. */
00770 
00771    /* Setup OpenGL state. */
00772    if (!glXMakeCurrent(XtDisplay(w), XtWindow(w), sv->X->GLXCONTEXT)) {
00773       fprintf (SUMA_STDERR, "Error %s: Failed in glXMakeCurrent.\n \tContinuing ...\n", FuncName);
00774    }
00775    
00776    /* call context_Init to setup colors and lighting */   
00777    SUMA_context_Init(sv);
00778 
00779    SUMA_RETURNe;
00780    
00781 }
00782 
00783 void 
00784 SUMA_context_Init(SUMA_SurfaceViewer *sv)
00785 {
00786    static char FuncName[]={"SUMA_context_Init"};
00787    GLfloat mat_specular[] = { SUMA_MAT_SPECULAR_INIT};
00788    GLfloat mat_shininess[] = { SUMA_MAT_SHININESS_INIT };
00789    GLfloat mat_ambient[] = { SUMA_MAT_AMBIENT_INIT};
00790    GLfloat mat_diffuse[] = { SUMA_MAT_DIFFUSE_INIT };
00791    GLfloat mat_emission[] = { SUMA_MAT_EMISSION_INIT  };
00792    
00793    GLfloat light0_color[] = { SUMA_LIGHT0_COLOR_INIT};
00794    /*GLfloat green_light[] = { 0.0, 1.0, 0.0, 1.0};*/
00795    
00796    GLfloat lmodel_ambient[] = {SUMA_LMODEL_AMBIENT};
00797 
00798    SUMA_ENTRY;
00799 
00800    glClearColor (sv->clear_color[0], sv->clear_color[1], sv->clear_color[2], sv->clear_color[3]);
00801    glShadeModel (GL_SMOOTH);
00802 
00803    SUMA_SET_GL_RENDER_MODE(sv->PolyMode); 
00804    
00805       
00806    /* Set the material properties*/
00807    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
00808    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
00809    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
00810    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
00811    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
00812    
00813    /* set the directional light properties */
00814    glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
00815    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
00816    glLightfv(GL_LIGHT0, GL_SPECULAR, light0_color);
00817 
00818    /*glLightfv(GL_LIGHT1, GL_POSITION, sv->light1_position);
00819    glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
00820    glLightfv(GL_LIGHT1, GL_SPECULAR, green_light);*/
00821    
00822    /* set the ambient light */
00823    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
00824  
00825    glEnable(GL_LIGHTING); /* prepare GL to perform lighting calculations */
00826    glEnable(GL_LIGHT0); /*Turn lights ON */
00827    /*glEnable(GL_LIGHT1); */
00828    glEnable(GL_DEPTH_TEST);
00829    /* back face culling does not work with SureFit surfaces since facesets are not all defined clockwise or counter clockwise */
00830    /* also back face culling won't light up the interior of a surface, which is nice to have at times. Like occip patches for example */
00831    if (sv->BF_Cull) {
00832       glCullFace (GL_BACK);
00833       glEnable (GL_CULL_FACE);
00834    }
00835    
00836    /*setup the view point and then setup the lights. Those lights will remain in place regardless of the rotations/translations
00837    done on the surface */
00838    glMatrixMode(GL_MODELVIEW);
00839    glLoadIdentity();
00840    gluLookAt (   sv->GVS[sv->StdView].ViewFrom[0], sv->GVS[sv->StdView].ViewFrom[1], 
00841                sv->GVS[sv->StdView].ViewFrom[2], sv->GVS[sv->StdView].ViewCenter[0], 
00842                sv->GVS[sv->StdView].ViewCenter[1], sv->GVS[sv->StdView].ViewCenter[2], 
00843                sv->GVS[sv->StdView].ViewCamUp[0], sv->GVS[sv->StdView].ViewCamUp[1], 
00844                sv->GVS[sv->StdView].ViewCamUp[2] );
00845 
00846    /*glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);*/
00847    /*glLightfv(GL_LIGHT1, GL_POSITION, sv->light1_position);*/
00848 
00849    SUMA_RETURNe;
00850 
00851 }
00852 
00853    
00854 void
00855 SUMA_resize(Widget w,
00856   XtPointer clientData, XtPointer call)
00857 {
00858    static char FuncName[]={"SUMA_resize"};
00859    GLwDrawingAreaCallbackStruct *callData;
00860    SUMA_SurfaceViewer *sv;
00861    int isv;
00862    
00863    SUMA_ENTRY;
00864 
00865    /* determine the surface viewer that the widget belongs to */
00866    SUMA_ANY_WIDGET2SV(w, sv, isv);
00867    if (isv < 0) {
00868       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
00869       SUMA_RETURNe;
00870    }
00871 
00872    /*   fprintf(stdout, "Resizn'...\n");*/
00873    callData = (GLwDrawingAreaCallbackStruct *) call;
00874    if (!glXMakeCurrent(XtDisplay(w), XtWindow(w), sv->X->GLXCONTEXT)) {
00875       fprintf (SUMA_STDERR, "Error %s: Failed in glXMakeCurrent.\n \tContinuing ...\n", FuncName);
00876    }
00877 
00878    glXWaitX();
00879    sv->X->WIDTH = callData->width;
00880    sv->X->HEIGHT = callData->height;
00881    glViewport(0, 0, callData->width, callData->height);
00882 
00883    glMatrixMode(GL_MODELVIEW);
00884    glLoadIdentity();
00885    gluLookAt (   sv->GVS[sv->StdView].ViewFrom[0], sv->GVS[sv->StdView].ViewFrom[1], 
00886                sv->GVS[sv->StdView].ViewFrom[2], sv->GVS[sv->StdView].ViewCenter[0], 
00887                sv->GVS[sv->StdView].ViewCenter[1], sv->GVS[sv->StdView].ViewCenter[2], 
00888                sv->GVS[sv->StdView].ViewCamUp[0], sv->GVS[sv->StdView].ViewCamUp[1], 
00889                sv->GVS[sv->StdView].ViewCamUp[2]);
00890    sv->Aspect = (GLfloat) callData->width/(GLfloat) callData->height;
00891    sv->WindWidth = callData->width; sv->WindHeight = callData->height;
00892    
00893    sv->rdc = SUMA_RDC_X_RESIZE;
00894    SUMA_postRedisplay(w, clientData, call);
00895    
00896    SUMA_RETURNe;
00897 }
00898 
00899 
00900 void
00901 SUMA_expose(Widget w,
00902   XtPointer clientData, XtPointer call)
00903 {
00904   static char FuncName[]={"SUMA_expose"};
00905   int isv;
00906   SUMA_SurfaceViewer *sv;
00907   SUMA_Boolean LocalHead = NOPE;
00908   
00909    SUMA_LH("Called");
00910   /*glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);*/ /* No need for that, done in display */
00911   
00912   
00913    /* get the viewer just entered. */
00914    SUMA_ANY_WIDGET2SV(w, sv, isv);
00915    if (isv < 0) {
00916       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
00917       SUMA_RETURNe;
00918    }
00919    
00920    sv->rdc = SUMA_RDC_X_EXPOSE;
00921    
00922    /* When using multiple viewers, you must reset the OpenGL state variables or risk having abrupt changes with the first click */
00923    sv->ResetGLStateVariables = YUP;
00924    SUMA_postRedisplay(w, NULL, NULL);
00925 
00926 }
00927 
00928 void
00929 SUMA_mapStateChanged(Widget w, XtPointer clientData,
00930   XEvent * event, Boolean * cont)
00931 {
00932 
00933    static char FuncName[]={"SUMA_mapStateChanged"};
00934    int isv;
00935    SUMA_SurfaceViewer *sv;
00936    SUMA_Boolean LocalHead = NOPE;
00937    
00938    SUMA_ENTRY;
00939    
00940    SUMA_LH("Called");
00941    
00942    /* determine the surface viewer that the widget belongs to */
00943    SUMA_ANY_WIDGET2SV(w, sv, isv);
00944    if (isv < 0) {
00945       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
00946       SUMA_RETURNe;
00947    }
00948 
00949    sv->rdc = SUMA_RDC_X_MAPSTATE;
00950    
00951    /* When using multiple viewers, you must reset the OpenGL state variables or risk having abrupt changes with the first click */
00952    sv->ResetGLStateVariables = YUP;
00953 
00954    /*fprintf(stdout, "widget window being mapped/unmapped\n");*/
00955    switch (event->type) {
00956    case MapNotify:
00957       sv->isShaded = NOPE;
00958       if (sv->GVS[sv->StdView].ApplyMomentum)
00959          sv->X->MOMENTUMID = XtAppAddTimeOut(SUMAg_CF->X->App, 1, SUMA_momentum, (XtPointer)w);
00960       break;
00961    case UnmapNotify:
00962       sv->isShaded = YUP;
00963       if (sv->GVS[sv->StdView].ApplyMomentum) {
00964          if (sv->X->MOMENTUMID) XtRemoveTimeOut(sv->X->MOMENTUMID);
00965          sv->X->MOMENTUMID = 0;
00966       }
00967       break;
00968    }
00969   
00970   SUMA_postRedisplay(w, clientData, NULL);
00971   
00972   SUMA_RETURNe;
00973 }
00974 
00975 /*! 
00976 
00977    \param ContID (void *) This parameters is stored in the callback structure that the menu items
00978                         send to the callback. You can pass an integer for a controller's index or 
00979                         any other structure like a surface object's ID for example.  
00980    The callback structure value associated with each menu widget (cv) is:
00981    CBp->ContID = ContID;
00982    CBp->callback_data = callback_data (that is passed in items);
00983    This allows you to create multiple versions 
00984    of the same menu and still be able to dissociate between them.
00985    \param hint, help (char *) strings for hints and bhelps...(NULL for nothing)
00986    \param MenuWidgets (Widget *) pointer to a vector that will contain widgets created.
00987          MenuWidgets[0] is the menu or cascade widgets, MenuWidgets[1]..MenuWidgets[N_wid-1]
00988          would contain the button and separator widgets specified in items
00989    \return N_wid (int) number of widgets in MenuWidgets. Obviously you'll need
00990          to know that ahead of time to allocate for MenuWidgets ... 
00991 
00992 -  This function is largely based on BuildMenu in the "Motif Programming Manual"
00993   Build popup, option and pulldown menus, depending on the menu_type.
00994   It may be XmMENU_PULLDOWN, XmMENU_OPTION or  XmMENU_POPUP.  Pulldowns
00995   return the CascadeButton that pops up the menu.  Popups return the menu.
00996   Option menus are created, but the RowColumn that acts as the option
00997   "area" is returned unmanaged. (The user must manage it.)
00998   Pulldown menus are built from cascade buttons, so this function
00999   also builds pullright menus.  The function also adds the right
01000   callback for PushButton or ToggleButton menu items.
01001    
01002  *** SIGNIFICANT CHANGE to BuildMenu ZSS Apr 23 04   
01003  *** MUST CALL SUMA_BuildMenuReset BEFORE calling SUMA_BuildMenu
01004  */
01005 static int i_wid = 0;
01006 static int N_wid = 0;
01007 static int nchar = 0;
01008 
01009 void SUMA_BuildMenuReset(int n_max)
01010 {
01011    static char FuncName[]={"SUMA_BuildMenuReset"};
01012    SUMA_ENTRY;
01013    i_wid = 0;
01014    N_wid = 0;
01015    nchar = n_max;
01016    SUMA_RETURNe;
01017 }
01018 
01019 int SUMA_BuildMenu(Widget parent, int menu_type, char *menu_title, 
01020                      char menu_mnemonic, SUMA_Boolean tear_off, SUMA_MenuItem *items, 
01021                      void *ContID, 
01022                      char *hint, char *help,
01023                      Widget *MenuWidgets )
01024 {
01025    static char FuncName[]={"SUMA_BuildMenu"};
01026    char nlabel[300];
01027    Widget menu = NULL, cascade = NULL;
01028    XmString str;
01029    int i;
01030    SUMA_Boolean LocalHead = NOPE;
01031    
01032    SUMA_ENTRY;
01033 
01034    if (LocalHead) fprintf (SUMA_STDERR, "%s: Here.\n", FuncName);
01035       
01036    if (menu_type == XmMENU_PULLDOWN || menu_type == XmMENU_OPTION)
01037      menu = XmCreatePulldownMenu (parent, "_pulldown", NULL, 0);
01038    else if (menu_type == XmMENU_POPUP)
01039      menu = XmCreatePopupMenu (parent, "_popup", NULL, 0);
01040    else {
01041      XtWarning ("Invalid menu type passed to BuildMenu()");
01042      SUMA_RETURN(-1);
01043    }
01044    
01045 
01046    if (tear_off)
01047      XtVaSetValues (menu, XmNtearOffModel, XmTEAR_OFF_ENABLED, NULL);
01048 
01049    /* Pulldown menus require a cascade button to be made */
01050    if (menu_type == XmMENU_PULLDOWN) {
01051      str = XmStringCreateLocalized (menu_title);
01052      cascade = XtVaCreateManagedWidget (menu_title,
01053          xmCascadeButtonWidgetClass, parent,
01054          XmNsubMenuId,   menu,
01055          XmNlabelString, str,
01056          XmNmnemonic,    menu_mnemonic,
01057          XmNmarginHeight, 0,
01058          XmNmarginTop, 0,
01059          XmNmarginBottom, 0,
01060          NULL);
01061      XmStringFree (str);
01062    } 
01063    else if (menu_type == XmMENU_OPTION) {
01064      /* Option menus are a special case, but not hard to handle */
01065      Arg args[10];
01066      int n = 0;
01067      SUMA_LH("Here");
01068      str = XmStringCreateLocalized (menu_title);
01069      XtSetArg (args[n], XmNsubMenuId, menu); n++;
01070      XtSetArg (args[n], XmNlabelString, str); n++;
01071      XtSetArg (args[n], XmNmarginHeight, 0); n++;
01072      XtSetArg (args[n], XmNmarginTop, 0 ); n++;
01073      XtSetArg (args[n], XmNmarginBottom, 0 ); n++;
01074      
01075      /* This really isn't a cascade, but this is the widget handle
01076       * we're going to return at the end of the function.
01077       */
01078      cascade = XmCreateOptionMenu (parent, menu_title, args, n);
01079      XmStringFree (str);
01080    }
01081    
01082    /* hide your jewel */
01083    if (menu_type == XmMENU_POPUP) {  MenuWidgets[i_wid] = menu; }
01084    else { MenuWidgets[i_wid] = cascade; } 
01085    
01086    if (hint) MCW_register_hint(MenuWidgets[i_wid], hint);
01087    if (help) MCW_reghelp_children(MenuWidgets[i_wid], help);
01088    
01089    ++i_wid;
01090    
01091    /* Now add the menu items */
01092    for (i = 0; items[i].label != NULL; i++) {
01093       if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding label # %d - %s\n", FuncName, i, items[i].label);
01094      /* If subitems exist, create the pull-right menu by calling this
01095       * function recursively.  Since the function returns a cascade
01096       * button, the widget returned is used..
01097       */
01098      if (items[i].subitems)
01099          if (menu_type == XmMENU_OPTION) {
01100              XtWarning ("You can't have submenus from option menu items.");
01101              continue;
01102          } 
01103          else {
01104              if (LocalHead) fprintf (SUMA_STDERR, "%s: Going for sub-menu.\n", FuncName);
01105              SUMA_BuildMenu (menu, XmMENU_PULLDOWN, items[i].label, 
01106                  items[i].mnemonic, tear_off, items[i].subitems, ContID, hint, help, MenuWidgets);
01107          }
01108      else {
01109          if (LocalHead) fprintf (SUMA_STDERR, "%s: Creating widgets MenuWidgets[%d]\n", FuncName, (int)items[i].callback_data);
01110          if (nchar > 0) {
01111             snprintf(nlabel, nchar*sizeof(char), "%s", items[i].label);
01112             MenuWidgets[i_wid] = XtVaCreateManagedWidget (nlabel,
01113                 *items[i].class, menu,
01114                 NULL);
01115          } else {
01116             MenuWidgets[i_wid] = XtVaCreateManagedWidget (items[i].label,
01117                 *items[i].class, menu,
01118                 NULL);
01119          }
01120       }
01121 
01122       
01123       /* Whether the item is a real item or a cascade button with a
01124       * menu, it can still have a mnemonic.
01125       */
01126       if (LocalHead) fprintf (SUMA_STDERR, "%s: Setting Mnemonic ...\n", FuncName);
01127       if (items[i].mnemonic)
01128          XtVaSetValues (MenuWidgets[i_wid], XmNmnemonic, items[i].mnemonic, NULL);
01129 
01130       /* any item can have an accelerator, except cascade menus. But,
01131       * we don't worry about that; we know better in our declarations.
01132       */
01133 
01134       if (LocalHead) fprintf (SUMA_STDERR, "%s: Setting accelerator ...\n", FuncName);
01135       if (items[i].accelerator) {
01136          str = XmStringCreateLocalized (items[i].accel_text);
01137          XtVaSetValues (MenuWidgets[i_wid],
01138              XmNaccelerator, items[i].accelerator,
01139              XmNacceleratorText, str,
01140              NULL);
01141          XmStringFree (str);
01142       }
01143 
01144       if (items[i].class == &xmToggleButtonWidgetClass ||
01145               items[i].class == &xmToggleButtonWidgetClass) {
01146          Pixel fg_pix;
01147          XtVaGetValues (MenuWidgets[i_wid], XmNforeground, &fg_pix, NULL);
01148          XtVaSetValues (MenuWidgets[i_wid], XmNselectColor, fg_pix, NULL); 
01149           
01150       }
01151      
01152       if (LocalHead) fprintf (SUMA_STDERR, "%s: Setting callback ...\n", FuncName);
01153       if (items[i].callback) {
01154          SUMA_MenuCallBackData *CBp=NULL;
01155          CBp = (SUMA_MenuCallBackData *)malloc (sizeof(SUMA_MenuCallBackData)); /* There is no freeing of this pointer in SUMA. Once created, a widget is only destroyed when SUMA is killed */
01156          /* prepare the callback pointer */
01157          CBp->callback_data = (XtPointer) items[i].callback_data;
01158          CBp->ContID = ContID;
01159          XtAddCallback (MenuWidgets[i_wid],
01160              (items[i].class == &xmToggleButtonWidgetClass ||
01161               items[i].class == &xmToggleButtonWidgetClass) ?
01162                  XmNvalueChangedCallback : /* ToggleButton class */
01163                  XmNactivateCallback,      /* PushButton class */
01164              items[i].callback, (XtPointer)CBp);
01165       }
01166       ++i_wid;
01167    }
01168 
01169    #if 0
01170     {
01171       SUMA_LH("Adding event handler. Crashes when dealing with File: cascade buttons ....");
01172       if (menu_type == XmMENU_POPUP) {
01173          SUMA_ShowMeTheChildren(menu);
01174       } else {
01175          SUMA_ShowMeTheChildren(cascade);
01176       }
01177       /* add yourself an even handler to deal with long menus a la AFNI 
01178       see bbox.c */
01179       if (0) {
01180       SUMA_ShowMeTheChildren(menu);
01181       XtInsertEventHandler(   cascade ,      /* handle events in optmenu */
01182                            ButtonPressMask ,  /* button presses */
01183                            FALSE ,            /* nonmaskable events? */
01184                            SUMA_optmenu_EV ,  /* handler */
01185                            (XtPointer) cascade ,   /* client data */
01186                            XtListTail ) ;     /* last in queue */
01187      } 
01188 
01189    }
01190    #endif
01191    /* for popup menus, just return the menu; pulldown menus, return
01192    * the cascade button; option menus, return the thing returned
01193    * from XmCreateOptionMenu().  This isn't a menu, or a cascade button!
01194    */
01195    if (LocalHead) fprintf (SUMA_STDERR, "%s: Returning %d widgets created.\n", FuncName, i_wid);
01196    SUMA_RETURN (i_wid);
01197 }
01198 
01199 Widget mainw, menubar, menupane, btn, sep, cascade, frame;
01200 Arg menuPaneArgs[1], args[1];
01201 
01202 SUMA_MenuItem FileOpen_menu[] = {
01203    {  "OpenSpec", &xmPushButtonWidgetClass, \
01204       'p', "Ctrl<Key>p", "Ctrl+p", \
01205       SUMA_cb_FileOpenSpec, (XtPointer) SW_FileOpenSpec, NULL},
01206    
01207    {  "OpenSurf", &xmPushButtonWidgetClass, \
01208       'o', "Ctrl<Key>o", "Ctrl+o", \
01209       SUMA_cb_FileOpenSurf, (XtPointer) SW_FileOpenSurf, NULL},
01210    
01211    {NULL} ,
01212 };
01213 
01214 SUMA_MenuItem File_menu[] = {
01215    /*{  "Open", &xmPushButtonWidgetClass, \
01216       '\0', NULL, NULL, \
01217       NULL,  (XtPointer) SW_FileOpen, (SUMA_MenuItem *) FileOpen_menu },
01218    */
01219    {  "Save View", &xmPushButtonWidgetClass, \
01220       '\0', NULL, NULL, \
01221       SUMA_cb_FileSaveView, (XtPointer) SW_FileSaveView, NULL},
01222    
01223    {  "Load View", &xmPushButtonWidgetClass, \
01224       '\0', NULL, NULL, \
01225       SUMA_cb_FileLoadView, (XtPointer) SW_FileLoadView, NULL},
01226       
01227    
01228    {  "Close", &xmPushButtonWidgetClass, \
01229       'C', NULL, "Esc", \
01230       SUMA_cb_FileClose, (XtPointer) SW_FileClose, NULL},
01231    
01232    {NULL},
01233 };
01234  
01235 
01236 /* 
01237 SUMA_MenuItem Edit_menu[] = {
01238    {  "Draw ROI", &xmPushButtonWidgetClass, \
01239       'D', "Ctrl <Key>d", "Ctrl+D", \
01240       SUMA_cb_ToolsDrawROI, (XtPointer) SW_ToolsDrawROI, NULL },
01241    
01242    {NULL},
01243 
01244 };
01245 */
01246 
01247 /* can use combo like: "Ctrl Shift<Key>d", "Ctrl+D"*/
01248 SUMA_MenuItem View_menu[] = {
01249    {  "SUMA Controller", &xmPushButtonWidgetClass, \
01250       'U', "Ctrl<Key>u", "Ctrl+u", \
01251       SUMA_cb_viewSumaCont, (XtPointer) SW_ViewSumaCont, NULL },
01252    
01253    {  "Surface Controller", &xmPushButtonWidgetClass, \
01254       'S', "Ctrl<Key>s", "Ctrl+s", \
01255       SUMA_cb_viewSurfaceCont, (XtPointer) SW_ViewSurfCont, NULL },
01256    
01257    {  "Viewer Controller", &xmPushButtonWidgetClass, \
01258       'V', "Ctrl<Key>v", "Ctrl+v", \
01259       SUMA_cb_viewViewerCont, (XtPointer) SW_ViewViewCont, NULL },
01260    
01261    {  "Separator 1", &xmSeparatorWidgetClass, \
01262       '\0', NULL, NULL, \
01263       NULL, (XtPointer) SW_ViewSep1, NULL },
01264    
01265    {  "Cross Hair", &xmToggleButtonWidgetClass, \
01266       'C', "<Key>F3", "F3",  \
01267       SUMA_cb_toggle_crosshair, (XtPointer) SW_ViewCrossHair, NULL },
01268    
01269    {  "Node in Focus", &xmToggleButtonWidgetClass, \
01270       'N', "<Key>F4", "F4", \
01271       SUMA_cb_toggle_node_in_focus, (XtPointer) SW_ViewNodeInFocus, NULL },
01272       
01273    {  "Selected Faceset", &xmToggleButtonWidgetClass, \
01274       'F', "<Key>F5", "F5", \
01275       SUMA_cb_toggle_selected_faceset, (XtPointer) SW_ViewSelectedFaceset, NULL },
01276       
01277    {NULL},
01278 };
01279 
01280 SUMA_MenuItem Tools_menu[] = {
01281    {  "Draw ROI", &xmPushButtonWidgetClass, \
01282       'D', "Ctrl <Key>d", "Ctrl+d", \
01283       SUMA_cb_ToolsDrawROI, (XtPointer) SW_ToolsDrawROI, NULL },
01284    
01285    {NULL},
01286 
01287 };
01288 
01289 
01290 SUMA_MenuItem Help_menu[] = {
01291    {  "Usage", &xmPushButtonWidgetClass, \
01292       'U', "Ctrl <Key>h", "Ctrl+h", \
01293       SUMA_cb_helpUsage, (XtPointer) SW_HelpUsage, NULL},
01294       
01295    {  "Message Log", &xmPushButtonWidgetClass, \
01296       'L', NULL, NULL, \
01297       SUMA_cb_helpMessageLog, (XtPointer) SW_HelpMessageLog, NULL},
01298       
01299    {  "Separator 1", &xmSeparatorWidgetClass, \
01300       '\0', NULL, NULL, \
01301       NULL, (XtPointer) SW_HelpSep1, NULL }, 
01302    
01303    {  "SUMA Global", &xmPushButtonWidgetClass, \
01304       'G', NULL, NULL, \
01305       SUMA_cb_helpSUMAGlobal, (XtPointer) SW_HelpSUMAGlobal, NULL},
01306    
01307    {  "Viewer struct", &xmPushButtonWidgetClass, \
01308       'V', NULL, NULL, \
01309       SUMA_cb_helpViewerStruct, (XtPointer) SW_HelpViewerStruct, NULL},
01310    
01311    {  "Surface struct", &xmPushButtonWidgetClass, \
01312       'S', NULL, NULL, \
01313       SUMA_cb_helpSurfaceStruct, (XtPointer) SW_HelpSurfaceStruct, NULL},
01314    
01315    {  "Separator 2", &xmSeparatorWidgetClass, \
01316       '\0', NULL, NULL, \
01317       NULL, (XtPointer) SW_HelpSep2, NULL },    
01318    
01319    {  "InOut Notify", &xmToggleButtonWidgetClass, \
01320       'I', NULL, NULL, \
01321       SUMA_cb_helpIO_notify, (XtPointer) SW_HelpIONotify, NULL},
01322       
01323    {  "MemTrace", &xmToggleButtonWidgetClass, \
01324       'M', NULL, NULL, \
01325       SUMA_cb_helpMemTrace, (XtPointer) SW_HelpMemTrace, NULL},
01326    {NULL},
01327 };
01328 
01329 SUMA_MenuItem RenderMode_Menu[] = {
01330    {  "Viewer", &xmPushButtonWidgetClass, 
01331       '\0', NULL, NULL, 
01332       SUMA_cb_SetRenderMode, (XtPointer) SW_SurfCont_RenderViewerDefault, NULL},
01333       
01334    {  "Fill", &xmPushButtonWidgetClass, 
01335       '\0', NULL, NULL, 
01336       SUMA_cb_SetRenderMode, (XtPointer) SW_SurfCont_RenderFill, NULL},
01337    
01338    {  "Line", &xmPushButtonWidgetClass, 
01339       '\0', NULL, NULL, 
01340       SUMA_cb_SetRenderMode, (XtPointer) SW_SurfCont_RenderLine, NULL},
01341     
01342    {  "Points", &xmPushButtonWidgetClass, 
01343       '\0', NULL, NULL, 
01344       SUMA_cb_SetRenderMode, (XtPointer) SW_SurfCont_RenderPoints, NULL},
01345         
01346    {NULL},
01347 };
01348 
01349 SUMA_MenuItem DrawROI_SaveMode_Menu[]= {
01350    {  "1D", &xmPushButtonWidgetClass, 
01351       '\0', NULL, NULL, 
01352       SUMA_cb_SetDrawROI_SaveMode, (XtPointer) SW_DrawROI_SaveMode1D, NULL},
01353    
01354    {  "NIML", &xmPushButtonWidgetClass, 
01355       '\0', NULL, NULL, 
01356       SUMA_cb_SetDrawROI_SaveMode, (XtPointer) SW_DrawROI_SaveModeNIML, NULL},
01357    
01358    {NULL},
01359 };
01360 
01361 SUMA_MenuItem DrawROI_SaveWhat_Menu[]= {
01362    {  "This", &xmPushButtonWidgetClass, 
01363       '\0', NULL, NULL, 
01364       SUMA_cb_SetDrawROI_SaveWhat, (XtPointer) SW_DrawROI_SaveWhatThis, NULL},
01365    
01366    {  "All", &xmPushButtonWidgetClass, 
01367       '\0', NULL, NULL, 
01368       SUMA_cb_SetDrawROI_SaveWhat, (XtPointer) SW_DrawROI_SaveWhatRelated, NULL},
01369          
01370    {NULL},
01371 };
01372 
01373 SUMA_MenuItem DrawROI_WhatDist_Menu[]= {
01374    {  "----", &xmPushButtonWidgetClass, 
01375       '\0', NULL, NULL, 
01376       SUMA_cb_SetDrawROI_WhatDist, (XtPointer) SW_DrawROI_WhatDistNothing, NULL},
01377    
01378    {  "trace", &xmPushButtonWidgetClass, 
01379       '\0', NULL, NULL, 
01380       SUMA_cb_SetDrawROI_WhatDist, (XtPointer) SW_DrawROI_WhatDistTrace, NULL},
01381    
01382    {  "all", &xmPushButtonWidgetClass, 
01383       '\0', NULL, NULL, 
01384       SUMA_cb_SetDrawROI_WhatDist, (XtPointer) SW_DrawROI_WhatDistAll, NULL},
01385          
01386    {NULL},
01387 };      
01388 SUMA_Boolean SUMA_X_SurfaceViewer_Create (void)
01389 {
01390    static char FuncName[]={"SUMA_X_SurfaceViewer_Create"};
01391    static int CallNum = 0;
01392    int ic = 0;
01393    char *vargv[1]={ "[A] SUMA" };
01394    int cargc = 1;
01395    SUMA_Boolean NewCreation = NOPE, Found, Inherit = NOPE;
01396    SUMA_Boolean LocalHead = NOPE;
01397    char slabel[20]; 
01398        
01399    SUMA_ENTRY;
01400 
01401    /* Step 1. */
01402    if (CallNum == 0) { /* first call, initialize App */
01403       SUMAg_CF->N_OpenSV = 0;
01404       SUMAg_SVv[ic].X->TOPLEVEL = XtAppInitialize(&SUMAg_CF->X->App, "SUMA", NULL, 0, &cargc, vargv,
01405        SUMA_get_fallbackResources(), NULL, 0);
01406       SUMAg_SVv[ic].X->DPY = XtDisplay(SUMAg_SVv[ic].X->TOPLEVEL);
01407       /* save DPY for first controller opened */
01408       SUMAg_CF->X->DPY_controller1 = SUMAg_SVv[ic].X->DPY;
01409       NewCreation = YUP;
01410       Inherit = NOPE;
01411    } else {/* not the first call, new controller is required */
01412       ic = 0;
01413       Found = NOPE;
01414       while (ic < SUMA_MAX_SURF_VIEWERS && !Found) {
01415          if (!SUMAg_SVv[ic].Open) {
01416             Found = YUP;
01417          } else {
01418             ++ic;
01419          }
01420       }
01421       if (!Found) { /* no unopen windows left to open */
01422          fprintf (SUMA_STDERR,"Error %s: Cannot open more than %d viewers.\n", FuncName, SUMA_MAX_SURF_VIEWERS);
01423          SUMA_RETURN (NOPE);
01424       }
01425       
01426       /* an unopen window was found, check its top level widget */
01427       if (SUMAg_SVv[ic].X->TOPLEVEL == NULL) {
01428          /* Unopen window found, needs a shell */
01429          SUMAg_SVv[ic].X->DPY = SUMAg_CF->X->DPY_controller1;
01430          SUMAg_SVv[ic].X->TOPLEVEL = XtVaAppCreateShell("SUMA" , "Suma" ,
01431                    topLevelShellWidgetClass , SUMAg_SVv[ic].X->DPY ,
01432                    XmNinitialResourcesPersistent , False ,
01433                    NULL ) ;
01434          NewCreation = YUP;
01435          Inherit = YUP;
01436       } else { /* Unopen window found, has a shell already. */
01437          NewCreation = NOPE;
01438       }
01439    }
01440 
01441    if (NewCreation) { /* create widgets, add call backs etc ,,, */
01442       /* Step 2. */
01443       XtAddEventHandler(SUMAg_SVv[ic].X->TOPLEVEL, StructureNotifyMask,
01444        False, SUMA_mapStateChanged, NULL);
01445       XtAddEventHandler(SUMAg_SVv[ic].X->TOPLEVEL, EnterWindowMask,
01446        False, SUMA_SetcSV, NULL);
01447       XtAddEventHandler(SUMAg_SVv[ic].X->TOPLEVEL, LeaveWindowMask,
01448        False, SUMA_unSetcSV, NULL); 
01449 
01450       /* Step 3 */
01451       if (!Inherit) {
01452          if (LocalHead) fprintf(stdout, "trying for cool double buffer visual\n");
01453          SUMAg_SVv[ic].X->VISINFO = glXChooseVisual(SUMAg_SVv[ic].X->DPY, DefaultScreen(SUMAg_SVv[ic].X->DPY), dblBuf);
01454          if (SUMAg_SVv[ic].X->VISINFO == NULL) {
01455          fprintf(stdout, "trying lame single buffer visual\n");
01456           XtAppWarning(SUMAg_CF->X->App, "trying lame single buffer visual");
01457           SUMAg_SVv[ic].X->VISINFO = glXChooseVisual(SUMAg_SVv[ic].X->DPY, DefaultScreen(SUMAg_SVv[ic].X->DPY), snglBuf);
01458           if (SUMAg_SVv[ic].X->VISINFO == NULL) {
01459             XtAppError(SUMAg_CF->X->App, "no good visual");
01460             SUMA_RETURN (NOPE);
01461             }
01462           SUMAg_SVv[ic].X->DOUBLEBUFFER = False;
01463          }
01464       } else {
01465          SUMA_LH("This is new. Inheriting");
01466          SUMAg_SVv[ic].X->VISINFO = SUMAg_SVv[0].X->VISINFO;
01467          SUMAg_SVv[ic].X->DOUBLEBUFFER = SUMAg_SVv[0].X->DOUBLEBUFFER;
01468       }
01469                 
01470       /* Step 3.5 Wed Dec 18 14:49:25 EST 2002 - The GUI*/
01471          /* see Kilgard's OpenGL Programming for the X window system */
01472          /* create main window */
01473          mainw = XmCreateMainWindow (SUMAg_SVv[ic].X->TOPLEVEL, "mainw", NULL, 0);
01474          XtManageChild (mainw);      
01475          /* create menu bar */
01476          menubar = XmCreateMenuBar (mainw, "menubar", NULL, 0);
01477          XtManageChild (menubar);
01478          
01479          /* create File Menu */
01480          SUMA_BuildMenuReset(0);
01481          SUMA_BuildMenu(menubar, XmMENU_PULLDOWN, 
01482                                  "File", 'F', YUP, File_menu, 
01483                                  (void *)ic, NULL, NULL,  
01484                                  SUMAg_SVv[ic].X->FileMenu );
01485          
01486          /* create View Menu */
01487          SUMA_BuildMenuReset(0);
01488          SUMA_BuildMenu(menubar, XmMENU_PULLDOWN, 
01489                                  "View", 'V', YUP, View_menu, 
01490                                  (void *)ic, NULL, NULL,  
01491                                  SUMAg_SVv[ic].X->ViewMenu );
01492          
01493          /* create Tools Menu */
01494          SUMA_BuildMenuReset(0);
01495          SUMA_BuildMenu(menubar, XmMENU_PULLDOWN, 
01496                                  "Tools", 'T', YUP, Tools_menu, 
01497                                  (void *)ic, NULL, NULL,  
01498                                  SUMAg_SVv[ic].X->ToolsMenu );
01499          
01500          /* create Help Menu */
01501          SUMA_BuildMenuReset(0);
01502          SUMA_BuildMenu(menubar, XmMENU_PULLDOWN, 
01503                                  "Help", 'H', YUP, Help_menu,
01504                                  (void *)ic, NULL, NULL,  
01505                                  SUMAg_SVv[ic].X->HelpMenu );
01506          
01507          XtVaSetValues (menubar, XmNmenuHelpWidget, SUMAg_SVv[ic].X->HelpMenu[SW_Help], NULL);
01508                                  
01509          /* set states of the some view menu widgets */
01510          XmToggleButtonSetState (SUMAg_SVv[ic].X->ViewMenu[SW_ViewCrossHair], 
01511             SUMAg_SVv[ic].ShowCrossHair, NOPE);
01512          
01513          XmToggleButtonSetState (SUMAg_SVv[ic].X->HelpMenu[SW_HelpMemTrace], 
01514             SUMAg_CF->MemTrace, NOPE);
01515          if (SUMAg_CF->MemTrace) {  XtSetSensitive (SUMAg_SVv[ic].X->HelpMenu[SW_HelpMemTrace], 0); }
01516 
01517          XmToggleButtonSetState (SUMAg_SVv[ic].X->HelpMenu[SW_HelpIONotify], 
01518             SUMAg_CF->InOut_Notify, NOPE);
01519          
01520  
01521          
01522       #ifdef SUMA_MOTIF_GLXAREA
01523         /* Step 4. */
01524         SUMAg_SVv[ic].X->FORM = XmCreateForm(SUMAg_SVv[ic].X->TOPLEVEL, "form", NULL, 0);
01525         XtManageChild(SUMAg_SVv[ic].X->FORM);
01526         SUMAg_SVv[ic].X->FRAME = XmCreateFrame(SUMAg_SVv[ic].X->FORM, "frame", NULL, 0);
01527         XtVaSetValues(SUMAg_SVv[ic].X->FRAME,
01528           XmNbottomAttachment, XmATTACH_FORM,
01529           XmNtopAttachment, XmATTACH_FORM,
01530           XmNleftAttachment, XmATTACH_FORM,
01531           XmNrightAttachment, XmATTACH_FORM,
01532           NULL);
01533         XtManageChild(SUMAg_SVv[ic].X->FRAME);
01534 
01535         /* Step 5. */
01536         SUMAg_SVv[ic].X->CMAP = SUMA_getShareableColormap(&(SUMAg_SVv[ic]));
01537 
01538         /* Step 6. */
01539          /* glwMDrawingAreaWidgetClass requires libMesaGLwM.a */
01540          SUMAg_SVv[ic].X->GLXAREA = XtVaCreateManagedWidget("glxarea",
01541           glwMDrawingAreaWidgetClass, SUMAg_SVv[ic].X->FRAME,
01542           GLwNvisualInfo, SUMAg_SVv[ic].X->VISINFO,
01543           XtNcolormap, SUMAg_SVv[ic].X->CMAP,
01544           NULL);
01545       #else
01546       /* Step 4-6. */
01547          SUMAg_SVv[ic].X->CMAP = SUMA_getShareableColormap(&(SUMAg_SVv[ic]));
01548 
01549          /* create a frame to put glxarea in */
01550          SUMAg_SVv[ic].X->FRAME  = XmCreateFrame (mainw, "frame", NULL, 0);
01551          XtManageChild(SUMAg_SVv[ic].X->FRAME);
01552 
01553          /* glwDrawingAreaWidgetClass requires libMesaGLw.a */
01554          SUMAg_SVv[ic].X->GLXAREA = XtVaCreateManagedWidget("glxarea",
01555           glwDrawingAreaWidgetClass, SUMAg_SVv[ic].X->FRAME,
01556           GLwNvisualInfo, SUMAg_SVv[ic].X->VISINFO,
01557           XtNcolormap, SUMAg_SVv[ic].X->CMAP,
01558           NULL);
01559       
01560       #endif
01561 
01562           
01563       /* Step 7. */
01564       XtAddCallback(SUMAg_SVv[ic].X->GLXAREA, GLwNginitCallback, SUMA_graphicsInit, NULL);
01565       XtAddCallback(SUMAg_SVv[ic].X->GLXAREA, GLwNexposeCallback, SUMA_expose, NULL);
01566       XtAddCallback(SUMAg_SVv[ic].X->GLXAREA, GLwNresizeCallback, SUMA_resize, NULL);
01567       XtAddCallback(SUMAg_SVv[ic].X->GLXAREA, GLwNinputCallback, SUMA_input, NULL);
01568 
01569       /* trap for window kill */
01570       
01571       /* turn off default delete response. If you do not do that, you will suffer.*/
01572        XtVaSetValues( SUMAg_SVv[ic].X->TOPLEVEL,
01573            XmNdeleteResponse, XmDO_NOTHING,
01574            NULL);      
01575          
01576       XmAddWMProtocolCallback(           /* make "Close" window menu work */
01577            SUMAg_SVv[ic].X->TOPLEVEL,
01578            XmInternAtom( SUMAg_SVv[ic].X->DPY , "WM_DELETE_WINDOW" , False ) ,
01579            SUMA_ButtClose_pushed , NULL ) ;
01580            
01581       /* Step 8. */
01582       XtRealizeWidget(SUMAg_SVv[ic].X->TOPLEVEL);
01583       
01584       /* I will need a Graphics Context variable to draw into the window */
01585       {  
01586          XGCValues gcv; /* see program drawing.c in Motif Programming Manual, Ch. 10 */
01587          gcv.foreground = BlackPixelOfScreen (XtScreen (SUMAg_SVv[ic].X->GLXAREA));
01588          SUMAg_SVv[ic].X->gc = XCreateGC (SUMAg_SVv[ic].X->DPY,
01589                                           XtWindow (SUMAg_SVv[ic].X->GLXAREA), 
01590                                           GCForeground, &gcv);
01591          SUMA_SetSVForegroundColor (&SUMAg_SVv[ic], "Green");
01592 
01593       }
01594       /* keep track of count */
01595       SUMAg_N_SVv += 1;
01596              
01597    } else { /* widget already set up, just undo whatever was done in SUMA_ButtClose_pushed */
01598       
01599       #ifdef SUMA_USE_WITHDRAW
01600          XMapRaised(SUMAg_SVv[ic].X->DPY, XtWindow(SUMAg_SVv[ic].X->TOPLEVEL));      
01601       #endif
01602       
01603       /* add the workprocess again */
01604       SUMA_register_workproc( SUMA_handleRedisplay, SUMAg_SVv[ic].X->GLXAREA );
01605       SUMAg_SVv[ic].X->REDISPLAYPENDING = 0;
01606    }
01607 
01608    SUMAg_SVv[ic].Open = YUP;
01609    ++SUMAg_CF->N_OpenSV;
01610    ++CallNum;
01611    
01612    SUMA_UpdateViewerCursor (&(SUMAg_SVv[ic]));
01613    SUMA_UpdateViewerTitle (&(SUMAg_SVv[ic]));
01614 
01615    SUMA_RETURN (YUP);
01616 }
01617 
01618 void SUMA_ButtOpen_pushed (Widget w, XtPointer cd1, XtPointer cd2)
01619 {
01620    static char FuncName[]={"SUMA_ButtOpen_pushed"};
01621    
01622    SUMA_ENTRY;
01623 
01624    if (!SUMA_X_SurfaceViewer_Create ()) {
01625       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_X_SurfaceViewer_Create.\n", FuncName);
01626    } 
01627    SUMA_RETURNe;
01628 }
01629 
01630 void SUMA_cb_FileOpenSpec (Widget w, XtPointer data, XtPointer calldata) 
01631 {
01632    static char FuncName[]={"SUMA_cb_FileOpenSpec"};
01633    
01634    SUMA_ENTRY;
01635    
01636    fprintf (SUMA_STDERR, "%s: called.\n", FuncName);
01637    SUMA_RETURNe;
01638 }
01639 
01640 void SUMA_cb_FileOpenSurf (Widget w, XtPointer data, XtPointer calldata) 
01641 {
01642    static char FuncName[]={"SUMA_cb_FileOpenSurf"};
01643    
01644    SUMA_ENTRY;
01645    
01646    fprintf (SUMA_STDERR, "%s: called.\n", FuncName);
01647    SUMA_RETURNe;
01648 }
01649 
01650 void SUMA_cb_FileSaveView (Widget w, XtPointer data, XtPointer calldata) 
01651 {
01652    static char FuncName[]={"SUMA_cb_FileSaveView"};
01653    int isv, widtype;
01654    SUMA_EngineData *ED = NULL; 
01655    DList *list = NULL;
01656    SUMA_SurfaceViewer *sv;
01657    
01658    SUMA_ENTRY;
01659    
01660    /* find the index of the viewer closed */
01661    SUMA_VIEWER_FROM_FILEMENU_CALLBACK(data, isv, widtype);
01662    if (widtype != SW_FileSaveView) {
01663       fprintf (SUMA_STDERR, "Error %s: Something really bad has happened.\n", FuncName);
01664       SUMA_RETURNe;
01665    }   
01666 
01667    sv = &SUMAg_SVv[isv];
01668    
01669    if (!list) list = SUMA_CreateList();
01670    ED = SUMA_InitializeEngineListData (SE_SaveViewFileSelection);
01671    if (!SUMA_RegisterEngineListCommand (  list, ED,
01672                                           SEF_ip, sv->X->TOPLEVEL,
01673                                           SES_Suma, (void *)sv, NOPE,
01674                                           SEI_Head, NULL)) {
01675       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
01676    }
01677    if (!SUMA_Engine (&list)) {
01678       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
01679    }
01680    
01681    /*
01682    if (!SUMA_SaveVisualState(NULL, (void*)sv)) {
01683       SUMA_SLP_Err("Failed to save view.");
01684       SUMA_RETURNe;
01685    }
01686    */
01687    
01688    SUMA_RETURNe;
01689 }
01690 
01691 void SUMA_cb_FileLoadView (Widget w, XtPointer data, XtPointer calldata) 
01692 {
01693    static char FuncName[]={"SUMA_cb_FileLoadView"};
01694    int isv, widtype;
01695    SUMA_EngineData *ED = NULL; 
01696    DList *list = NULL;
01697    SUMA_SurfaceViewer *sv;
01698    
01699    SUMA_ENTRY;
01700    
01701    /* find the index of the viewer closed */
01702    SUMA_VIEWER_FROM_FILEMENU_CALLBACK(data, isv, widtype);
01703    if (widtype != SW_FileLoadView) {
01704       fprintf (SUMA_STDERR, "Error %s: Something really bad has happened.\n", FuncName);
01705       SUMA_RETURNe;
01706    }   
01707 
01708    sv = &SUMAg_SVv[isv];
01709    
01710    if (!list) list = SUMA_CreateList();
01711    ED = SUMA_InitializeEngineListData (SE_LoadViewFileSelection);
01712    if (!SUMA_RegisterEngineListCommand (  list, ED,
01713                                           SEF_ip, sv->X->TOPLEVEL,
01714                                           SES_Suma, (void *)sv, NOPE,
01715                                           SEI_Head, NULL)) {
01716       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
01717    }
01718    if (!SUMA_Engine (&list)) {
01719       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
01720    }
01721    
01722    /*
01723    if (!SUMA_LoadVisualState(NULL, (void*)sv)) {
01724       SUMA_SLP_Err("Failed to load view.");
01725       SUMA_RETURNe;
01726    }
01727    */
01728    
01729    SUMA_RETURNe;
01730 }
01731 
01732 
01733 void SUMA_cb_FileClose (Widget w, XtPointer data, XtPointer calldata) 
01734 {
01735    static char FuncName[]={"SUMA_cb_FileClose"};
01736    int isv, widtype;
01737    SUMA_SurfaceViewer *sv;
01738    
01739    SUMA_ENTRY;
01740    
01741    /* find the index of the viewer closed */
01742    SUMA_VIEWER_FROM_FILEMENU_CALLBACK(data, isv, widtype);
01743    if (widtype != SW_FileClose) {
01744       fprintf (SUMA_STDERR, "Error %s: Something really bad has happened.\n", FuncName);
01745       SUMA_RETURNe;
01746    }   
01747 
01748    sv = &SUMAg_SVv[isv];
01749    SUMA_ButtClose_pushed (sv->X->GLXAREA, data, calldata);
01750       
01751    SUMA_RETURNe;
01752 }
01753 
01754 
01755 /*!
01756   \brief Close the viewer. Exit if it is last viewer to be closed. 
01757 */
01758 void SUMA_ButtClose_pushed (Widget w, XtPointer cd1, XtPointer cd2)
01759 {
01760    static char FuncName[]={"SUMA_ButtClose_pushed"};
01761    int ic, Found;
01762    SUMA_Boolean LocalHead = NOPE;
01763    
01764    SUMA_ENTRY;
01765 
01766    SUMA_LH("Called");
01767    ic = 0;
01768    Found = 0;
01769    while (ic < SUMA_MAX_SURF_VIEWERS && !Found) {
01770       #if 0 
01771       /*use once you have a close button with its widget*/
01772       if (SUMAg_SVv[ic].X->ButtClose == w) {
01773          if (LocalHead) fprintf (SUMA_STDERR,"%s: Close order from button.\n", FuncName);
01774          Found = 1;
01775       }
01776       #endif
01777       if (SUMAg_SVv[ic].X->TOPLEVEL == w) {
01778          if (LocalHead) fprintf (SUMA_STDERR,"%s: Close order from window manager.\n", FuncName);
01779          Found = 1;
01780       }else if (SUMAg_SVv[ic].X->GLXAREA == w) { 
01781          if (LocalHead) fprintf (SUMA_STDERR,"%s: Close order from GLX area.\n", FuncName);
01782          Found = 1;
01783       }
01784       
01785       if (!Found) ++ic;
01786    }
01787    
01788    if (Found) {
01789          if (LocalHead) fprintf (SUMA_STDERR,"%s: Widget Found\n", FuncName);
01790          
01791          /* Must turn off all workprocesses and timeouts for this surface viewer */
01792          
01793          if (LocalHead) fprintf (SUMA_STDERR,"%s: Turning off workprocesses and timeouts ...\n", FuncName);
01794          if (SUMAg_SVv[ic].GVS[SUMAg_SVv[ic].StdView].ApplyMomentum) {
01795             if (SUMAg_SVv[ic].X->MOMENTUMID) XtRemoveTimeOut(SUMAg_SVv[ic].X->MOMENTUMID); 
01796             SUMAg_SVv[ic].X->MOMENTUMID = 0;
01797          }
01798          
01799          /* remove Redisplay workprocess*/
01800          SUMA_remove_workproc2( SUMA_handleRedisplay, SUMAg_SVv[ic].X->GLXAREA );
01801          
01802          /* flush display */
01803          if (SUMAg_SVv[ic].X->DOUBLEBUFFER)
01804              glXSwapBuffers(SUMAg_SVv[ic].X->DPY, XtWindow(SUMAg_SVv[ic].X->GLXAREA));
01805           else
01806             glFlush();
01807          
01808          /* done cleaning up, deal with windows ... */
01809          
01810          /** Fri Jan  3 09:51:35 EST 2003
01811              XtUnrealizeWidget is not used anymore because it destroys windows associated with a widget and its descendants.
01812             There's no need for that here. 
01813             Also, destroying widgets should not be used either because that would automatically destroy the SUMA controller which is a 
01814             child of one of the viewers. The code for destroy is left for historical reasons.*/
01815          #ifdef SUMA_USE_WITHDRAW 
01816             if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing it.\n", FuncName);
01817             XWithdrawWindow(SUMAg_SVv[ic].X->DPY, 
01818                XtWindow(SUMAg_SVv[ic].X->TOPLEVEL), 
01819                XScreenNumberOfScreen(XtScreen(SUMAg_SVv[ic].X->TOPLEVEL)));
01820             if (SUMAg_SVv[ic].X->ViewCont->TopLevelShell) {
01821                XWithdrawWindow(SUMAg_SVv[ic].X->DPY, 
01822                XtWindow(SUMAg_SVv[ic].X->ViewCont->TopLevelShell),
01823                XScreenNumberOfScreen(XtScreen(SUMAg_SVv[ic].X->ViewCont->TopLevelShell)));
01824             }
01825          #endif
01826          #ifdef SUMA_USE_DESTROY 
01827             if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying it.\n", FuncName);
01828             XtDestroyWidget(SUMAg_SVv[ic].X->TOPLEVEL);
01829             SUMAg_SVv[ic].X->TOPLEVEL = NULL;      
01830             
01831             /* no need to destroy viewer controller */
01832             SUMAg_SVv[ic].X->ViewCont->TopLevelShell = NULL;
01833             
01834             /* update the count */
01835             SUMAg_N_SVv -= 1;
01836 
01837          #endif
01838 
01839          SUMAg_SVv[ic].Open = NOPE;
01840          --SUMAg_CF->N_OpenSV;
01841          if (SUMAg_CF->N_OpenSV == 0) {
01842             if (LocalHead) fprintf (SUMA_STDERR,"%s: No more viewers, exiting.\n", FuncName);
01843             /* not quite necessary but for completeness */
01844             if (SUMAg_CF->X->SumaCont->AppShell) {
01845                XtDestroyWidget(SUMAg_CF->X->SumaCont->AppShell);
01846             }
01847             exit(0);
01848          }
01849    } else {
01850       fprintf (SUMA_STDERR,"Error %s: Widget not Found!.\n", FuncName);
01851    }
01852    
01853     SUMA_RETURNe;
01854 }
01855 
01856 Colormap SUMA_getShareableColormap_Eng (XVisualInfo * vi, Display *dpy) 
01857 {
01858    Status status;
01859    XStandardColormap *standardCmaps;
01860    int i, numCmaps;
01861    Colormap cmap;
01862    SUMA_Boolean LocalHead = NOPE;
01863    static char FuncName[]={"SUMA_getShareableColormap_Eng"};
01864    
01865    SUMA_ENTRY;
01866 
01867    /* Be lazy; using DirectColor too involved for this example. */
01868 #if defined(__cplusplus) || defined(c_plusplus)
01869    if (vi->c_class != TrueColor) {
01870       SUMA_S_Crit("SUMA has no support for non-TrueColor visual");
01871       exit(1);
01872    }
01873 #else 
01874    if (vi->class != TrueColor) {
01875       SUMA_S_Crit("SUMA has no no support for non-TrueColor visual");
01876       exit(1);
01877    }
01878 #endif
01879 
01880    /* If no standard colormap but TrueColor, just make an
01881      unshared one. */
01882    status = XmuLookupStandardColormap(dpy, vi->screen, vi->visualid,
01883     vi->depth, XA_RGB_DEFAULT_MAP,
01884     False,              /* Replace. */
01885     True);              /* Retain. */
01886    if (status == 1) {
01887     status = XGetRGBColormaps(dpy, RootWindow(dpy, vi->screen),
01888       &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP);
01889     if (status == 1)
01890       for (i = 0; i < numCmaps; i++)
01891         if (standardCmaps[i].visualid == vi->visualid) {
01892           cmap = standardCmaps[i].colormap;
01893           XFree(standardCmaps);
01894           SUMA_RETURN(cmap);
01895         }
01896    }
01897   cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone);
01898 
01899   SUMA_RETURN(cmap);
01900 
01901 }
01902 Colormap
01903 SUMA_getShareableColormap(SUMA_SurfaceViewer *csv)
01904 {
01905    SUMA_Boolean LocalHead = NOPE;
01906    static char FuncName[]={"SUMA_getShareableColormap"};
01907    
01908    SUMA_ENTRY;
01909 
01910    SUMA_RETURN(SUMA_getShareableColormap_Eng(csv->X->VISINFO, csv->X->DPY));
01911 }
01912 
01913 void SUMA_SetcSV (Widget w, XtPointer clientData, XEvent * event, Boolean * cont)
01914 {
01915    static char FuncName[]={"SUMA_SetcSV"};
01916    SUMA_SurfaceViewer *sv;
01917    int isv;
01918    SUMA_Boolean LocalHead = NOPE;
01919    
01920    SUMA_ENTRY;
01921    
01922    if (LocalHead) fprintf(SUMA_STDERR,"%s:\n Called, w = %p\n", FuncName, w);
01923    
01924 
01925    /* When using multiple viewers, you must reset the OpenGL state variables or risk having abrupt changes with the first click */
01926    SUMA_ANY_WIDGET2SV(w, sv, isv);
01927    if (isv < 0) {
01928       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
01929       SUMA_RETURNe;
01930    }
01931 
01932    #ifdef DARWIN
01933       /* Set the focus manually.
01934       If you're not using motif widgets, window focus is not managed.
01935       You can manage it yourself with XSetInputFocus when the EnterWindowEvent is captured.
01936       You don't need to do that however if you link (for some reason) to -lXm.
01937       But on the macosx10, -lXm does not help, so we manage the foucs ourselves */
01938       /* The downside is that this call seems to be related to a crash on the mac,
01939       reported as a complaint coming from X_SetInputFocus.
01940       The crash happened when multiple viewers were open and one of them was closed
01941       AND suma was set to prompt the user with "Close this viewer?"
01942       I tried resetting the focus to a viewer that is not being closed before
01943       closing the reviewer as requested by the user but that did not help.
01944       It turns out that the problem does not occur if the prompt window does not
01945       appear on top of the viewer to be closed. More precisely, if the pointer ends
01946       up on top of the viewer just after the prompt window disapears SUMA crashes with the 
01947       message: X Error of failed request: BadMatch (invalid parameter attributes) ...
01948       The solution is simple, on DARWIN, make sure prompt window appears to the right
01949       of the viewer. If the user moves it back over the viewer AND then presses YES to close 
01950       the viewer then they will suffer the crash. June 15 04*/
01951 
01952       XSetInputFocus(sv->X->DPY, XtWindow(w), RevertToPointerRoot, CurrentTime);
01953    #endif
01954 
01955    sv->rdc = SUMA_RDC_X_ENTER_WINDOW;
01956    
01957    if (LocalHead) fprintf (SUMA_STDERR, "%s: in Surface Viewer #%d.\n", FuncName, isv);
01958    sv->ResetGLStateVariables = YUP;  
01959 
01960    SUMA_postRedisplay(w, clientData, NULL);
01961 
01962    
01963    SUMA_RETURNe;
01964 }
01965 
01966 void SUMA_unSetcSV (Widget w, XtPointer clientData, XEvent * event, Boolean * cont)
01967 {
01968    static char FuncName[]={"SUMA_unSetcSV"};
01969    
01970    SUMA_ENTRY;
01971    SUMA_RETURNe;
01972 }
01973 
01974 /* ------------------------------------------------------------------------------------------------------------*/
01975 /*! 
01976  
01977  functions SUMA_generateEPS, SUMA_grabPixels, SUMA_RenderToPixMap are straight from pixmap2eps.c
01978 
01979  COPYRIGHT NOTICE FROM pixmap2eps.c
01980  Copyright (c) Mark J. Kilgard, 1996. 
01981 
01982  This program is freely distributable without licensing fees 
01983    and is provided without guarantee or warrantee expressed or 
01984    implied. This program is -not- in the public domain. 
01985 
01986  \sa OpenGl, Programming for the X Window System, pp 94, 95
01987  
01988 */
01989 
01990 int
01991 SUMA_generateEPS(char *filename, int inColor, unsigned int width, unsigned int height)
01992 {
01993    FILE *fp;
01994    GLvoid *pixels;
01995    unsigned char *curpix;
01996    int components, pos, i;
01997    static char FuncName[]={"SUMA_generateEPS"};
01998    
01999    SUMA_ENTRY;
02000 
02001    pixels = SUMA_grabPixels(inColor, width, height);
02002    
02003    if (pixels == NULL)
02004     SUMA_RETURN (1);
02005    if (inColor)
02006     components = 3;     /* Red, green, blue. */
02007    else
02008     components = 1;     /* Luminance. */
02009 
02010    fp = fopen(filename, "w");
02011    if (fp == NULL) {
02012     SUMA_RETURN (2);
02013    }
02014    fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
02015    fprintf(fp, "%%%%Creator: OpenGL pixmap render output\n");
02016    fprintf(fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
02017    fprintf(fp, "%%%%EndComments\n");
02018    fprintf(fp, "gsave\n");
02019    fprintf(fp, "/bwproc {\n");
02020    fprintf(fp, "    rgbproc\n");
02021    fprintf(fp, "    dup length 3 idiv string 0 3 0\n");
02022    fprintf(fp, "    5 -1 roll {\n");
02023    fprintf(fp, "    add 2 1 roll 1 sub dup 0 eq\n");
02024    fprintf(fp, "    { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n");
02025    fprintf(fp, "        3 1 roll 5 -1 roll put 1 add 3 0 }\n");
02026    fprintf(fp, "    { 2 1 roll } ifelse\n");
02027    fprintf(fp, "    } forall\n");
02028    fprintf(fp, "    pop pop pop\n");
02029    fprintf(fp, "} def\n");
02030    fprintf(fp, "systemdict /colorimage known not {\n");
02031    fprintf(fp, "    /colorimage {\n");
02032    fprintf(fp, "        pop\n");
02033    fprintf(fp, "        pop\n");
02034    fprintf(fp, "        /rgbproc exch def\n");
02035    fprintf(fp, "        { bwproc } image\n");
02036    fprintf(fp, "    } def\n");
02037    fprintf(fp, "} if\n");
02038    fprintf(fp, "/picstr %d string def\n", width * components);
02039    fprintf(fp, "%d %d scale\n", width, height);
02040    fprintf(fp, "%d %d %d\n", width, height, 8);
02041    fprintf(fp, "[%d 0 0 %d 0 0]\n", width, height);
02042    fprintf(fp, "{currentfile picstr readhexstring pop}\n");
02043    fprintf(fp, "false %d\n", components);
02044    fprintf(fp, "colorimage\n");
02045 
02046    curpix = (unsigned char *) pixels;
02047    pos = 0;
02048    for (i = width * height * components; i > 0; i--) {
02049     fprintf(fp, "%02hx", *curpix++);
02050     if (++pos >= 32) {
02051       fprintf(fp, "\n");
02052       pos = 0;
02053     }
02054    }
02055    if (pos)
02056     fprintf(fp, "\n");
02057 
02058    fprintf(fp, "grestore\n");
02059    SUMA_free(pixels);
02060    fclose(fp);
02061    SUMA_RETURN (0);
02062 }
02063 
02064 GLvoid *
02065 SUMA_grabPixels(int inColor, unsigned int width, unsigned int height)
02066 {
02067    GLvoid *buffer;
02068    GLint swapbytes, lsbfirst, rowlength;
02069    GLint skiprows, skippixels, alignment;
02070    GLenum format;
02071    unsigned int size;
02072    static char FuncName[]={"SUMA_grabPixels"};
02073 
02074    SUMA_ENTRY;
02075    
02076    if (inColor) {
02077     format = GL_RGB;
02078     size = width * height * 3;
02079    } else {
02080     format = GL_LUMINANCE;
02081     size = width * height * 1;
02082    }
02083 
02084    buffer = (GLvoid *) SUMA_malloc(size);
02085    if (buffer == NULL)
02086     SUMA_RETURN (buffer);
02087 
02088    /* Save current modes. */
02089    glGetIntegerv(GL_PACK_SWAP_BYTES, &swapbytes);
02090    glGetIntegerv(GL_PACK_LSB_FIRST, &lsbfirst);
02091    glGetIntegerv(GL_PACK_ROW_LENGTH, &rowlength);
02092    glGetIntegerv(GL_PACK_SKIP_ROWS, &skiprows);
02093    glGetIntegerv(GL_PACK_SKIP_PIXELS, &skippixels);
02094    glGetIntegerv(GL_PACK_ALIGNMENT, &alignment);
02095    /* Little endian machines (DEC Alpha for example) could
02096      benefit from setting GL_PACK_LSB_FIRST to GL_TRUE
02097      instead of GL_FALSE, but this would require changing the
02098      generated bitmaps too. */
02099    glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE);
02100    glPixelStorei(GL_PACK_LSB_FIRST, GL_TRUE);
02101    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
02102    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
02103    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
02104    glPixelStorei(GL_PACK_ALIGNMENT, 1);
02105 
02106    /* Actually read the pixels. */
02107    glReadPixels(0, 0, width, height, format,
02108     GL_UNSIGNED_BYTE, (GLvoid *) buffer);
02109 
02110    /* Restore saved modes. */
02111    glPixelStorei(GL_PACK_SWAP_BYTES, swapbytes);
02112    glPixelStorei(GL_PACK_LSB_FIRST, lsbfirst);
02113    glPixelStorei(GL_PACK_ROW_LENGTH, rowlength);
02114    glPixelStorei(GL_PACK_SKIP_ROWS, skiprows);
02115    glPixelStorei(GL_PACK_SKIP_PIXELS, skippixels);
02116    glPixelStorei(GL_PACK_ALIGNMENT, alignment);
02117    SUMA_RETURN (buffer);
02118 }
02119  
02120 
02121 SUMA_Boolean SUMA_RenderToPixMap (SUMA_SurfaceViewer *csv, SUMA_DO *dov) 
02122 {
02123    static int configuration[] = { GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16,
02124    GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
02125    Display *dpy;
02126    XVisualInfo *vi;
02127    GLXContext cx;
02128    Pixmap pmap;
02129    GLXPixmap glxpmap;
02130    static char FuncName[]={"SUMA_RenderToPixMap"};
02131 
02132    SUMA_ENTRY;
02133 
02134    dpy = XOpenDisplay(NULL);
02135    if (dpy == NULL)
02136     fprintf(SUMA_STDERR,"Error %s: could not open display", FuncName);
02137 
02138    if (!glXQueryExtension(dpy, NULL, NULL))
02139     fprintf(SUMA_STDERR,"Error %s: X server has no OpenGL GLX extension", FuncName);
02140 
02141    /* find an OpenGL-capable RGB visual with depth buffer */
02142    #if 1  /* use screen rendering Xvisual */
02143    vi = glXChooseVisual(dpy, DefaultScreen(dpy), &configuration[1]);
02144    if (vi == NULL) {
02145    /*fprintf(SUMA_STDERR,"%s: Trying to use useless double buffering configuration.\n", FuncName);*/
02146     vi = glXChooseVisual(dpy, DefaultScreen(dpy), &configuration[0]);
02147     if (vi == NULL) {
02148       fprintf(SUMA_STDERR,"Error %s: no appropriate RGB visual with depth buffer", FuncName);
02149     }
02150    }
02151    #else
02152    vi = csv->X->VISINFO;
02153    #endif
02154 
02155 
02156    /* create an OpenGL rendering context */
02157    cx = glXCreateContext(dpy, vi,
02158     NULL,               /* no sharing of display lists */
02159     False);             /* direct rendering if possible */
02160    if (cx == NULL)
02161     fprintf(SUMA_STDERR,"Error %s: could not create rendering context", FuncName);
02162 
02163    pmap = XCreatePixmap(dpy, RootWindow(dpy, vi->screen),
02164     csv->X->WIDTH, csv->X->HEIGHT, vi->depth);
02165    glxpmap = glXCreateGLXPixmap(dpy, vi, pmap);
02166    if (!glXMakeCurrent(dpy, glxpmap, cx)) {
02167       fprintf (SUMA_STDERR, "Error %s: Failed in glXMakeCurrent.\n \tContinuing ...\n", FuncName);
02168    }
02169 
02170    SUMA_context_Init(csv);
02171    glViewport(0, 0, csv->X->WIDTH, csv->X->HEIGHT);
02172    SUMA_display(csv, dov);
02173 
02174    glFinish (); /* make sure you wait until rendering is over */
02175 
02176    /* find out the next best name and write it*/
02177    {
02178         char tmpprfx[100], *padprfx, *padname;
02179       int cntindx=0;
02180       SUMA_SurfaceObject *SO;
02181       SUMA_Boolean OKname = NOPE;
02182       
02183       /* get the SO in focus, use it's label for output filename */
02184       if (csv->Focus_SO_ID >= 0) {
02185          SO = (SUMA_SurfaceObject *)(SUMAg_DOv[csv->Focus_SO_ID].OP);
02186       }else {
02187          SO = NULL;
02188       }
02189       
02190       if (!SO){
02191          padname = (char *)SUMA_calloc(100, sizeof(char));
02192       }else {
02193          if (!SO->Label) { /* nothing set, proceed with default */
02194             padname = (char *)SUMA_calloc(100, sizeof(char));
02195          } else {
02196             padname = (char *)SUMA_calloc(strlen(SO->Label)+10, sizeof(char));
02197          }
02198       }
02199       while (!OKname) {
02200          sprintf (tmpprfx, "%d", cntindx);
02201          padprfx = SUMA_pad_str (tmpprfx, '0', 4, 0);
02202          if (!SO) {
02203             sprintf(padname,"suma_img%s.eps", padprfx);
02204          }else {
02205             sprintf(padname,"%s_%s.eps", SO->Label, padprfx);
02206          }
02207          if (SUMA_filexists(padname)) {
02208             ++cntindx;
02209          } else { OKname = YUP; }
02210 
02211          SUMA_free(padprfx);
02212       }
02213 
02214      fprintf (SUMA_STDOUT,"%s: Writing image to %s ...", FuncName, padname);
02215      SUMA_generateEPS(padname, /* color */ 1, csv->X->WIDTH, csv->X->HEIGHT);
02216      fprintf (SUMA_STDOUT,"Done.\n");
02217      SUMA_free(padname);
02218    }
02219 
02220    /* render to original context */
02221    if (!glXMakeCurrent(XtDisplay(csv->X->GLXAREA), XtWindow(csv->X->GLXAREA),  csv->X->GLXCONTEXT)) {
02222       fprintf (SUMA_STDERR, "Error %s: Failed in glXMakeCurrent.\n \tContinuing ...\n", FuncName);   
02223    }
02224 
02225    SUMA_RETURN (YUP);
02226 }
02227 
02228 /* ------------------------------------------------------------------------------------------------------------*/
02229 
02230 /*!
02231    Purpose: Takes a the world x,y,z coordinates and turns them into screen coordinates
02232    Set the last param to 0 (or NOPE) if you are calling this function after the projection 
02233    and other viewing matrices have been set. This happens when this function is called as
02234    a child of SUMA_display
02235    \sa SUMA_GetSelectionLine
02236 */
02237 SUMA_Boolean SUMA_World2ScreenCoords (SUMA_SurfaceViewer *sv, int N_List, double *WorldList, 
02238                               double *ScreenList, int *Quad, SUMA_Boolean ApplyXform)
02239 {
02240    static char FuncName[]={"SUMA_World2ScreenCoords"};
02241    GLfloat rotationMatrix[4][4];
02242    GLint viewport[4];
02243    GLdouble mvmatrix[16], projmatrix[16];
02244    int i, i3;
02245    char CommString[100];
02246    SUMA_Boolean LocalHead = NOPE;
02247    
02248    SUMA_ENTRY;
02249    
02250    if (LocalHead) {
02251       fprintf (SUMA_STDERR, "%s: Current Quat: %.4f, %.4f, %.4f, %.4f.\n", \
02252        FuncName, sv->GVS[sv->StdView].currentQuat[0], sv->GVS[sv->StdView].currentQuat[1], \
02253        sv->GVS[sv->StdView].currentQuat[2],sv->GVS[sv->StdView].currentQuat[3]);
02254       fprintf (SUMA_STDERR, "%s: Translation Vector of view #%d: %.4f, %.4f, %.4f\n", \
02255          FuncName, sv->StdView, sv->GVS[sv->StdView].translateVec[0], sv->GVS[sv->StdView].translateVec[1], \
02256          sv->GVS[sv->StdView].translateVec[2]);
02257       fprintf (SUMA_STDERR, "%s: RotaCenter of view #%d: %.4f, %.4f, %.4f\n", \
02258          FuncName, sv->StdView, sv->GVS[sv->StdView].RotaCenter[0], sv->GVS[sv->StdView].RotaCenter[1], \
02259          sv->GVS[sv->StdView].RotaCenter[2]);
02260    }
02261       
02262    
02263    if (ApplyXform) {
02264       /* go through the ModelView transforms as you would in display since the modelview matrix is popped
02265       after each display call */
02266       SUMA_build_rotmatrix(rotationMatrix, sv->GVS[sv->StdView].currentQuat);
02267       glMatrixMode(GL_MODELVIEW);
02268       /* The next line appears to fix some bug with GL_MODELVIEW's matrix. When you clicked button3 for the first time in a viewer, 
02269       the chosen point was off. The next click in the identical position would select the correct point and subsequent clicks are OK.
02270       None of the parameters used for the selection would change between the first click and the next but it appears that going from one
02271       viewer to the next caused GL_MODELVIEW to change (sometimes) slightly. Putting the line glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02272       to check (and debug) what was happening to GL_MODELVIEW matrix between one viewer and the next fixed the clicking problem. So, we keep
02273       it here as a fix until a better one comes along. PS: This was also the source of the Z (blue) eye axis showing up when it should not. */  
02274          glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02275          if (LocalHead) {
02276             int itmp = 0;
02277             fprintf (SUMA_STDERR, "%s: Initial Modelview:\nMV=[ ", FuncName);
02278             while (itmp < 16) { fprintf (SUMA_STDERR, "%.4f, ", mvmatrix[itmp]); ++itmp;}
02279             fprintf (SUMA_STDERR, "]\n");
02280          }
02281       glPushMatrix();
02282       glTranslatef (sv->GVS[sv->StdView].translateVec[0], sv->GVS[sv->StdView].translateVec[1], 0.0);
02283       glTranslatef (sv->GVS[sv->StdView].RotaCenter[0], sv->GVS[sv->StdView].RotaCenter[1], sv->GVS[sv->StdView].RotaCenter[2]);
02284       glMultMatrixf(&rotationMatrix[0][0]);
02285          glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02286          if (LocalHead) {
02287             int itmp = 0;
02288             fprintf (SUMA_STDERR, "%s: Modelview After Translation & Rotation:\nMVtr=[ ", FuncName);
02289             while (itmp < 16) { fprintf (SUMA_STDERR, "%.4f, ", mvmatrix[itmp]); ++itmp;}
02290             fprintf (SUMA_STDERR, "]\n");
02291          }
02292       glTranslatef (-sv->GVS[sv->StdView].RotaCenter[0], -sv->GVS[sv->StdView].RotaCenter[1], -sv->GVS[sv->StdView].RotaCenter[2]);
02293    } 
02294    glGetIntegerv(GL_VIEWPORT, viewport);
02295    glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02296    glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
02297    
02298    for (i=0;i<N_List; ++i) {
02299       i3 = 3*i;
02300       gluProject( (GLdouble)WorldList[i3], (GLdouble)WorldList[i3+1], (GLdouble)WorldList[i3+2],  
02301                   mvmatrix, projmatrix, viewport, \
02302                   (GLdouble*)(&(ScreenList[i3])), (GLdouble*)(&(ScreenList[i3+1])), (GLdouble*)(&(ScreenList[i3+2])) );
02303       ScreenList[i3+1] = viewport[3] - ScreenList[i3+1] - 1; /* change from OpenGL's y to screen's y */
02304       if (ScreenList[i3] < sv->WindWidth/2) {
02305          if (ScreenList[i3+1] > sv->WindHeight/2) Quad[i] = SUMA_LOWER_LEFT_SCREEN;
02306          else Quad[i] = SUMA_UPPER_LEFT_SCREEN;
02307       } else {
02308          if (ScreenList[i3+1] > sv->WindHeight/2) Quad[i] = SUMA_LOWER_RIGHT_SCREEN;
02309          else Quad[i] = SUMA_UPPER_RIGHT_SCREEN;
02310       }
02311       if (LocalHead) fprintf (SUMA_STDOUT, "%s: World: [%.2f %.2f %.2f] \t Screen [%.2f %.2f %.2f] \t Quad %d\n", 
02312                               FuncName, WorldList[i3],WorldList[i3+1], WorldList[i3+2], 
02313                               ScreenList[i3], ScreenList[i3+1],ScreenList[i3+2], Quad[i]);
02314    
02315    }
02316 
02317    if (ApplyXform) glPopMatrix();
02318 
02319    SUMA_RETURN (YUP);
02320 }
02321 
02322 /*!
02323    Purpose: Takes a the x,y positions of the cursor and sets the Pick0 and Pick1 values (usually sv's) 
02324    \param sv (*SUMA_SurfaceViewer)
02325    \param x (int) mouse coordinate
02326    \param y (int)
02327    \param Pick0 (GLdouble *) vector of 3 elements (usually, pass sv->Pick0)
02328    \param Pick1 (GLdouble *) vector of 3 elements (usually, pass sv->Pick1)
02329    \param N_List (int) if > 0, it indicates that there are N_list other mouse coordinates
02330                               to consider in addition to the y and y above.
02331    \param xList (int *) a vector of N_list x values
02332    \param yList (int *) a vector of N_list y values
02333    \param PickList (Gldouble *) a N_list x 3 vector containing the equivalent of Pick0 
02334                                  for the values in xList and yList
02335    \return YUP/NOPE
02336    \sa SUMA_input, button3 pick
02337    \sa 
02338 */
02339 SUMA_Boolean SUMA_GetSelectionLine (SUMA_SurfaceViewer *sv, int x, int y, GLdouble *Pick0, GLdouble *Pick1, 
02340                                     int N_List, int *xList, int *yList, GLdouble *Pick0List)
02341 {
02342    static char FuncName[]={"SUMA_GetSelectionLine"};
02343    GLfloat rotationMatrix[4][4];
02344    GLint viewport[4];
02345    GLdouble mvmatrix[16], projmatrix[16];
02346    GLint realy; /* OpenGL y coordinate position */
02347    char CommString[100];
02348    SUMA_Boolean LocalHead = NOPE;
02349    
02350    SUMA_ENTRY;
02351    
02352    
02353    
02354    if (LocalHead) {
02355       fprintf (SUMA_STDERR, "%s: Current Quat: %.4f, %.4f, %.4f, %.4f.\n", \
02356        FuncName, sv->GVS[sv->StdView].currentQuat[0], sv->GVS[sv->StdView].currentQuat[1], \
02357        sv->GVS[sv->StdView].currentQuat[2],sv->GVS[sv->StdView].currentQuat[3]);
02358       fprintf (SUMA_STDERR, "%s: Translation Vector of view #%d: %.4f, %.4f, %.4f\n", \
02359          FuncName, sv->StdView, sv->GVS[sv->StdView].translateVec[0], sv->GVS[sv->StdView].translateVec[1], \
02360          sv->GVS[sv->StdView].translateVec[2]);
02361       fprintf (SUMA_STDERR, "%s: RotaCenter of view #%d: %.4f, %.4f, %.4f\n", \
02362          FuncName, sv->StdView, sv->GVS[sv->StdView].RotaCenter[0], sv->GVS[sv->StdView].RotaCenter[1], \
02363          sv->GVS[sv->StdView].RotaCenter[2]);
02364    }
02365       
02366    
02367    /* go through the ModelView transforms as you would in display since the modelview matrix is popped
02368    after each display call */
02369    SUMA_build_rotmatrix(rotationMatrix, sv->GVS[sv->StdView].currentQuat);
02370    glMatrixMode(GL_MODELVIEW);
02371    /* The next line appears to fix some bug with GL_MODELVIEW's matrix. When you clicked button3 for the first time in a viewer, 
02372    the chosen point was off. The next click in the identical position would select the correct point and subsequent clicks are OK.
02373    None of the parameters used for the selection would change between the first click and the next but it appears that going from one
02374    viewer to the next caused GL_MODELVIEW to change (sometimes) slightly. Putting the line glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02375    to check (and debug) what was happening to GL_MODELVIEW matrix between one viewer and the next fixed the clicking problem. So, we keep
02376    it here as a fix until a better one comes along. PS: This was also the source of the Z (blue) eye axis showing up when it should not. */  
02377       glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02378       if (LocalHead) {
02379          int itmp = 0;
02380          fprintf (SUMA_STDERR, "%s: Initial Modelview:\nMV=[ ", FuncName);
02381          while (itmp < 16) { fprintf (SUMA_STDERR, "%.4f, ", mvmatrix[itmp]); ++itmp;}
02382          fprintf (SUMA_STDERR, "]\n");
02383       }
02384    glPushMatrix();
02385    glTranslatef (sv->GVS[sv->StdView].translateVec[0], sv->GVS[sv->StdView].translateVec[1], 0.0);
02386    glTranslatef (sv->GVS[sv->StdView].RotaCenter[0], sv->GVS[sv->StdView].RotaCenter[1], sv->GVS[sv->StdView].RotaCenter[2]);
02387    glMultMatrixf(&rotationMatrix[0][0]);
02388       glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02389       if (LocalHead) {
02390          int itmp = 0;
02391          fprintf (SUMA_STDERR, "%s: Modelview After Translation & Rotation:\nMVtr=[ ", FuncName);
02392          while (itmp < 16) { fprintf (SUMA_STDERR, "%.4f, ", mvmatrix[itmp]); ++itmp;}
02393          fprintf (SUMA_STDERR, "]\n");
02394       }
02395    glTranslatef (-sv->GVS[sv->StdView].RotaCenter[0], -sv->GVS[sv->StdView].RotaCenter[1], -sv->GVS[sv->StdView].RotaCenter[2]);
02396 
02397    glGetIntegerv(GL_VIEWPORT, viewport);
02398    glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
02399    glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
02400    /* viewport[3] is height of window in pixels */
02401    realy = viewport[3] - (GLint)y -1;
02402 
02403    if (LocalHead) fprintf (SUMA_STDOUT, "%s: Coordinates at cursor are (%4d, %4d)\n", FuncName, x, realy);
02404 
02405    /* set the pick points at both ends of the clip planes */
02406    if (Pick0) {
02407       gluUnProject((GLdouble)x, (GLdouble)realy, 0.0,\
02408          mvmatrix, projmatrix, viewport, \
02409          &(Pick0[0]), &(Pick0[1]), &(Pick0[2]));
02410       if (LocalHead) fprintf (SUMA_STDOUT, "World Coords at z=0.0 (near clip plane) are (%f, %f, %f)\n",\
02411          (Pick0[0]), (Pick0[1]), (Pick0[2]));
02412    }
02413    if (Pick1) {
02414       gluUnProject((GLdouble)x, (GLdouble)realy, 1.0,\
02415          mvmatrix, projmatrix, viewport, \
02416          &(Pick1[0]), &(Pick1[1]), &(Pick1[2]));
02417       if (LocalHead) fprintf (SUMA_STDOUT, "World Coords at z=1.0 (far clip plane) are (%f, %f, %f)\n",\
02418          (Pick1[0]), (Pick1[1]), (Pick1[2]));
02419    }
02420 
02421    if (N_List > 0) {
02422       SUMA_LH("Doing the list thing");
02423       if (!Pick0List || !xList || !yList) { SUMA_S_Err("Null Pick0List or xlist or ylist with non 0 N_List.\nPickList ignored."); }
02424       else {
02425          int i, i3;
02426          for (i=0; i<N_List; ++i) {
02427             i3 = 3*i;
02428             realy = viewport[3] - (GLint)yList[i] -1;
02429             gluUnProject((GLdouble)xList[i], (GLdouble)realy, 0.0,\
02430                            mvmatrix, projmatrix, viewport, \
02431                            &(Pick0List[i3+0]), &(Pick0List[i3+1]), &(Pick0List[i3+2]));
02432          }
02433       }  
02434    }
02435    glPopMatrix();
02436 
02437    SUMA_RETURN (YUP);
02438 }
02439 
02440 /*!
02441    \brief Draws a line between screen (window) coordinates 
02442 */
02443 SUMA_Boolean SUMA_DrawWindowLine(SUMA_SurfaceViewer *sv, int x0, int y0, int x1, int y1, int meth)
02444 {
02445    static char FuncName[]={"SUMA_DrawWindowLine"};
02446    GLfloat rotationMatrix[4][4];
02447    static GLfloat LineCol[]={ SUMA_RED_GL };
02448    static int xlist[2], ylist[2];
02449    GLdouble Pick0[3], Pick1[3], PickList[6];
02450    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};   
02451    SUMA_Boolean LocalHead  = NOPE;
02452    SUMA_ENTRY;
02453 
02454    switch (meth) {
02455       case 0: /* does not work on OSX */
02456          XDrawLine (sv->X->DPY, XtWindow(sv->X->GLXAREA), sv->X->gc, 
02457            (int)x0, (int)y0,
02458            (int)x1, (int)y1);
02459          break;
02460       case 1:
02461          SUMA_build_rotmatrix(rotationMatrix, sv->GVS[sv->StdView].currentQuat);
02462          xlist[0] = x0; xlist[1] = x1;
02463          ylist[0] = y0; ylist[1] = y1;
02464          SUMA_GetSelectionLine (sv, x0, y0, NULL, NULL, 2, xlist, ylist, PickList);
02465          SUMA_SET_GL_PROJECTION(sv);
02466          SUMA_SET_GL_MODELVIEW(sv);
02467          glMaterialfv(GL_FRONT, GL_EMISSION, LineCol);
02468          glLineWidth(SUMA_CROSS_HAIR_LINE_WIDTH);
02469          if (LocalHead) {
02470             fprintf(SUMA_STDERR,"%s:PickList\n[%.3f %.3f %.3f\n %.3f %.3f %.3f]\n", FuncName,
02471                      PickList[0],PickList[1],PickList[2],PickList[3], PickList[4],PickList[5] );
02472          }
02473          glBegin(GL_LINES);
02474          glVertex3d(PickList[0], PickList[1], PickList[2]-0.001); /* something to do with clipping ...*/
02475          glVertex3d(PickList[3], PickList[4], PickList[5]-0.001);
02476          glVertex3d(PickList[0], PickList[1], PickList[2]+0.001); /* something to do with clipping ...*/
02477          glVertex3d(PickList[3], PickList[4], PickList[5]+0.001);
02478          glEnd();
02479          glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
02480          glPopMatrix();   
02481          if (sv->X->DOUBLEBUFFER)
02482              glXSwapBuffers(sv->X->DPY, XtWindow(sv->X->GLXAREA));
02483           else
02484             glFlush();         
02485          break;
02486       default:
02487          break;
02488    }
02489 
02490    SUMA_RETURN(YUP);
02491 }
02492 
02493 
02494 /*!
02495    \brief A call back to open the help window 
02496    No input parameters needed
02497 */
02498 void SUMA_cb_helpUsage (Widget w, XtPointer data, XtPointer callData)
02499 {
02500    static char FuncName[] = {"SUMA_cb_helpUsage"};
02501    DList *list = NULL;
02502    
02503    SUMA_ENTRY;
02504    if (!list) list = SUMA_CreateList();
02505    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Help, SES_Suma, NULL); 
02506    if (!SUMA_Engine (&list)) {
02507       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
02508    }
02509    
02510    SUMA_RETURNe;
02511 
02512 }
02513 
02514 /*!
02515    \brief A call back to open the Message Log window 
02516    No input parameters needed
02517 */
02518 void SUMA_cb_helpMessageLog (Widget w, XtPointer data, XtPointer callData)
02519 {
02520    static char FuncName[] = {"SUMA_cb_helpMessageLog"};
02521    DList *list = NULL;
02522    
02523    SUMA_ENTRY;
02524    if (!list) list = SUMA_CreateList();
02525    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Log, SES_Suma, NULL); 
02526    if (!SUMA_Engine (&list)) {
02527       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
02528    }
02529    
02530    SUMA_RETURNe;
02531 
02532 }
02533 
02534 /*!
02535    \brief A call back to open the viewer Info window 
02536    Exepcts the index of the viewer in SUMAg_SVv in data->ContID
02537 */
02538 void SUMA_cb_helpViewerStruct (Widget w, XtPointer data, XtPointer callData)
02539 {
02540    static char FuncName[] = {"SUMA_cb_helpViewerStruct"};
02541    SUMA_MenuCallBackData *datap=NULL;
02542    SUMA_SurfaceViewer *sv = NULL;
02543    
02544    SUMA_ENTRY;
02545    
02546    datap = (SUMA_MenuCallBackData *)data;
02547    sv = &(SUMAg_SVv[(int)datap->ContID]);
02548    
02549    if (!sv->X->ViewCont->TopLevelShell) { /* see comments on similar section in SUMA_cb_helpSurfaceStruct */
02550       SUMA_cb_createViewerCont( w, (XtPointer)sv, callData);
02551       SUMA_cb_closeViewerCont ( w, (XtPointer)sv, callData); 
02552    }
02553    /* Now do the info thingy */
02554    SUMA_cb_moreViewerInfo (w, (XtPointer)sv, callData);
02555 
02556    
02557    SUMA_RETURNe;
02558 
02559 }
02560 
02561 /*!
02562    \brief A call back to open the surface Info window 
02563    Exepcts the index of the viewer in SUMAg_SVv in data->ContID
02564 */
02565 void SUMA_cb_helpSurfaceStruct (Widget w, XtPointer data, XtPointer callData)
02566 {
02567    static char FuncName[] = {"SUMA_cb_helpSurfaceStruct"};
02568    SUMA_MenuCallBackData *datap=NULL;
02569    SUMA_SurfaceViewer *sv = NULL;
02570    SUMA_SurfaceObject *SO = NULL;
02571    
02572    SUMA_ENTRY;
02573    
02574    datap = (SUMA_MenuCallBackData *)data;
02575    sv = &(SUMAg_SVv[(int)datap->ContID]);
02576    if (sv->Focus_SO_ID >= 0) {
02577       SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
02578    }else {
02579       SUMA_SLP_Err("No surface object in focus.\n");
02580       SUMA_RETURNe;
02581    }
02582 
02583    if (!SO->SurfCont->TopLevelShell) {
02584       /* Before you open the surface info widget, you'll need to open
02585       the surface controller to initialize the Surface Controller first */
02586       SUMA_cb_createSurfaceCont( w, (XtPointer)SO, callData);
02587       /* NOW CLOSE IT, user need not use it.
02588       Could have been a bit more elegant here
02589       but that's good enough*/
02590       SUMA_cb_closeSurfaceCont ( w, (XtPointer)SO, callData); 
02591    }
02592    
02593    /* Now do the info thingy */
02594    SUMA_cb_moreSurfInfo (w, (XtPointer)SO->SurfCont->curSOp, callData);
02595 
02596    SUMA_RETURNe;
02597 
02598 }
02599 
02600 void SUMA_cb_helpSUMAGlobal (Widget w, XtPointer data, XtPointer callData)
02601 {
02602    static char FuncName[] = {"SUMA_cb_helpSUMAGlobal"};
02603    
02604    SUMA_ENTRY;
02605    
02606    if (!SUMAg_CF->X->SumaCont->AppShell) { /* create */
02607       SUMA_cb_createSumaCont( w, data, callData);
02608       SUMA_cb_closeSumaCont ( w, data, callData);
02609    }
02610    
02611    /* Now open the info thingy */
02612    SUMA_cb_moreSumaInfo (w, data, callData);
02613    
02614    SUMA_RETURNe;
02615 }
02616 
02617 /*!
02618  function to toggle the IOnotify debugging flag
02619  - expects nothing
02620 */  
02621 void SUMA_cb_helpIO_notify(Widget w, XtPointer data, XtPointer callData)
02622 {
02623    static char FuncName[] = {"SUMA_cb_helpIO_notify"};
02624    int ii;
02625    
02626    SUMA_ENTRY;
02627    
02628    SUMA_INOUT_NOTIFY_TOGGLE;
02629    
02630    /* must update the state of toggle buttons in otherviewers */
02631    for (ii=0; ii<SUMAg_N_SVv; ++ii) {
02632       if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
02633          /* you must check for both conditions because by default 
02634          all viewers are initialized to isShaded = NOPE, even before they are ever opened */
02635          if (w != SUMAg_SVv[ii].X->HelpMenu[SW_HelpIONotify]) {
02636             XmToggleButtonSetState (SUMAg_SVv[ii].X->HelpMenu[SW_HelpIONotify], 
02637                SUMAg_CF->InOut_Notify, NOPE);
02638          }
02639       }
02640    }
02641    
02642     
02643    SUMA_RETURNe; 
02644 }
02645 
02646 /*!
02647  function to toggle the Memtrace debugging flag
02648  - expects nothing
02649 */  
02650 void SUMA_cb_helpMemTrace(Widget w, XtPointer data, XtPointer callData)
02651 {
02652    static char FuncName[] = {"SUMA_cb_helpIO_notify"};
02653    int ii;
02654    
02655    SUMA_ENTRY;
02656    
02657    SUMA_MEMTRACE_TOGGLE;
02658    
02659    /* must update the state of toggle buttons in otherviewers */
02660    for (ii=0; ii<SUMAg_N_SVv; ++ii) {
02661       if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
02662          /* you must check for both conditions because by default 
02663          all viewers are initialized to isShaded = NOPE, even before they are ever opened */
02664          XmToggleButtonSetState (SUMAg_SVv[ii].X->HelpMenu[SW_HelpMemTrace], 
02665             SUMAg_CF->MemTrace, NOPE);
02666          if (SUMAg_CF->MemTrace) {
02667             /* can't turn it off */
02668              XtSetSensitive (SUMAg_SVv[ii].X->HelpMenu[SW_HelpMemTrace], 0);
02669          }
02670       }
02671    }
02672    
02673    SUMA_RETURNe; 
02674 }
02675 
02676 /*!
02677    \brief callback to open SUMA 's Controller
02678    No input parameters needed
02679 */
02680 void SUMA_cb_viewSumaCont(Widget w, XtPointer data, XtPointer callData)
02681 {
02682    static char FuncName[] = {"SUMA_cb_viewSumaCont"};
02683    Boolean LocalHead = NOPE;
02684    
02685    SUMA_ENTRY;
02686    
02687    if (!SUMAg_CF->X->SumaCont->AppShell) { /* create */
02688       if (LocalHead) fprintf (SUMA_STDERR,"%s: creating controller \n", FuncName);
02689       SUMA_cb_createSumaCont( w, data, callData);
02690    }else {
02691       /* controller already created, need to bring it up again */
02692       #ifdef SUMA_USE_WITHDRAW
02693          if (LocalHead) fprintf (SUMA_STDERR,"%s: raising SUMA controller \n", FuncName);
02694          XMapRaised(SUMAg_CF->X->DPY_controller1, XtWindow(SUMAg_CF->X->SumaCont->AppShell));
02695       #endif
02696    }
02697 
02698    SUMA_RETURNe;
02699 }
02700 /*!
02701    \brief SUMA_cb_viewSurfaceCont(Widget w, XtPointer data, XtPointer callData);
02702    opens the surface controller for the surface in focus. 
02703    \param data (XtPointer) index of widget into sv->X->ViewMenu  
02704    It is the controller for the surface in focus that will be open.
02705    
02706 */ 
02707 void SUMA_cb_viewSurfaceCont(Widget w, XtPointer data, XtPointer callData)
02708 {
02709    SUMA_SurfaceObject *SO;
02710    SUMA_SurfaceViewer *sv;
02711    int isv, widtype;
02712    static char FuncName[] = {"SUMA_cb_viewSurfaceCont"};
02713    SUMA_Boolean LocalHead = NOPE;
02714    
02715    SUMA_ENTRY;
02716    
02717    SUMA_VIEWER_FROM_VIEWMENU_CALLBACK (data, isv, widtype);
02718    
02719    if (LocalHead) fprintf (SUMA_STDERR,"%s: A call from viewer %d, widget %d.\n", FuncName, isv, widtype);
02720    
02721    sv = &SUMAg_SVv[isv];
02722    if (sv->Focus_SO_ID >= 0) {
02723     SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
02724    }else {
02725       fprintf (SUMA_STDERR,"%s: No surface object in focus.\n", FuncName);
02726       SUMA_RETURNe;
02727    }
02728    
02729    
02730    if (!SO->SurfCont->TopLevelShell) {
02731       if (LocalHead) fprintf (SUMA_STDERR,"%s: Calling SUMA_cb_createSurfaceCont.\n", FuncName);
02732       SUMA_cb_createSurfaceCont( w, (XtPointer)SO, callData);
02733    }else {
02734       /* controller already created, need to bring it up again */
02735       #ifdef SUMA_USE_WITHDRAW
02736          if (LocalHead) fprintf (SUMA_STDERR,"%s: Controller already created, Raising it.\n", FuncName);
02737          XMapRaised(SUMAg_CF->X->DPY_controller1, XtWindow(SO->SurfCont->TopLevelShell));      
02738       #endif
02739 
02740    }
02741    
02742    SUMA_Init_SurfCont_SurfParam(SO);
02743    SUMA_Init_SurfCont_CrossHair(SO);
02744    
02745    if (SO->SurfCont->PosRef != sv->X->TOPLEVEL) {
02746       SO->SurfCont->PosRef = sv->X->TOPLEVEL;
02747       SUMA_PositionWindowRelative (SO->SurfCont->TopLevelShell, SO->SurfCont->PosRef, SWP_TOP_RIGHT);   
02748    } 
02749 
02750    SUMA_RETURNe;
02751 }
02752 /*! \brief SUMA_cb_viewViewerCont(Widget w, XtPointer data, XtPointer callData)
02753       opens the viewer controller. 
02754       \param data index of widget into sv->X->ViewMenu 
02755 */
02756 void SUMA_cb_viewViewerCont(Widget w, XtPointer data, XtPointer callData)
02757 {
02758    int isv, widtype;
02759    SUMA_SurfaceViewer *sv;
02760    SUMA_Boolean LocalHead = NOPE;
02761    static char FuncName[] = {"SUMA_cb_viewViewerCont"};
02762    
02763    SUMA_ENTRY;
02764    
02765    SUMA_VIEWER_FROM_VIEWMENU_CALLBACK (data, isv, widtype);
02766    
02767    sv = &SUMAg_SVv[isv];
02768 
02769    if (!sv->X->ViewCont->TopLevelShell) {
02770       if (LocalHead) fprintf (SUMA_STDERR,"%s: Calling SUMA_cb_createViewerCont.\n", FuncName);
02771       SUMA_cb_createViewerCont( w, sv, callData);
02772    }else {
02773       /* controller already created, need to bring it up again */
02774       
02775       #ifdef SUMA_USE_WITHDRAW
02776          if (LocalHead) fprintf (SUMA_STDERR,"%s: Controller already created, Raising it.\n", FuncName);
02777          XMapRaised(sv->X->DPY, XtWindow(sv->X->ViewCont->TopLevelShell));      
02778       #endif
02779 
02780    }
02781    
02782    SUMA_RETURNe;
02783 }
02784 
02785 
02786 
02787 /*!<
02788  the function expects the index of widget into sv->X->ViewMenu in data */
02789 void SUMA_cb_toggle_crosshair(Widget w, XtPointer data, XtPointer callData)
02790 {
02791    static char FuncName[] = {"SUMA_cb_toggle_crosshair"};
02792    int isv, widtype;
02793    DList *list = NULL;
02794    SUMA_SurfaceViewer *sv;
02795       
02796    SUMA_ENTRY;
02797    
02798    SUMA_VIEWER_FROM_VIEWMENU_CALLBACK (data, isv, widtype);
02799    
02800    sv = &SUMAg_SVv[isv];
02801       
02802    if (!list) list = SUMA_CreateList();
02803    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleCrossHair, SES_SumaWidget, sv);
02804    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_SumaWidget, sv);
02805 
02806    if (!SUMA_Engine (&list)) {
02807       fprintf(stderr,"Error %s: Failed SUMA_Engine\n", FuncName);
02808    }
02809    
02810    SUMA_RETURNe;
02811 }
02812  
02813 void SUMA_cb_toggle_node_in_focus(Widget w, XtPointer data, XtPointer callData)
02814 {
02815    static char FuncName[] = {"SUMA_cb_toggle_node_in_focus"};
02816    int isv, widtype;
02817    DList *list = NULL;
02818    SUMA_SurfaceViewer *sv;
02819    
02820    SUMA_ENTRY;
02821    
02822    SUMA_VIEWER_FROM_VIEWMENU_CALLBACK (data, isv, widtype);
02823    
02824    sv = &SUMAg_SVv[isv];
02825       
02826    if (!list) list = SUMA_CreateList();
02827    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleShowSelectedNode, SES_SumaWidget, sv);
02828    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_SumaWidget, sv);
02829 
02830    if (!SUMA_Engine (&list)) {
02831       fprintf(stderr,"Error %s: Failed SUMA_Engine\n", FuncName);
02832    }
02833 
02834    SUMA_RETURNe;
02835 }
02836 
02837 void SUMA_cb_toggle_selected_faceset(Widget w, XtPointer data, XtPointer callData)
02838 {
02839    static char FuncName[] = {"SUMA_cb_toggle_selected_faceset"};
02840    int isv, widtype;
02841    DList *list = NULL;
02842    SUMA_SurfaceViewer *sv;
02843    
02844    SUMA_ENTRY;
02845    
02846    SUMA_VIEWER_FROM_VIEWMENU_CALLBACK (data, isv, widtype);
02847    
02848    sv = &SUMAg_SVv[isv];
02849       
02850    if (!list) list = SUMA_CreateList();
02851    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleShowSelectedFaceSet, SES_SumaWidget, sv);
02852    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_SumaWidget, sv);
02853 
02854    if (!SUMA_Engine (&list)) {
02855       fprintf(stderr,"Error %s: Failed SUMA_Engine\n", FuncName);
02856    }
02857 
02858    
02859    SUMA_RETURNe;
02860 }         
02861 
02862 /*! Creates the dialog shell of the viewer controller.
02863 */
02864 #define SUMA_CONTROLLER_AS_DIALOG 0 /* controller widgets as dialog (1) or toplevelshells (0) 
02865                                     Stick with toplevelshells or window managers might force 
02866                                     you to keep them atop the surface viewers. Downside is that
02867                                     it is managed such that if the viewer is minimized, the controller is not.
02868                                     But that is not necessarily a bad thing. */
02869 /*!
02870 \brief Creates the viewer controller, expects sv in data 
02871 */
02872 void SUMA_cb_createViewerCont(Widget w, XtPointer data, XtPointer callData)
02873 {
02874    static char FuncName[] = {"SUMA_cb_createViewerCont"};
02875    Widget tl, rc, pb, ViewerFrame, SwitchFrame, QuitFrame, rc_left, rc_right, rc_mamma;
02876    Display *dpy;
02877    SUMA_SurfaceViewer *sv;
02878    int isv;    
02879    char slabel[100]; 
02880    SUMA_Boolean LocalHead = NOPE;
02881    
02882    SUMA_ENTRY;
02883    
02884    sv = (SUMA_SurfaceViewer *)data;
02885    isv = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
02886    
02887    if (sv->X->ViewCont->TopLevelShell) {
02888       fprintf (SUMA_STDERR,"Error %s: sv->X->ViewCont->TopLevelShell!=NULL. Should not be here.\n", FuncName);
02889       SUMA_RETURNe;
02890    }
02891    tl = SUMA_GetTopShell(w); /* top level widget */
02892    dpy = XtDisplay(tl);
02893    
02894    sprintf(slabel,"[%c] Viewer Controller", 65+isv);
02895    
02896    
02897    #if SUMA_CONTROLLER_AS_DIALOG /*xmDialogShellWidgetClass, topLevelShellWidgetClass*/
02898    SUMA_LH("Create a popup");
02899    sv->X->ViewCont->TopLevelShell = XtVaCreatePopupShell (slabel,
02900       xmDialogShellWidgetClass, tl,
02901       XmNallowShellResize, True, /* let code resize shell */
02902       XmNdeleteResponse, XmDO_NOTHING,
02903       NULL);    
02904    #else
02905    SUMA_LH("Create an App");
02906    /** Feb 03/03: I was using XtVaCreatePopupShell to create a topLevelShellWidgetClass. 
02907    XtVaCreatePopupShell is used to create dialog shells not toplevel or appshells */
02908    sv->X->ViewCont->TopLevelShell = XtVaAppCreateShell (slabel, "Suma",
02909       topLevelShellWidgetClass, SUMAg_CF->X->DPY_controller1 ,
02910       XmNdeleteResponse, XmDO_NOTHING,
02911       NULL);   
02912    #endif
02913    
02914    /* allow for code to resize the shell */
02915    XtVaSetValues (sv->X->ViewCont->TopLevelShell, 
02916          XmNresizePolicy , XmRESIZE_NONE , /* allow (?) childrent to resize */
02917          XmNallowShellResize , True ,       /* let code resize shell */
02918          NULL);
02919    
02920    /* handle the close button from window manager */
02921    XmAddWMProtocolCallback(/* make "Close" window menu work */
02922       sv->X->ViewCont->TopLevelShell,
02923       XmInternAtom( dpy , "WM_DELETE_WINDOW" , False ) ,
02924       SUMA_cb_closeViewerCont, (XtPointer) sv) ;
02925    
02926    /* create a form widget, manage it at the end ...*/
02927    sv->X->ViewCont->Mainform = XtVaCreateWidget ("dialog", 
02928       xmFormWidgetClass, sv->X->ViewCont->TopLevelShell,
02929       XmNborderWidth , 0 ,
02930       XmNmarginHeight , SUMA_MARGIN ,
02931       XmNmarginWidth  , SUMA_MARGIN ,
02932       XmNshadowThickness, 2,
02933       XmNshadowType, XmSHADOW_ETCHED_IN,
02934       NULL); 
02935    
02936    rc_mamma = XtVaCreateWidget ("rowcolumn",
02937             xmRowColumnWidgetClass, sv->X->ViewCont->Mainform,
02938             XmNpacking, XmPACK_TIGHT, 
02939             XmNorientation , XmHORIZONTAL ,
02940             XmNmarginHeight, SUMA_MARGIN ,
02941             XmNmarginWidth , SUMA_MARGIN ,
02942             XmNleftAttachment , XmATTACH_FORM ,
02943             XmNtopAttachment  , XmATTACH_FORM ,
02944             XmNrightAttachment , XmATTACH_FORM ,
02945             NULL);
02946             
02947    rc_left = XtVaCreateWidget ("rowcolumn",
02948             xmRowColumnWidgetClass, rc_mamma,
02949             XmNpacking, XmPACK_TIGHT, 
02950             XmNorientation , XmVERTICAL ,
02951             XmNmarginHeight, SUMA_MARGIN ,
02952             XmNmarginWidth , SUMA_MARGIN ,
02953             NULL);
02954    
02955    rc_right = XtVaCreateWidget ("rowcolumn",
02956             xmRowColumnWidgetClass, rc_mamma,
02957             XmNpacking, XmPACK_TIGHT, 
02958             XmNorientation , XmVERTICAL ,
02959             XmNmarginHeight, SUMA_MARGIN ,
02960             XmNmarginWidth , SUMA_MARGIN ,
02961             NULL); 
02962    
02963    {/*s group, state and info */ 
02964       Widget rc, pb, label;
02965       
02966       /* put a frame */
02967       ViewerFrame = XtVaCreateWidget ("dialog",
02968          xmFrameWidgetClass, rc_left,
02969          XmNshadowType , XmSHADOW_ETCHED_IN ,
02970          XmNshadowThickness , 5 ,
02971          XmNtraversalOn , False ,
02972          NULL); 
02973          
02974       /* row column Lock rowcolumns */
02975       rc = XtVaCreateWidget ("rowcolumn",
02976             xmRowColumnWidgetClass, ViewerFrame,
02977             XmNpacking, XmPACK_TIGHT, 
02978             XmNorientation , XmHORIZONTAL ,
02979             XmNmarginHeight, SUMA_MARGIN ,
02980             XmNmarginWidth , SUMA_MARGIN ,
02981             NULL);
02982 
02983       /*put a label containing the surface name, number of nodes and number of facesets */
02984       snprintf(slabel, 40*sizeof(char), "Group: %s, State: %s", sv->CurGroupName, sv->State);
02985       sv->X->ViewCont->Info_lb = XtVaCreateManagedWidget (slabel, 
02986                xmLabelWidgetClass, rc,
02987                NULL);
02988                
02989       XtVaCreateManagedWidget (  "sep", 
02990                                  xmSeparatorWidgetClass, rc, 
02991                                  XmNorientation, XmVERTICAL,NULL);
02992 
02993       sv->X->ViewCont->ViewerInfo_pb = XtVaCreateWidget ("more", 
02994          xmPushButtonWidgetClass, rc, 
02995          NULL);   
02996       XtAddCallback (sv->X->ViewCont->ViewerInfo_pb, XmNactivateCallback, SUMA_cb_moreViewerInfo, (XtPointer) sv);
02997       XtVaSetValues (sv->X->ViewCont->ViewerInfo_pb, XmNuserData, (XtPointer)sv, NULL); /* store sv in userData
02998                                                                   I think it is more convenient than as data
02999                                                                   in the call back structure. This way it will
03000                                                                   be easy to change the sv that this same button
03001                                                                   might refer to. 
03002                                                                   This is only for testing purposes, the pb_close
03003                                                                   button still expects sv in clientData
03004                                                                   Feb 23 04: UserData works well, but other 
03005                                                                   functions don't use it much so also store sv in clientData*/
03006       MCW_register_hint( sv->X->ViewCont->ViewerInfo_pb , "More info on Viewer" ) ;
03007       MCW_register_help( sv->X->ViewCont->ViewerInfo_pb , SUMA_moreViewerInfo_help ) ;
03008       XtManageChild (sv->X->ViewCont->ViewerInfo_pb); 
03009 
03010       XtManageChild (rc);
03011       
03012       XtManageChild (ViewerFrame);
03013    
03014    }
03015    { /* switch group and state frames */
03016       Widget rc, pb, label;/* put a frame */
03017       
03018       SwitchFrame = XtVaCreateWidget ("dialog",
03019          xmFrameWidgetClass, rc_left,
03020          XmNshadowType , XmSHADOW_ETCHED_IN ,
03021          XmNshadowThickness , 5 ,
03022          XmNtraversalOn , False ,
03023          NULL); 
03024          
03025       /* row column for switching groups and state */
03026       rc = XtVaCreateWidget ("rowcolumn",
03027             xmRowColumnWidgetClass, SwitchFrame,
03028             XmNpacking, XmPACK_TIGHT, 
03029             XmNorientation , XmHORIZONTAL ,
03030             XmNmarginHeight, SUMA_MARGIN ,
03031             XmNmarginWidth , SUMA_MARGIN ,
03032             NULL);
03033 
03034       /*put a label for Switch */
03035       snprintf(slabel, 40*sizeof(char), "Switch:");
03036       label = XtVaCreateManagedWidget (slabel, 
03037                xmLabelWidgetClass, rc,
03038                NULL);
03039 
03040       
03041       /* put a button for swiching groups */
03042       snprintf(slabel, 40*sizeof(char), "[%c] Switch Group", 65 + isv);
03043       sv->X->ViewCont->SwitchGrouplst = SUMA_AllocateScrolledList (slabel, SUMA_LSP_SINGLE, 
03044                               NOPE, YUP,
03045                               sv->X->ViewCont->TopLevelShell, SWP_TOP_LEFT,
03046                               SUMA_cb_SelectSwitchGroup, (void *)sv,
03047                               SUMA_cb_SelectSwitchGroup, (void *)sv,
03048                               SUMA_cb_CloseSwitchGroup, (void *)sv);
03049     
03050 
03051       pb = XtVaCreateWidget ("Group", 
03052          xmPushButtonWidgetClass, rc, 
03053          NULL);
03054       XtAddCallback (pb, XmNactivateCallback, SUMA_cb_ViewerCont_SwitchGroup, (XtPointer) sv);
03055       MCW_register_hint( pb , "Switch Group" ) ;
03056       MCW_register_help( pb , "Switch Group" ) ;
03057       XtManageChild (pb);
03058 
03059       /* put a button for swiching states */
03060       pb = XtVaCreateWidget ("State", 
03061          xmPushButtonWidgetClass, rc, 
03062          NULL);
03063       XtAddCallback (pb, XmNactivateCallback, SUMA_cb_ViewerCont_SwitchState, (XtPointer) sv);
03064       MCW_register_hint( pb , "Switch State" ) ;
03065       MCW_register_help( pb , "Switch State" ) ;
03066       XtManageChild (pb);
03067       
03068       
03069       /* now start managing the row column widget */
03070       XtManageChild (rc);
03071 
03072       /* manage the frame and the fslabelorm */
03073       XtManageChild (SwitchFrame);
03074    }               
03075    
03076    { /*s close and help buttons */
03077       Widget rc, pb_close, pb_bhelp;
03078       
03079       /* put up a frame to group the display controls */
03080       QuitFrame = XtVaCreateWidget ("dialog",
03081          xmFrameWidgetClass, sv->X->ViewCont->Mainform,
03082          XmNleftAttachment , XmATTACH_FORM ,
03083          XmNtopAttachment  , XmATTACH_WIDGET ,
03084          XmNtopWidget, SwitchFrame,
03085          XmNshadowType , XmSHADOW_ETCHED_IN ,
03086          XmNshadowThickness , 5 ,
03087          XmNtraversalOn , False ,
03088          NULL); 
03089 
03090          
03091       #if 0
03092       /* ugly, useless */
03093       /* this one requires Motif 1.2 or newer */
03094       XtVaCreateManagedWidget ("Disp. Cont.",
03095             xmLabelWidgetClass, QuitFrame, 
03096             XmNchildType, XmFRAME_TITLE_CHILD,
03097             XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
03098             NULL);
03099       #endif
03100       
03101       /* row column Lock rowcolumns */
03102       rc = XtVaCreateWidget ("rowcolumn",
03103             xmRowColumnWidgetClass, QuitFrame,
03104             XmNpacking, XmPACK_TIGHT, 
03105             XmNorientation , XmHORIZONTAL ,
03106             XmNmarginHeight, SUMA_MARGIN ,
03107             XmNmarginWidth , SUMA_MARGIN ,
03108             NULL);
03109 
03110       pb_close = XtVaCreateWidget ("Close", 
03111          xmPushButtonWidgetClass, rc, 
03112          NULL);   
03113       XtAddCallback (pb_close, XmNactivateCallback, SUMA_cb_closeViewerCont, (XtPointer) sv);
03114       MCW_register_hint( pb_close , "Close Viewer controller" ) ;
03115       MCW_register_help( pb_close , SUMA_closeViewerCont_help ) ;
03116       XtManageChild (pb_close); 
03117 
03118       pb_bhelp = XtVaCreateWidget ("BHelp", 
03119          xmPushButtonWidgetClass, rc, 
03120          NULL);
03121       XtAddCallback (pb_bhelp, XmNactivateCallback, MCW_click_help_CB, NULL);
03122       MCW_register_help(pb_bhelp , SUMA_help_help ) ;
03123       MCW_register_hint(pb_bhelp  , "Press this button then click on a button/label/menu for more help." ) ;
03124 
03125       XtManageChild (pb_bhelp); 
03126 
03127 
03128 
03129       /* now start managing the row column widget */
03130       XtManageChild (rc);
03131 
03132       /* manage the frame and the fslabelorm */
03133       XtManageChild (QuitFrame);
03134    }
03135       
03136    XtManageChild (rc_right);
03137    XtManageChild (rc_left);
03138    XtManageChild (rc_mamma);
03139    XtManageChild (sv->X->ViewCont->Mainform);
03140    
03141    #if SUMA_CONTROLLER_AS_DIALOG    
03142    #else
03143    /** Feb 03/03: pop it up if it is a topLevelShellWidgetClass, you should do the popping after all the widgets have been created.
03144    Otherwise, the window does not size itself correctly when open */
03145    XtPopup(sv->X->ViewCont->TopLevelShell, XtGrabNone);
03146    #endif
03147    
03148    /* realize the widget */
03149    XtRealizeWidget (sv->X->ViewCont->TopLevelShell);
03150    
03151    SUMA_RETURNe;
03152 }
03153 
03154 /*!
03155    \brief Closes a viewer controller, expects sv in data
03156 */
03157 void SUMA_cb_closeViewerCont(Widget w, XtPointer data, XtPointer callData)
03158 {
03159    static char FuncName[] = {"SUMA_cb_closeViewerCont"};
03160    SUMA_SurfaceViewer *sv;
03161    SUMA_Boolean LocalHead = NOPE;
03162    
03163    SUMA_ENTRY;
03164    
03165    sv = (SUMA_SurfaceViewer *)data;
03166    
03167    if (!sv->X->ViewCont->TopLevelShell) SUMA_RETURNe;
03168 
03169    #ifdef SUMA_USE_WITHDRAW 
03170       if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing Viewer Controller...\n", FuncName);
03171       
03172       XWithdrawWindow(sv->X->DPY, 
03173          XtWindow(sv->X->ViewCont->TopLevelShell),
03174          XScreenNumberOfScreen(XtScreen(sv->X->ViewCont->TopLevelShell)));
03175    #endif
03176    #ifdef SUMA_USE_DESTROY 
03177       if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying Viewer Controller...\n", FuncName);
03178       XtDestroyWidget(sv->X->ViewCont->TopLevelShell);
03179       sv->X->ViewCont->TopLevelShell = NULL;
03180    #endif
03181 
03182     
03183    SUMA_RETURNe;
03184 
03185 }
03186 
03187 /*!
03188    \brief SUMA_cb_createSurfaceCont(Widget w, XtPointer data, XtPointer callData);
03189    \param data (XtPointer) to SO (NOT sv)
03190 
03191 */
03192 void SUMA_cb_createSurfaceCont(Widget w, XtPointer data, XtPointer callData)
03193 {
03194    Widget tl, pb, form, DispFrame, SurfFrame, rc_left, rc_right, rc_mamma;
03195    Display *dpy;
03196    SUMA_SurfaceObject *SO;
03197    char *slabel, *lbl30; 
03198    SUMA_Boolean LocalHead = NOPE;
03199    static char FuncName[] = {"SUMA_cb_createSurfaceCont"};
03200    
03201    SUMA_ENTRY;
03202    
03203    SO = (SUMA_SurfaceObject *)data;
03204    *(SO->SurfCont->curSOp) = (void *)SO;
03205    
03206    if (SO->SurfCont->TopLevelShell) {
03207       fprintf (SUMA_STDERR,"Error %s: SO->SurfCont->TopLevelShell!=NULL. Should not be here.\n", FuncName);
03208       SUMA_RETURNe;
03209    }
03210    tl = SUMA_GetTopShell(w); /* top level widget */
03211    dpy = XtDisplay(tl);
03212    
03213    slabel = (char *)SUMA_malloc (sizeof(char) * (strlen(SO->Label) + 100));
03214    if (strlen(SO->Label) > 40) {
03215       char *tmpstr=NULL;
03216       tmpstr = SUMA_truncate_string(SO->Label, 40);
03217       if (tmpstr) { 
03218          sprintf(slabel,"[%s] Surface Controller", tmpstr);
03219          free(tmpstr); tmpstr=NULL;
03220       }
03221    } else {
03222       sprintf(slabel,"[%s] Surface Controller", SO->Label);
03223    }
03224    
03225    #if SUMA_CONTROLLER_AS_DIALOG /*xmDialogShellWidgetClass, topLevelShellWidgetClass*/
03226    if (LocalHead) fprintf(SUMA_STDERR, "%s: Creating dialog shell.\n", FuncName);
03227    SO->SurfCont->TopLevelShell = XtVaCreatePopupShell (slabel,
03228       xmDialogShellWidgetClass, tl,
03229       XmNallowShellResize, True, /* let code resize shell */
03230       XmNdeleteResponse, XmDO_NOTHING,
03231       NULL);    
03232    #else
03233    if (LocalHead) fprintf(SUMA_STDERR, "%s: Creating toplevel shell.\n", FuncName);
03234    /** Feb 03/03: I was using XtVaCreatePopupShell to create a topLevelShellWidgetClass. 
03235    XtVaCreatePopupShell is used to create dialog shells not toplevel or appshells. 
03236    Of course, it made no difference! */
03237    SO->SurfCont->TopLevelShell = XtVaAppCreateShell (slabel, "Suma",
03238       topLevelShellWidgetClass, SUMAg_CF->X->DPY_controller1 ,
03239       XmNdeleteResponse, XmDO_NOTHING,
03240       NULL);   
03241    #endif
03242    
03243    /* allow for code to resize the shell */
03244    XtVaSetValues (SO->SurfCont->TopLevelShell, 
03245          XmNresizePolicy , XmRESIZE_NONE , 
03246          XmNallowShellResize , True ,       /* let code resize shell */
03247          NULL);
03248     
03249    /* handle the close button from window manager */
03250    XmAddWMProtocolCallback(/* make "Close" window menu work */
03251       SO->SurfCont->TopLevelShell,
03252       XmInternAtom( dpy , "WM_DELETE_WINDOW" , False ) ,
03253       SUMA_cb_closeSurfaceCont, (XtPointer) SO) ;
03254    
03255    /* create a form widget, manage it at the end ...*/
03256    SO->SurfCont->Mainform = XtVaCreateWidget ("dialog", 
03257       xmFormWidgetClass, SO->SurfCont->TopLevelShell,
03258       XmNborderWidth , 0 ,
03259       XmNmarginHeight , SUMA_MARGIN ,
03260       XmNmarginWidth  , SUMA_MARGIN ,
03261       XmNshadowThickness, 2,
03262       XmNshadowType, XmSHADOW_ETCHED_IN,
03263       NULL); 
03264    
03265    rc_mamma = XtVaCreateWidget ("rowcolumn",
03266             xmRowColumnWidgetClass, SO->SurfCont->Mainform,
03267             XmNpacking, XmPACK_TIGHT, 
03268             XmNorientation , XmHORIZONTAL ,
03269             XmNmarginHeight, SUMA_MARGIN ,
03270             XmNmarginWidth , SUMA_MARGIN ,
03271             XmNleftAttachment , XmATTACH_FORM ,
03272             XmNtopAttachment  , XmATTACH_FORM ,
03273             XmNrightAttachment , XmATTACH_FORM ,
03274             NULL);
03275             
03276    rc_left = XtVaCreateWidget ("rowcolumn",
03277             xmRowColumnWidgetClass, rc_mamma,
03278             XmNpacking, XmPACK_TIGHT, 
03279             XmNorientation , XmVERTICAL ,
03280             XmNmarginHeight, SUMA_MARGIN ,
03281             XmNmarginWidth , SUMA_MARGIN ,
03282             XmNwidth, 317,
03283             XmNresizeWidth, False,
03284             NULL);
03285    
03286    rc_right = XtVaCreateWidget ("rowcolumn",
03287             xmRowColumnWidgetClass, rc_mamma,
03288             XmNpacking, XmPACK_TIGHT, 
03289             XmNorientation , XmVERTICAL ,
03290             XmNmarginHeight, SUMA_MARGIN ,
03291             XmNmarginWidth , SUMA_MARGIN ,
03292             NULL); 
03293                     
03294    
03295    {/*surface properties */ 
03296       Widget rc, label, rc_SurfProp, pb;
03297      
03298       /* put a frame */
03299       SurfFrame = XtVaCreateWidget ("dialog",
03300          xmFrameWidgetClass, rc_left,
03301          XmNshadowType , XmSHADOW_ETCHED_IN ,
03302          XmNshadowThickness , 5 ,
03303          XmNtraversalOn , False ,
03304          NULL); 
03305       
03306       XtVaCreateManagedWidget ("Surface Properties",
03307             xmLabelWidgetClass, SurfFrame, 
03308             XmNchildType, XmFRAME_TITLE_CHILD,
03309             XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
03310             NULL);
03311       
03312       rc_SurfProp = XtVaCreateWidget ("rowcolumn",
03313             xmRowColumnWidgetClass, SurfFrame,
03314             XmNpacking, XmPACK_TIGHT, 
03315             XmNorientation , XmVERTICAL ,
03316             XmNmarginHeight, 0 ,
03317             XmNmarginWidth , 0 ,
03318             NULL); 
03319       
03320       rc = XtVaCreateWidget ("rowcolumn",
03321             xmRowColumnWidgetClass, rc_SurfProp,
03322             XmNpacking, XmPACK_TIGHT, 
03323             XmNorientation , XmHORIZONTAL ,
03324             XmNmarginHeight, 0 ,
03325             XmNmarginWidth , 0 ,
03326             NULL);
03327 
03328       /*put a label containing the surface name, number of nodes and number of facesets */
03329       lbl30 = SUMA_set_string_length(SO->Label, ' ', 27);
03330       if (lbl30) {
03331          sprintf(slabel,"%s\n%d nodes: %d tri.", lbl30, SO->N_Node, SO->N_FaceSet); 
03332          SUMA_free(lbl30); lbl30 = NULL;
03333       } else {
03334          sprintf(slabel,"???\n%d nodes: %d tri.", SO->N_Node, SO->N_FaceSet); 
03335       }
03336       SO->SurfCont->SurfInfo_label = XtVaCreateManagedWidget (slabel, 
03337                xmLabelWidgetClass, rc,
03338                NULL);
03339 
03340       XtVaCreateManagedWidget (  "sep", 
03341                                  xmSeparatorWidgetClass, rc, 
03342                                  XmNorientation, XmVERTICAL,NULL);
03343 
03344       SO->SurfCont->SurfInfo_pb = XtVaCreateWidget ("more", 
03345          xmPushButtonWidgetClass, rc, 
03346          NULL);   
03347       XtAddCallback (SO->SurfCont->SurfInfo_pb, XmNactivateCallback, SUMA_cb_moreSurfInfo, (XtPointer)SO->SurfCont->curSOp);
03348       XtVaSetValues (SO->SurfCont->SurfInfo_pb, XmNuserData, (XtPointer)SO->SurfCont->curSOp, NULL); /* 
03349                                                                   Feb 23 04: XmNuserData is not used anymore.
03350                                                                   See notes for SUMA_cb_moreViewerInfo
03351                                                                   call for reasons why this was done...
03352                                                                   
03353                                                                   store the surface object SO in userData
03354                                                                   I think it is more convenient than as data
03355                                                                   in the call back structure. This way it will
03356                                                                   be easy to change the SO that this same button
03357                                                                   might refer to. 
03358                                                                   This is only for testing purposes, the pb_close
03359                                                                   button still expects SO in clientData*/
03360       MCW_register_hint( SO->SurfCont->SurfInfo_pb , "More info on Surface" ) ;
03361       MCW_register_help( SO->SurfCont->SurfInfo_pb , SUMA_SurfContHelp_more ) ;
03362       XtManageChild (SO->SurfCont->SurfInfo_pb); 
03363 
03364       XtManageChild (rc);
03365       
03366       XtVaCreateManagedWidget (  "sep", 
03367                                  xmSeparatorWidgetClass, rc_SurfProp, 
03368                                  XmNorientation, XmHORIZONTAL,NULL);
03369 
03370       rc = XtVaCreateWidget ("rowcolumn",
03371             xmRowColumnWidgetClass, rc_SurfProp,
03372             XmNpacking, XmPACK_TIGHT, 
03373             XmNorientation , XmHORIZONTAL ,
03374             XmNmarginHeight, SUMA_MARGIN ,
03375             XmNmarginWidth , SUMA_MARGIN ,
03376             NULL);
03377 
03378       /* rendering menu option */
03379       SUMA_BuildMenuReset(0);
03380       SUMA_BuildMenu (rc, XmMENU_OPTION, 
03381                                  "RenderMode", '\0', YUP, RenderMode_Menu, 
03382                                  (void *)(SO->SurfCont->curSOp), 
03383                                  "Choose the rendering mode for this surface.",
03384                                  SUMA_SurfContHelp_RenderMode, 
03385                                  SO->SurfCont->RenderModeMenu );
03386       XtManageChild (SO->SurfCont->RenderModeMenu[SW_SurfCont_Render]);
03387       
03388       pb = XtVaCreateWidget ("Dsets", 
03389          xmPushButtonWidgetClass, rc, 
03390          NULL);   
03391       XtAddCallback (pb, XmNactivateCallback, SUMA_cb_UnmanageWidget, (XtPointer) SO->SurfCont->curSOp);
03392       MCW_register_hint( pb , "Show/Hide Dataset (previously Color Plane) controllers" ) ;
03393       MCW_register_help( pb , SUMA_SurfContHelp_Dsets ) ;
03394       XtManageChild (pb);
03395       
03396       XtManageChild (rc);
03397 
03398       XtManageChild (rc_SurfProp);
03399       XtManageChild (SurfFrame);
03400    }  
03401    
03402    {  /* Xhair Controls */
03403       Widget rcv;
03404       /* put a frame */
03405       SO->SurfCont->Xhair_fr = XtVaCreateWidget ("dialog",
03406          xmFrameWidgetClass, rc_left,
03407          XmNshadowType , XmSHADOW_ETCHED_IN ,
03408          XmNshadowThickness , 5 ,
03409          XmNtraversalOn , False ,
03410          NULL); 
03411       
03412       XtVaCreateManagedWidget ("Xhair Info",
03413             xmLabelWidgetClass, SO->SurfCont->Xhair_fr, 
03414             XmNchildType, XmFRAME_TITLE_CHILD,
03415             XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
03416             NULL);
03417             
03418       /* vertical row column */
03419       rcv = XtVaCreateWidget ("rowcolumn",
03420             xmRowColumnWidgetClass, SO->SurfCont->Xhair_fr,
03421             XmNpacking, XmPACK_TIGHT, 
03422             XmNorientation , XmVERTICAL ,
03423             XmNmarginHeight, 0 ,
03424             XmNmarginWidth , 0 ,
03425             NULL);
03426 
03427       /* create the widgets for the colormap stuff */
03428       SUMA_CreateXhairWidgets(rcv, SO);
03429 
03430       
03431       XtManageChild(rcv);
03432       XtManageChild(SO->SurfCont->Xhair_fr);
03433    }  /* Xhair Controls */
03434     
03435    {  /* Dset Mapping */
03436       Widget rcv;
03437       /* put a frame */
03438       SO->SurfCont->DsetMap_fr = XtVaCreateWidget ("dialog",
03439          xmFrameWidgetClass, rc_right,
03440          XmNrightAttachment , XmATTACH_FORM ,
03441          XmNleftAttachment, XmATTACH_WIDGET,
03442          XmNleftWidget, SurfFrame,
03443          XmNtopAttachment  , XmATTACH_FORM ,
03444          XmNshadowType , XmSHADOW_ETCHED_IN ,
03445          XmNshadowThickness , 5 ,
03446          XmNtraversalOn , False ,
03447          NULL); 
03448       
03449       XtVaCreateManagedWidget ("Dset Mapping",
03450             xmLabelWidgetClass, SO->SurfCont->DsetMap_fr, 
03451             XmNchildType, XmFRAME_TITLE_CHILD,
03452             XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
03453             NULL);
03454             
03455       /* vertical row column */
03456       rcv = XtVaCreateWidget ("rowcolumn",
03457             xmRowColumnWidgetClass, SO->SurfCont->DsetMap_fr,
03458             XmNpacking, XmPACK_TIGHT, 
03459             XmNorientation , XmVERTICAL ,
03460             XmNmarginHeight, 0 ,
03461             XmNmarginWidth , 0 ,
03462             NULL);
03463 
03464       /* create the widgets for the colormap stuff */
03465       SUMA_CreateCmapWidgets(rcv, SO);
03466       
03467       XtManageChild(rcv);
03468       XtManageChild(SO->SurfCont->DsetMap_fr);
03469    }
03470 
03471    /* Dset Controls */
03472    {
03473        Widget rc, rcv, pb;
03474      
03475       
03476       /* put a frame */
03477       SO->SurfCont->ColPlane_fr = XtVaCreateWidget ("dialog",
03478          xmFrameWidgetClass, rc_left,
03479          XmNshadowType , XmSHADOW_ETCHED_IN ,
03480          XmNshadowThickness , 5 ,
03481          XmNtraversalOn , False ,
03482          NULL); 
03483       
03484       XtVaCreateManagedWidget ("Dset Controls",
03485             xmLabelWidgetClass, SO->SurfCont->ColPlane_fr, 
03486             XmNchildType, XmFRAME_TITLE_CHILD,
03487             XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
03488             NULL);
03489             
03490       /* vertical row column */
03491       rcv = XtVaCreateWidget ("rowcolumn",
03492             xmRowColumnWidgetClass, SO->SurfCont->ColPlane_fr,
03493             XmNpacking, XmPACK_TIGHT, 
03494             XmNorientation , XmVERTICAL ,
03495             XmNmarginHeight, 0 ,
03496             XmNmarginWidth , 0 ,
03497             NULL);
03498             
03499       /* row column for label*/
03500       rc = XtVaCreateWidget ("rowcolumn",
03501             xmRowColumnWidgetClass, rcv,
03502             XmNpacking, XmPACK_TIGHT, 
03503             XmNorientation , XmHORIZONTAL ,
03504             XmNmarginHeight, 0 ,
03505             XmNmarginWidth , 0 ,
03506             NULL);
03507       
03508       /*put a label containing the surface name, number of nodes and number of facesets */
03509       {
03510          char *Dset_tit[]  =  {  "Lbl", "Par", NULL };
03511          char *Dset_hint[] =  {  "Label of Dset", 
03512                                  "Parent surface of Dset", NULL };
03513          char *Dset_help[] =  {  SUMA_SurfContHelp_DsetLblTblr0, 
03514                                  SUMA_SurfContHelp_DsetLblTblr1, NULL };
03515          int colw[]={ 3, 27};
03516          SUMA_CreateTable(rc, 
03517             2, 2,
03518             Dset_tit, NULL,
03519             Dset_hint, NULL,
03520             Dset_help, NULL,
03521             colw, NOPE, SUMA_string,
03522             NULL, NULL,
03523             NULL, NULL,
03524             NULL, NULL, 
03525             SO->SurfCont->ColPlaneLabelTable);
03526       }
03527       XtManageChild (rc);
03528       
03529       /* add a rc for the colorplane order and opacity */
03530       rc = XtVaCreateWidget ("rowcolumn",
03531          xmRowColumnWidgetClass, rcv,
03532          XmNpacking, XmPACK_TIGHT, 
03533          XmNorientation , XmHORIZONTAL ,
03534          NULL);
03535    
03536       SUMA_CreateArrowField ( rc, "Ord:",
03537                            1, 0, 20, 1,
03538                            2, SUMA_int,
03539                            NOPE,
03540                            SUMA_ColPlane_NewOrder, (void *)SO,
03541                            SUMA_SurfCont_ColPlaneOrder_hint, SUMA_SurfContHelp_DsetOrd,
03542                            SO->SurfCont->ColPlaneOrder);
03543                              
03544       SUMA_CreateArrowField ( rc, "Opa:",
03545                            1, 0.0, 1.0, 0.1,
03546                            3, SUMA_float,
03547                            NOPE,
03548                            SUMA_ColPlane_NewOpacity, (void *)SO,
03549                            SUMA_SurfCont_ColPlaneOpacity_hint, SUMA_SurfContHelp_DsetOpa,
03550                            SO->SurfCont->ColPlaneOpacity);
03551 
03552       /* manage  rc */
03553       XtManageChild (rc);
03554       
03555       /* add a rc for the colorplane brightness factor and visibility */
03556       rc = XtVaCreateWidget ("rowcolumn",
03557          xmRowColumnWidgetClass, rcv,
03558          XmNpacking, XmPACK_TIGHT, 
03559          XmNorientation , XmHORIZONTAL ,
03560          NULL);
03561    
03562       SUMA_CreateArrowField ( rc, "Dim:",
03563                            1, 0.1, 1, 0.1,
03564                            3, SUMA_float,
03565                            YUP,
03566                            SUMA_ColPlane_NewDimFact, (void *)SO, 
03567                            SUMA_SurfCont_ColPlaneDim_hint, SUMA_SurfContHelp_DsetDim,
03568                            SO->SurfCont->ColPlaneDimFact);
03569            
03570       SO->SurfCont->ColPlaneShow_tb = XtVaCreateManagedWidget("view", 
03571             xmToggleButtonWidgetClass, rc, NULL);
03572       XmToggleButtonSetState (SO->SurfCont->ColPlaneShow_tb, YUP, NOPE);
03573       XtAddCallback (SO->SurfCont->ColPlaneShow_tb, 
03574                   XmNvalueChangedCallback, SUMA_cb_ColPlaneShow_toggled, SO);
03575                   
03576       MCW_register_help(SO->SurfCont->ColPlaneShow_tb , SUMA_SurfContHelp_DsetView ) ;
03577       MCW_register_hint(SO->SurfCont->ColPlaneShow_tb , "Shows/Hides Dset." ) ;
03578       SUMA_SET_SELECT_COLOR(SO->SurfCont->ColPlaneShow_tb);
03579       
03580       SO->SurfCont->ColPlaneShowOne_tb = XtVaCreateManagedWidget("1 Only", 
03581             xmToggleButtonWidgetClass, rc, NULL);
03582       XmToggleButtonSetState (SO->SurfCont->ColPlaneShowOne_tb, SO->SurfCont->ShowCurOnly, NOPE);
03583       XtAddCallback (SO->SurfCont->ColPlaneShowOne_tb, 
03584                   XmNvalueChangedCallback, SUMA_cb_ColPlaneShowOne_toggled, SO);
03585                   
03586       MCW_register_help(SO->SurfCont->ColPlaneShowOne_tb , SUMA_SurfContHelp_DsetViewOne ) ;
03587       MCW_register_hint(SO->SurfCont->ColPlaneShowOne_tb , "Shows ONLY selected Dset from foreground stack." ) ;
03588       SUMA_SET_SELECT_COLOR(SO->SurfCont->ColPlaneShowOne_tb);
03589            
03590       /* manage  rc */
03591       XtManageChild (rc);
03592       
03593       XtVaCreateManagedWidget (  "sep", 
03594                                  xmSeparatorWidgetClass, rcv, 
03595                                  XmNorientation, XmHORIZONTAL,NULL);
03596 
03597       /* row column for Switch, Load, Delete */
03598       rc = XtVaCreateWidget ("rowcolumn",
03599          xmRowColumnWidgetClass, rcv,
03600          XmNpacking, XmPACK_TIGHT, 
03601          XmNorientation , XmHORIZONTAL ,
03602          NULL);
03603          
03604       /* put a push button to switch between color planes */
03605       SO->SurfCont->SwitchDsetlst = SUMA_AllocateScrolledList ("Switch Dset", SUMA_LSP_SINGLE, 
03606                                  NOPE, NOPE, /* duplicate deletion, no sorting */ 
03607                                  SO->SurfCont->TopLevelShell, SWP_POINTER,
03608                                  SUMA_cb_SelectSwitchColPlane, (void *)SO,
03609                                  SUMA_cb_SelectSwitchColPlane, (void *)SO,
03610                                  SUMA_cb_CloseSwitchColPlane, NULL);
03611 
03612 
03613       pb = XtVaCreateWidget ("Switch Dset", 
03614          xmPushButtonWidgetClass, rc, 
03615          NULL);   
03616       XtAddCallback (pb, XmNactivateCallback, SUMA_cb_SurfCont_SwitchColPlane, (XtPointer)SO);
03617       MCW_register_hint(pb , "Switch between datasets" ) ;
03618       MCW_register_help(pb , SUMA_SurfContHelp_DsetSwitch ) ;
03619       XtManageChild (pb);
03620       
03621       pb = XtVaCreateWidget ("Load Dset", 
03622             xmPushButtonWidgetClass, rc, 
03623             NULL);   
03624          XtAddCallback (pb, XmNactivateCallback, SUMA_cb_Dset_Load, (XtPointer) SO);
03625          MCW_register_hint(pb ,  "Load a new dataset (much more with BHelp)" ) ;
03626          MCW_register_help(pb ,  SUMA_SurfContHelp_DsetLoad ) ;
03627          XtManageChild (pb);
03628       
03629       pb = XtVaCreateWidget ("Delete", 
03630          xmPushButtonWidgetClass, rc, 
03631          NULL);   
03632       XtAddCallback (pb, XmNactivateCallback, SUMA_cb_ColPlane_Delete, (XtPointer) SO);
03633       /* XtManageChild (pb); */ /* Not ready for this one yet */
03634 
03635       pb = XtVaCreateWidget ("Load Col", 
03636          xmPushButtonWidgetClass, rc, 
03637          NULL);   
03638       XtAddCallback (pb, XmNactivateCallback, SUMA_cb_ColPlane_Load, (XtPointer) SO);
03639       MCW_register_hint(pb , "Load a new color plane (same as ctrl+c)" ) ;
03640       MCW_register_help(pb , SUMA_SurfContHelp_DsetLoadCol  ) ;
03641       XtManageChild (pb);
03642       
03643        
03644       XtManageChild (rc);
03645       
03646       /* manage vertical row column */
03647       XtManageChild (rcv);
03648       
03649       XtManageChild (SO->SurfCont->ColPlane_fr);
03650    }
03651    
03652    
03653    if (1){ /*s close and help buttons */
03654       Widget rc, pb_close, pb_bhelp;
03655       
03656       /* put up a frame to group the display controls */
03657       DispFrame = XtVaCreateWidget ("dialog",
03658          xmFrameWidgetClass, rc_left,
03659          XmNleftAttachment , XmATTACH_FORM ,
03660          XmNbottomAttachment  , XmATTACH_WIDGET ,
03661          XmNbottomWidget, rc_left,
03662          XmNshadowType , XmSHADOW_ETCHED_IN ,
03663          XmNshadowThickness , 5 ,
03664          XmNtraversalOn , False ,
03665          NULL); 
03666 
03667          
03668       /* this one requires Motif 1.2 or newer */
03669          XtVaCreateManagedWidget ("Disp. Cont.",
03670             xmLabelWidgetClass, DispFrame, 
03671             XmNchildType, XmFRAME_TITLE_CHILD,
03672             XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
03673             NULL);
03674 
03675       /* row column Lock rowcolumns */
03676       rc = XtVaCreateWidget ("rowcolumn",
03677             xmRowColumnWidgetClass, DispFrame,
03678             XmNpacking, XmPACK_TIGHT, 
03679             XmNorientation , XmHORIZONTAL ,
03680             XmNmarginHeight, SUMA_MARGIN ,
03681             XmNmarginWidth , SUMA_MARGIN ,
03682             NULL);
03683 
03684       pb_close = XtVaCreateWidget ("Close", 
03685          xmPushButtonWidgetClass, rc, 
03686          NULL);   
03687       XtAddCallback (pb_close, XmNactivateCallback, SUMA_cb_closeSurfaceCont, (XtPointer) SO);
03688       MCW_register_hint( pb_close , "Close Surface controller" ) ;
03689       MCW_register_help( pb_close , SUMA_closeSurfaceCont_help ) ;
03690       XtManageChild (pb_close); 
03691 
03692       pb_bhelp = XtVaCreateWidget ("BHelp", 
03693          xmPushButtonWidgetClass, rc, 
03694          NULL);
03695       XtAddCallback (pb_bhelp, XmNactivateCallback, MCW_click_help_CB, NULL);
03696       MCW_register_help(pb_bhelp , SUMA_help_help ) ;
03697       MCW_register_hint(pb_bhelp  , "Press this button then click on a button/label/menu for more help." ) ;
03698 
03699       XtManageChild (pb_bhelp); 
03700 
03701 
03702 
03703       /* now start managing the row column widget */
03704       XtManageChild (rc);
03705 
03706       /* manage the frame and the fslabelorm */
03707       XtManageChild (DispFrame);
03708    }
03709    
03710    XtManageChild (rc_right);
03711    XtManageChild (rc_left);
03712    XtManageChild (rc_mamma);
03713    XtManageChild (SO->SurfCont->Mainform);
03714    
03715    #if SUMA_CONTROLLER_AS_DIALOG    
03716    #else
03717    /** Feb 03/03: pop it up if it is a topLevelShellWidgetClass, you should do the popping after all the widgets have been created.
03718    Otherwise, the window does not size itself correctly when open */
03719    XtPopup(SO->SurfCont->TopLevelShell, XtGrabNone);
03720    #endif
03721    
03722    /* realize the widget */
03723    XtRealizeWidget (SO->SurfCont->TopLevelShell);
03724    
03725    SUMA_free (slabel);
03726    
03727    /* initialize the left side (no need here, that's done in SUMA_cb_viewSurfaceCont)*/
03728    /* SUMA_Init_SurfCont_SurfParam(SO); */
03729    
03730    /* initialize the ColorPlane frame if possible 
03731    Do it here rather than above because scale goes crazy 
03732    when parent widgets are being resized*/
03733    if (!SO->Overlays[0]) {
03734       SUMA_SurfaceObject *SOp=NULL;
03735       if (LocalHead) fprintf(SUMA_STDERR,"%s:\n"
03736                            "NO Overlays yet for this surface\n", FuncName);
03737       /* happens in very few instances when both child and parent 
03738       are in the first view and the child is selected before the surface
03739       controller for that family is ever opened! */
03740       SOp = SUMA_findSOp_inDOv(SO->LocalDomainParentID, SUMAg_DOv, SUMAg_N_DOv);
03741       if (!SOp) {
03742          SUMA_SL_Err("Failed to find parent, should not be.");
03743       }
03744 
03745       if (!SUMA_GetOverlaysFromParent(SO, SOp)) {
03746          SUMA_SL_Err("Failed to copy overlays!");
03747          SUMA_RETURNe;
03748       }
03749    }
03750    
03751    if (SO->N_Overlays) {
03752       SUMA_InitializeColPlaneShell(SO, SO->Overlays[0]);
03753    }
03754    
03755    SUMA_RETURNe;
03756 }
03757 
03758 /*!
03759    \brief close surface controller, expects SO in data
03760 */
03761 void SUMA_cb_closeSurfaceCont(Widget w, XtPointer data, XtPointer callData)
03762 {
03763    static char FuncName[] = {"SUMA_cb_closeSurfaceCont"};
03764    SUMA_SurfaceObject *SO;
03765    SUMA_Boolean LocalHead = NOPE;
03766    
03767    SUMA_ENTRY;
03768    
03769    SO = (SUMA_SurfaceObject *)data;
03770    
03771    if (!SO->SurfCont->TopLevelShell) SUMA_RETURNe;
03772 
03773    #ifdef SUMA_USE_WITHDRAW 
03774       if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing Surface Controller...\n", FuncName);
03775       
03776       XWithdrawWindow(SUMAg_CF->X->DPY_controller1, 
03777          XtWindow(SO->SurfCont->TopLevelShell),
03778          XScreenNumberOfScreen(XtScreen(SO->SurfCont->TopLevelShell)));
03779    #endif
03780    #ifdef SUMA_USE_DESTROY 
03781       if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying Surface Controller...\n", FuncName);
03782       XtDestroyWidget(SO->SurfCont->TopLevelShell);
03783       SO->SurfCont->TopLevelShell = NULL;
03784    #endif
03785 
03786     
03787    SUMA_RETURNe;
03788 
03789 }
03790 
03791 /*!
03792    \brief updates the left side of Surface Controller
03793 */
03794 SUMA_Boolean SUMA_Init_SurfCont_SurfParam(SUMA_SurfaceObject *SO)
03795 {
03796    static char FuncName[]={"SUMA_Init_SurfCont_SurfParam"};
03797    char *slabel = NULL, *Name, *lbl30 = NULL;
03798    int i, imenu;
03799    Widget *w=NULL, whist=NULL;
03800    XmString string;
03801    SUMA_SurfaceObject *oSO;
03802    SUMA_Boolean SameSurface = NOPE;
03803    SUMA_Boolean LocalHead = NOPE;
03804    
03805    SUMA_ENTRY;
03806    oSO = *(SO->SurfCont->curSOp);
03807    if (oSO == SO) {
03808       SameSurface = YUP;
03809    } else {
03810       SameSurface = NOPE;
03811    }
03812    
03813    /* set the new current surface pointer */
03814    *(SO->SurfCont->curSOp) = (void *)SO;
03815    
03816    if (!SameSurface) {
03817       /* initialize the title of the window */
03818       slabel = (char *)SUMA_malloc (sizeof(char) * (strlen(SO->Label) + 100));
03819       if (strlen(SO->Label) > 40) {
03820          char *tmpstr=NULL;
03821          tmpstr = SUMA_truncate_string(SO->Label, 40);
03822          if (tmpstr) { 
03823             sprintf(slabel,"[%s] Surface Controller", tmpstr);
03824             free(tmpstr); tmpstr=NULL;
03825          }
03826       } else {
03827          sprintf(slabel,"[%s] Surface Controller", SO->Label);
03828       }
03829       SUMA_LH("Setting title");
03830       XtVaSetValues(SO->SurfCont->TopLevelShell, XtNtitle, slabel, NULL);
03831 
03832       /* initialize the string before the more button */
03833          /*put a label containing the surface name, number of nodes and number of facesets */
03834          lbl30 = SUMA_set_string_length(SO->Label, ' ', 27);
03835          if (lbl30) {
03836             sprintf(slabel,"%s\n%d nodes: %d tri.", lbl30, SO->N_Node, SO->N_FaceSet); 
03837             SUMA_free(lbl30); lbl30 = NULL;
03838          } else {
03839             sprintf(slabel,"???\n%d nodes: %d tri.", SO->N_Node, SO->N_FaceSet); 
03840          }
03841          SUMA_LH("Setting label");
03842          string = XmStringCreateLocalized (slabel);
03843          XtVaSetValues(SO->SurfCont->SurfInfo_label, XmNlabelString, string, NULL);
03844          XmStringFree (string);
03845 
03846       if (slabel) SUMA_free(slabel); slabel = NULL;
03847       /* Can't do much with the SurfInfo button,
03848       You can only have on Info shell/LocalDomainParent
03849       at a time */
03850 
03851       SUMA_LH("Setting RenderMode");
03852       /* set the correct RenderMode for that surface */
03853       imenu = -1;
03854       switch (SO->PolyMode) {
03855          case SRM_ViewerDefault:
03856             imenu = SW_SurfCont_RenderViewerDefault;
03857             break;
03858          case SRM_Fill:
03859             imenu = SW_SurfCont_RenderFill;
03860             break;
03861          case SRM_Line:
03862             imenu = SW_SurfCont_RenderLine;
03863             break;
03864          case SRM_Points:
03865             imenu = SW_SurfCont_RenderPoints;
03866             break;
03867          default: 
03868             fprintf (SUMA_STDERR, "Error %s: Unexpected something.\n", FuncName);
03869             break;
03870       }
03871       /* look for name of widget with imenu for call data. This is overkill but its fun */
03872       i = 0;
03873       Name = NULL;
03874       while (&(RenderMode_Menu[i])) {
03875          if ((int)RenderMode_Menu[i].callback_data == imenu) {
03876             Name = RenderMode_Menu[i].label;
03877             if (LocalHead) fprintf (SUMA_STDERR,"Looking for %s\n", Name);
03878             /* now we know what the name of the button needed is, look for it*/
03879             w = SO->SurfCont->RenderModeMenu;
03880             for (i=0; i< SW_N_SurfCont_Render; ++i) {
03881                if (LocalHead) fprintf (SUMA_STDERR,"I have %s\n", XtName(w[i]));
03882                if (strcmp(Name, XtName(w[i])) == 0) {
03883                   SUMA_LH("Match!");
03884                   XtVaSetValues(  w[0], XmNmenuHistory , w[i] , NULL ) ;  
03885                   SUMA_RETURN(YUP);
03886               }
03887             }
03888          }
03889          ++i;
03890       }
03891    } 
03892    
03893    /* do even if this is the old surface */ 
03894     
03895    SUMA_RETURN(YUP);
03896 }
03897 
03898 /*!
03899    \brief creates/raises the DrawROI window
03900    
03901    \param DrawnROI (SUMA_DRAWN_ROI *) a drawn ROI that is currently being drawn. NULL if there are none
03902    
03903 */
03904 SUMA_Boolean SUMA_OpenDrawROIWindow (SUMA_DRAWN_ROI *DrawnROI)
03905 {
03906    static char FuncName[] = {"SUMA_OpenDrawROIWindow"};
03907    SUMA_Boolean LocalHead = NOPE;
03908    
03909    SUMA_ENTRY;
03910    
03911    if (!SUMAg_CF->X->DrawROI->AppShell) { /* need to create window */
03912       SUMA_CreateDrawROIWindow ();
03913    } else {/* just needs raising */
03914       /* controller already created, need to bring it up again */
03915       #ifdef SUMA_USE_WITHDRAW
03916          if (LocalHead) fprintf (SUMA_STDERR,"%s: raising DrawROI window \n", FuncName);
03917          XMapRaised(SUMAg_CF->X->DPY_controller1, XtWindow(SUMAg_CF->X->DrawROI->AppShell));
03918       #endif
03919    }
03920    
03921    if (DrawnROI) {
03922       /* initialize the window */
03923       SUMA_InitializeDrawROIWindow (DrawnROI);
03924    } 
03925    
03926    SUMA_RETURN(YUP);
03927 }
03928  
03929 /*!
03930    \brief Sets the widgets in the DrawROI window based on the DrawnROI structure
03931 */
03932 SUMA_Boolean SUMA_InitializeDrawROIWindow (SUMA_DRAWN_ROI *DrawnROI)
03933 {
03934    static char FuncName[] = {"SUMA_InitializeDrawROIWindow"};
03935    SUMA_SurfaceObject *SOp = NULL;
03936    char sbuf[SUMA_MAX_LABEL_LENGTH];
03937    SUMA_Boolean LocalHead = NOPE;
03938    
03939    SUMA_ENTRY;
03940    
03941    if (!DrawnROI) {
03942       if (LocalHead) fprintf (SUMA_STDERR, "%s: Initializing with NULL.\n", FuncName);
03943       SUMA_SET_LABEL(SUMAg_CF->X->DrawROI->ParentLabel_lb, "Parent: -");
03944       SUMA_SET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIlbl->textfield, "-");
03945       SUMA_SET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIval->textfield, "0");
03946    }else {
03947       if (LocalHead) fprintf (SUMA_STDERR, "%s: Initializing with %p.\n", FuncName, DrawnROI);
03948       SOp = SUMA_findSOp_inDOv(DrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
03949       sprintf (sbuf, "Parent: %s", SOp->Label);
03950       if (SOp) {
03951          SUMA_SET_LABEL(SUMAg_CF->X->DrawROI->ParentLabel_lb, sbuf);
03952       } else {
03953          SUMA_SET_LABEL(SUMAg_CF->X->DrawROI->ParentLabel_lb, "Parent: Not Found");
03954       }  
03955 
03956       SUMAg_CF->X->DrawROI->curDrawnROI = DrawnROI; /* set the currently drawnROI */
03957 
03958       SUMA_SET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIlbl->textfield, DrawnROI->Label);
03959       
03960       SUMAg_CF->X->DrawROI->ROIval->value = DrawnROI->iLabel;
03961       sprintf(sbuf,"%d", DrawnROI->iLabel);
03962       SUMA_SET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIval->textfield, sbuf);
03963    }
03964    SUMA_RETURN (YUP);
03965 }
03966 
03967 /*!
03968    \brief Initializes the widgets in the color plane shell window based on the SUMA_OVERLAYS structue
03969 */
03970 SUMA_Boolean SUMA_InitializeColPlaneShell(SUMA_SurfaceObject *SO, SUMA_OVERLAYS *ColPlane)
03971 {
03972    static char FuncName[] = {"SUMA_InitializeColPlaneShell"};
03973    char sbuf[SUMA_MAX_LABEL_LENGTH];
03974    float range[2];
03975    int loc[2], i;
03976    
03977    SUMA_Boolean LocalHead = NOPE;
03978    
03979    SUMA_ENTRY;
03980    
03981    SUMA_LH("Called");
03982    if (!SO->SurfCont->ColPlane_fr) SUMA_RETURN(YUP);
03983    
03984    if (!ColPlane) {
03985       SUMA_LH("Initializing with NULL");
03986       SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 0, 1, "-");
03987       SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 1, 1, "-");
03988       SUMA_SET_TEXT_FIELD(SO->SurfCont->ColPlaneOrder->textfield, "-");
03989       SUMA_SET_TEXT_FIELD(SO->SurfCont->ColPlaneOpacity->textfield,"-");
03990       SUMA_SET_TEXT_FIELD(SO->SurfCont->ColPlaneDimFact->textfield,"-");
03991    }else {
03992       SUMA_LH("Initializing for real");
03993       if (strlen(ColPlane->Label) + strlen(SO->Label) +25 > SUMA_MAX_LABEL_LENGTH) {
03994          SUMA_SL_Warn("Surface Labels too long!");
03995          SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 0, 1, "Surface Labels too long!");
03996          SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 1, 1, "Surface Labels too long!");
03997       } else {
03998          if (strlen(SO->Label) > 40) {
03999             char *tmpstr=NULL;
04000             tmpstr = SUMA_truncate_string(SO->Label, 40);
04001             if (tmpstr) { 
04002                sprintf (sbuf, "Label: %s\nParent: %s", ColPlane->Label, tmpstr);
04003                free(tmpstr); tmpstr = NULL;
04004             }
04005             SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 0, 1, ColPlane->Label);
04006             SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 1, 1, tmpstr);
04007          } else {
04008             sprintf (sbuf, "Label: %s\nParent: %s", ColPlane->Label, SO->Label);
04009          }
04010          SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 0, 1, ColPlane->Label);
04011          SUMA_INSERT_CELL_STRING(SO->SurfCont->ColPlaneLabelTable, 1, 1, SO->Label);
04012       }
04013       
04014       SO->SurfCont->ColPlaneOrder->value = ColPlane->PlaneOrder;
04015       sprintf(sbuf,"%d", ColPlane->PlaneOrder);
04016       SUMA_SET_TEXT_FIELD(SO->SurfCont->ColPlaneOrder->textfield, sbuf);
04017       
04018       SO->SurfCont->ColPlaneOpacity->value = ColPlane->GlobalOpacity;
04019       sprintf(sbuf,"%.1f", ColPlane->GlobalOpacity);
04020       SUMA_SET_TEXT_FIELD(SO->SurfCont->ColPlaneOpacity->textfield, sbuf);
04021       
04022       if (ColPlane->OptScl) SO->SurfCont->ColPlaneDimFact->value = ColPlane->OptScl->BrightFact;
04023       else SO->SurfCont->ColPlaneDimFact->value = ColPlane->DimFact;
04024       sprintf(sbuf,"%.1f", SO->SurfCont->ColPlaneDimFact->value);
04025       SUMA_SET_TEXT_FIELD(SO->SurfCont->ColPlaneDimFact->textfield, sbuf);
04026       
04027    }
04028    
04029    XmToggleButtonSetState (SO->SurfCont->ColPlaneShow_tb, ColPlane->Show, NOPE);
04030 
04031    SO->SurfCont->curColPlane = ColPlane;
04032       
04033    /* update the cross hair group */
04034    SUMA_Init_SurfCont_CrossHair(SO);
04035    
04036    /* set the colormap */
04037    if (SO->SurfCont->cmp_ren->cmap_context) {
04038       if (strcmp(SO->SurfCont->curColPlane->cmapname, "explicit") == 0) {
04039          if (XtIsManaged(SO->SurfCont->DsetMap_fr)) {
04040             SUMA_LH("An RGB dset, no surface controls to be seen");
04041             XtUnmanageChild(SO->SurfCont->DsetMap_fr);
04042             XtUnmanageChild(XtParent(SO->SurfCont->DsetMap_fr));
04043          }
04044       } else {
04045          if (!XtIsManaged(SO->SurfCont->DsetMap_fr)) {
04046             SUMA_LH("A non RGB dset, surface controls need to be seen\nBut only when ColPlane_fr is also shown (frame may be hidden by Dsets button action)");
04047             if (XtIsManaged(SO->SurfCont->ColPlane_fr)) {
04048                XtManageChild(XtParent(SO->SurfCont->DsetMap_fr));
04049                XtManageChild(SO->SurfCont->DsetMap_fr);
04050             }
04051          }
04052          SUMA_cmap_wid_handleRedisplay((XtPointer) SO); 
04053 
04054          /* set the widgets for dems mapping options */
04055          SUMA_set_cmap_options(SO, YUP, NOPE);
04056 
04057          /* set the menu to show the colormap used */
04058          SUMA_SetCmapMenuChoice(SO, ColPlane->cmapname);
04059 
04060          /* set the values for the threshold bar */
04061          if (SUMA_GetDsetColRange(SO->SurfCont->curColPlane->dset_link, SO->SurfCont->curColPlane->OptScl->tind, range, loc)) {   
04062             SUMA_SetScaleRange(SO, range );
04063          }
04064       }
04065    } else {
04066       SUMA_LH("cmap_context was NULL");
04067    }
04068    
04069    
04070    SUMA_RETURN (YUP);
04071 }
04072 
04073 /*!
04074    \brief Updates color plane editing windows of surfaces related to SO, 
04075    if the color planes are open and displaying the same plane
04076    
04077 */
04078 SUMA_Boolean SUMA_UpdateColPlaneShellAsNeeded(SUMA_SurfaceObject *SO)
04079 {
04080    static char FuncName[] = {"SUMA_UpdateColPlaneShellAsNeeded"};
04081    int i=-1;
04082    SUMA_SurfaceObject *SOi=NULL;
04083    SUMA_Boolean LocalHead = NOPE;
04084    
04085    SUMA_ENTRY;
04086    
04087    SUMA_LH("Called");
04088    /* find out which surfaces are related to SO */
04089    for (i=0; i<SUMAg_N_DOv; ++i) {
04090       if (SUMA_isSO(SUMAg_DOv[i])) {
04091          SOi = (SUMA_SurfaceObject *)SUMAg_DOv[i].OP;
04092          if (SOi != SO && SUMA_isRelated (SOi, SO, 1)) { /* do this for kins of the 1st order */
04093             if (SOi->SurfCont) {
04094                if (SOi->SurfCont != SO->SurfCont && SOi->SurfCont->ColPlane_fr && SOi->SurfCont->curColPlane == SO->SurfCont->curColPlane) {
04095                   SUMA_InitializeColPlaneShell(SOi, SOi->SurfCont->curColPlane);
04096                }
04097             }
04098          }
04099       }
04100    }
04101    
04102    SUMA_RETURN(YUP);
04103 }
04104 
04105 /*!
04106    \brief Creates the widgets for the DrawROI window
04107 */
04108 void SUMA_CreateDrawROIWindow(void)
04109 {
04110    static char FuncName[] = {"SUMA_CreateDrawROIWindow"};
04111    Widget form, frame, rc, pb, rc_ur, rcv, rc_switch, rc_save;
04112    int i;
04113    SUMA_Boolean LocalHead = NOPE;
04114    
04115    SUMA_ENTRY;
04116 
04117    if (SUMAg_CF->X->DrawROI->AppShell) {
04118       fprintf (SUMA_STDERR,"Error %s: SUMAg_CF->X->DrawROI->AppShell!=NULL. Should not be here.\n", FuncName);
04119       SUMA_RETURNe;
04120    }
04121     
04122    /* create as a separate application shell, you do not want a parent to this controller that
04123    can be closed or withdrawn temporarily */
04124    SUMAg_CF->X->DrawROI->AppShell = XtVaAppCreateShell("Draw ROI" , "Suma" ,
04125       topLevelShellWidgetClass , SUMAg_CF->X->DPY_controller1 ,
04126       NULL ) ;
04127    
04128    /* turn off default delete response. If you do not do that, you will suffer.*/
04129    XtVaSetValues( SUMAg_CF->X->DrawROI->AppShell,
04130            XmNdeleteResponse, XmDO_NOTHING,
04131            NULL);  
04132              
04133    /* handle the close button from window manager */
04134    XmAddWMProtocolCallback(/* make "Close" window menu work */
04135       SUMAg_CF->X->DrawROI->AppShell,
04136       XmInternAtom( SUMAg_CF->X->DPY_controller1 , "WM_DELETE_WINDOW" , False ) ,
04137       SUMA_cb_CloseDrawROIWindow, NULL) ;
04138    
04139    /* create a form widget, manage it at the end ...*/
04140    form = XtVaCreateWidget ("dialog", 
04141       xmFormWidgetClass, SUMAg_CF->X->DrawROI->AppShell,
04142       XmNborderWidth , 0 ,
04143       XmNmarginHeight , SUMA_MARGIN ,
04144       XmNmarginWidth  , SUMA_MARGIN ,
04145       XmNshadowThickness, 2,
04146       XmNshadowType, XmSHADOW_ETCHED_IN,
04147       NULL); 
04148    
04149    /* a frame to put stuff in */
04150    frame = XtVaCreateWidget ("dialog",
04151       xmFrameWidgetClass, form,
04152       XmNleftAttachment , XmATTACH_FORM ,
04153       XmNtopAttachment  , XmATTACH_FORM ,
04154       XmNshadowType , XmSHADOW_ETCHED_IN ,
04155       XmNshadowThickness , 5 ,
04156       XmNtraversalOn , False ,
04157       NULL); 
04158    
04159    XtVaCreateManagedWidget ("ROI",
04160       xmLabelWidgetClass, frame, 
04161       XmNchildType, XmFRAME_TITLE_CHILD,
04162       XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
04163       NULL);
04164    
04165    
04166    /* vertical row column to stack horizontal rcs in */
04167    rcv = XtVaCreateWidget ("rowcolumn",
04168          xmRowColumnWidgetClass, frame,
04169          XmNorientation , XmVERTICAL ,
04170          XmNmarginHeight, 0 ,
04171          XmNmarginWidth , 0 ,
04172          NULL);
04173          
04174    /* row column for the parent surface name */
04175    rc = XtVaCreateWidget ("rowcolumn",
04176          xmRowColumnWidgetClass, rcv,
04177          XmNpacking, XmPACK_TIGHT, 
04178          XmNorientation , XmHORIZONTAL ,
04179          XmNmarginHeight, 0 ,
04180          XmNmarginWidth , 0 ,
04181          NULL);
04182    
04183    /*put a label containing the ROI's parent surface name */
04184    SUMAg_CF->X->DrawROI->ParentLabel_lb = XtVaCreateManagedWidget ("Parent: N/A", 
04185             xmLabelWidgetClass, rc,
04186             NULL);
04187    MCW_register_help(SUMAg_CF->X->DrawROI->ParentLabel_lb , SUMA_DrawROI_ParentLabel_help ) ;
04188    MCW_register_hint(SUMAg_CF->X->DrawROI->ParentLabel_lb , "Label of the ROI's parent surface" ) ;
04189    
04190    XtManageChild(rc);
04191    
04192    /* row column for the surface labels and the toggle DrawROI buttons */
04193    rc = XtVaCreateWidget ("rowcolumn",
04194          xmRowColumnWidgetClass, rcv,
04195          XmNpacking, XmPACK_TIGHT, 
04196          XmNorientation , XmHORIZONTAL ,
04197          XmNmarginHeight, 0 ,
04198          XmNmarginWidth , 0 ,
04199          NULL);
04200 
04201    /*put a toggle button for the DrawROI more */
04202    /* Turn on the ROI drawing mode, since that is what the users want to do the first time they open this window */
04203    SUMAg_CF->ROI_mode = YUP;
04204    /* make a call to change the cursor */
04205    SUMA_UpdateAllViewerCursor(); 
04206    SUMAg_CF->X->DrawROI->DrawROImode_tb = XtVaCreateManagedWidget("Draw Mode", 
04207       xmToggleButtonWidgetClass, rc, NULL);
04208    XmToggleButtonSetState (SUMAg_CF->X->DrawROI->DrawROImode_tb, SUMAg_CF->ROI_mode, NOPE);
04209    XtAddCallback (SUMAg_CF->X->DrawROI->DrawROImode_tb, 
04210                   XmNvalueChangedCallback, SUMA_cb_DrawROImode_toggled, 
04211                   NULL);
04212    MCW_register_help(SUMAg_CF->X->DrawROI->DrawROImode_tb , SUMA_DrawROI_DrawROIMode_help ) ;
04213    MCW_register_hint(SUMAg_CF->X->DrawROI->DrawROImode_tb , "Toggles ROI drawing mode" ) ;
04214 
04215    /* set the toggle button's select color */
04216    SUMA_SET_SELECT_COLOR(SUMAg_CF->X->DrawROI->DrawROImode_tb);
04217    
04218    /*put a toggle button for the Pen mode */
04219    SUMAg_CF->X->DrawROI->Penmode_tb = XtVaCreateManagedWidget("Pen", 
04220       xmToggleButtonWidgetClass, rc, NULL);
04221    XmToggleButtonSetState (SUMAg_CF->X->DrawROI->Penmode_tb, SUMAg_CF->Pen_mode, NOPE);
04222    XtAddCallback (SUMAg_CF->X->DrawROI->Penmode_tb, 
04223                   XmNvalueChangedCallback, SUMA_cb_DrawROIPen_toggled, 
04224                   NULL);
04225    MCW_register_help(SUMAg_CF->X->DrawROI->Penmode_tb , SUMA_DrawROI_PenMode_help ) ;
04226    MCW_register_hint(SUMAg_CF->X->DrawROI->Penmode_tb , "Toggles Pen drawing mode" ) ;
04227 
04228    /* set the toggle button's select color */
04229    SUMA_SET_SELECT_COLOR(SUMAg_CF->X->DrawROI->Penmode_tb);
04230    
04231    /* set sensitivity of Pen button */
04232    if (SUMAg_CF->ROI_mode) XtSetSensitive (SUMAg_CF->X->DrawROI->Penmode_tb, 1);
04233    else XtSetSensitive (SUMAg_CF->X->DrawROI->Penmode_tb, 0);
04234    
04235    /* Put a toggle button for real time communication with AFNI */
04236    SUMAg_CF->X->DrawROI->AfniLink_tb = XtVaCreateManagedWidget("Afni", 
04237       xmToggleButtonWidgetClass, rc, NULL);
04238    
04239    #if 0
04240    /* can the link be on ? */
04241    if (SUMAg_CF->Connected) SUMAg_CF->ROI2afni = YUP;
04242    else SUMAg_CF->ROI2afni = NOPE;
04243    #endif
04244    SUMAg_CF->ROI2afni = NOPE; /* keep link off when starting, otherwise  it is confusing */
04245    
04246    XmToggleButtonSetState (SUMAg_CF->X->DrawROI->AfniLink_tb, SUMAg_CF->ROI2afni, NOPE);
04247    XtAddCallback (SUMAg_CF->X->DrawROI->AfniLink_tb, 
04248                   XmNvalueChangedCallback, SUMA_cb_AfniLink_toggled, 
04249                   NULL);
04250    MCW_register_help(SUMAg_CF->X->DrawROI->AfniLink_tb , SUMA_DrawROI_AfniLink_help ) ;
04251    MCW_register_hint(SUMAg_CF->X->DrawROI->AfniLink_tb , "Toggles Link to Afni" ) ;
04252 
04253    /* set the toggle button's select color */
04254    SUMA_SET_SELECT_COLOR(SUMAg_CF->X->DrawROI->AfniLink_tb);
04255    
04256    /* put a menu for writing distance info */
04257    SUMA_BuildMenuReset(0);
04258    SUMA_BuildMenu (rc, XmMENU_OPTION, 
04259                    "Dist", '\0', YUP, DrawROI_WhatDist_Menu, 
04260                    "DoDist", "Report length of drawn segments? (BHelp for more)", SUMA_DrawROI_WhatDist_help,   
04261                    SUMAg_CF->X->DrawROI->WhatDistMenu);
04262    XtManageChild (SUMAg_CF->X->DrawROI->WhatDistMenu[SW_DrawROI_WhatDist]);
04263    
04264     /* manage rc */
04265    XtManageChild (rc);
04266    
04267    /* add a rc for the ROI label and the ROI node value */
04268    rc = XtVaCreateWidget ("rowcolumn",
04269       xmRowColumnWidgetClass, rcv,
04270       XmNpacking, XmPACK_TIGHT, 
04271       XmNorientation , XmHORIZONTAL ,
04272       XmNmarginHeight, 0 ,
04273       XmNmarginWidth , 0 ,
04274       NULL);
04275   
04276    
04277    SUMA_CreateTextField ( rc, "Label:",
04278                            6, SUMA_DrawROI_NewLabel,
04279                            "Label of ROI being drawn", SUMA_DrawROI_Label_help,
04280                            SUMAg_CF->X->DrawROI->ROIlbl);
04281                         
04282    SUMA_CreateArrowField ( rc, "Value:",
04283                            1, 0, 999, 1,
04284                            3, SUMA_int,
04285                            NOPE,
04286                            SUMA_DrawROI_NewValue, NULL,
04287                            "Integer value associated with ROI", SUMA_DrawROI_Value_help,
04288                            SUMAg_CF->X->DrawROI->ROIval);
04289    /* manage  rc */
04290    XtManageChild (rc);
04291    
04292    
04293    /* a separator */
04294    XtVaCreateManagedWidget ("sep", xmSeparatorWidgetClass, rcv, NULL);
04295    
04296    /* add rc for undo, redo buttons */
04297    rc_ur = XtVaCreateWidget ("rowcolumn",
04298       xmRowColumnWidgetClass, rcv,
04299       XmNpacking, XmPACK_TIGHT, 
04300       XmNorientation , XmHORIZONTAL ,
04301       XmNmarginHeight, SUMA_MARGIN ,
04302       XmNmarginWidth , SUMA_MARGIN ,
04303       NULL);
04304 
04305    SUMAg_CF->X->DrawROI->Undo_pb = XtVaCreateWidget ("Undo", 
04306       xmPushButtonWidgetClass, rc_ur, 
04307       NULL);
04308    XtAddCallback (SUMAg_CF->X->DrawROI->Undo_pb, XmNactivateCallback, SUMA_cb_DrawROI_Undo, NULL);   
04309    MCW_register_help(SUMAg_CF->X->DrawROI->Undo_pb , SUMA_DrawROI_Undo_help ) ;
04310    MCW_register_hint(SUMAg_CF->X->DrawROI->Undo_pb , "Undo the last action on the stack" ) ;
04311    XtManageChild (SUMAg_CF->X->DrawROI->Undo_pb);
04312    
04313    SUMAg_CF->X->DrawROI->Redo_pb = XtVaCreateWidget ("Redo", 
04314       xmPushButtonWidgetClass, rc_ur, 
04315       NULL);
04316    XtAddCallback (SUMAg_CF->X->DrawROI->Redo_pb, XmNactivateCallback, SUMA_cb_DrawROI_Redo, NULL);
04317    MCW_register_help(SUMAg_CF->X->DrawROI->Redo_pb , SUMA_DrawROI_Redo_help ) ;
04318    MCW_register_hint(SUMAg_CF->X->DrawROI->Redo_pb , "Redo the last undone action" ) ;
04319    XtManageChild (SUMAg_CF->X->DrawROI->Redo_pb);
04320    
04321    XtVaCreateManagedWidget (  "sep", 
04322                               xmSeparatorWidgetClass, rc_ur, 
04323                               XmNorientation, XmVERTICAL,NULL);
04324    
04325    SUMAg_CF->X->DrawROI->Join_pb = XtVaCreateWidget ("Join", 
04326       xmPushButtonWidgetClass, rc_ur, 
04327       NULL);
04328    XtAddCallback (SUMAg_CF->X->DrawROI->Join_pb, XmNactivateCallback, SUMA_cb_DrawROI_Join, NULL);
04329    MCW_register_help(SUMAg_CF->X->DrawROI->Join_pb , SUMA_DrawROI_Join_help ) ;
04330    MCW_register_hint(SUMAg_CF->X->DrawROI->Join_pb , "Join the first node of the path to the last" ) ;
04331    XtManageChild (SUMAg_CF->X->DrawROI->Join_pb);
04332                                  
04333    SUMAg_CF->X->DrawROI->Finish_pb = XtVaCreateWidget ("Finish", 
04334       xmPushButtonWidgetClass, rc_ur, 
04335       NULL);
04336    XtAddCallback (SUMAg_CF->X->DrawROI->Finish_pb, XmNactivateCallback, SUMA_cb_DrawROI_Finish, NULL);
04337    MCW_register_help(SUMAg_CF->X->DrawROI->Finish_pb , SUMA_DrawROI_Finish_help ) ;
04338    MCW_register_hint(SUMAg_CF->X->DrawROI->Finish_pb , "Label ROI as finished." ) ;
04339    XtManageChild (SUMAg_CF->X->DrawROI->Finish_pb);
04340                                  
04341    /* a separator */
04342    XtVaCreateManagedWidget ("sep", xmSeparatorWidgetClass, rcv, NULL);
04343 
04344    /* manage rc_ur */
04345    XtManageChild (rc_ur);
04346   
04347    /* add rc for switchin */
04348    rc_switch = XtVaCreateWidget ("rowcolumn",
04349       xmRowColumnWidgetClass, rcv,
04350       XmNpacking, XmPACK_TIGHT, 
04351       XmNorientation , XmHORIZONTAL ,
04352       XmNmarginHeight, SUMA_MARGIN ,
04353       XmNmarginWidth , SUMA_MARGIN ,
04354       NULL);
04355 
04356    
04357    
04358    /* put a push button to switch between ROIs */
04359    SUMAg_CF->X->DrawROI->SwitchROIlst = SUMA_AllocateScrolledList ("Switch ROI", SUMA_LSP_SINGLE, 
04360                               NOPE, YUP,
04361                               SUMAg_CF->X->DrawROI->AppShell, SWP_TOP_LEFT,
04362                               SUMA_cb_SelectSwitchROI, NULL,
04363                               SUMA_cb_SelectSwitchROI, NULL,
04364                               SUMA_cb_CloseSwitchROI, NULL);
04365     
04366    pb = XtVaCreateWidget ("Switch ROI", xmPushButtonWidgetClass, rc_switch, NULL);
04367    XtAddCallback (pb, XmNactivateCallback, SUMA_cb_DrawROI_SwitchROI, SUMAg_CF->X->DrawROI->SwitchROIlst);
04368    MCW_register_help(pb , SUMA_DrawROI_SwitchROI_help ) ;
04369    MCW_register_hint(pb , "Switch between ROIs." ) ;
04370    XtManageChild (pb);
04371    
04372    SUMAg_CF->X->DrawROI->Load_pb = XtVaCreateWidget ("Load", 
04373       xmPushButtonWidgetClass, rc_switch, 
04374       NULL);
04375    XtAddCallback (SUMAg_CF->X->DrawROI->Load_pb, XmNactivateCallback, SUMA_cb_DrawROI_Load, NULL);
04376    MCW_register_help(SUMAg_CF->X->DrawROI->Load_pb , SUMA_DrawROI_Load_help ) ;
04377    MCW_register_hint(SUMAg_CF->X->DrawROI->Load_pb , "Load a Drawn ROI" ) ;
04378    XtManageChild (SUMAg_CF->X->DrawROI->Load_pb);
04379    
04380    XtVaCreateManagedWidget (  "sep", 
04381                            xmSeparatorWidgetClass, rc_switch, 
04382                            XmNorientation, XmVERTICAL,NULL);
04383                                                             
04384    SUMAg_CF->X->DrawROI->Delete_pb = XtVaCreateWidget ("delete ROI", 
04385       xmPushButtonWidgetClass, rc_switch, 
04386       NULL);
04387    XtAddCallback (SUMAg_CF->X->DrawROI->Delete_pb, XmNactivateCallback, SUMA_cb_DrawROI_Delete, NULL);
04388    MCW_register_hint( SUMAg_CF->X->DrawROI->Delete_pb , "Click twice in 5 seconds to delete ROI. No Undo for this action." ) ;
04389    MCW_register_help( SUMAg_CF->X->DrawROI->Delete_pb , SUMA_DrawROI_DeleteROI_help);
04390    MCW_set_widget_bg( SUMAg_CF->X->DrawROI->Delete_pb , MCW_hotcolor(SUMAg_CF->X->DrawROI->Delete_pb) , 0 ) ;
04391 
04392    XtManageChild (SUMAg_CF->X->DrawROI->Delete_pb); 
04393 
04394 
04395    /* manage rc_switch */
04396    XtManageChild (rc_switch);
04397    
04398    /* a separator */
04399    XtVaCreateManagedWidget ("sep", xmSeparatorWidgetClass, rcv, NULL);
04400    
04401    /* add rc for savin */
04402    rc_save = XtVaCreateWidget ("rowcolumn",
04403       xmRowColumnWidgetClass, rcv,
04404       XmNpacking, XmPACK_TIGHT, 
04405       XmNorientation , XmHORIZONTAL ,
04406       XmNmarginHeight, SUMA_MARGIN ,
04407       XmNmarginWidth , SUMA_MARGIN ,
04408       NULL);
04409 
04410    SUMAg_CF->X->DrawROI->Save_pb = XtVaCreateWidget ("Save", 
04411       xmPushButtonWidgetClass, rc_save, 
04412       NULL);
04413    XtAddCallback (SUMAg_CF->X->DrawROI->Save_pb, XmNactivateCallback, SUMA_cb_DrawROI_Save, NULL);
04414    MCW_register_help(SUMAg_CF->X->DrawROI->Save_pb , SUMA_DrawROI_Save_help ) ;
04415    MCW_register_hint(SUMAg_CF->X->DrawROI->Save_pb , "Save the Drawn ROI to disk." ) ;
04416    XtManageChild (SUMAg_CF->X->DrawROI->Save_pb);
04417 
04418    /* Saving Mode */
04419    SUMA_BuildMenuReset(0);
04420    SUMA_BuildMenu (rc_save, XmMENU_OPTION, 
04421                                NULL, '\0', YUP, DrawROI_SaveMode_Menu, 
04422                                "Frm.", "File format for saving ROI", SUMA_DrawROI_SaveFormat_help, 
04423                                SUMAg_CF->X->DrawROI->SaveModeMenu);
04424    XtManageChild (SUMAg_CF->X->DrawROI->SaveModeMenu[SW_DrawROI_SaveMode]);
04425       
04426    /* Saving what ? */
04427    SUMA_BuildMenuReset(0);
04428    SUMA_BuildMenu (rc_save, XmMENU_OPTION, 
04429                                NULL, '\0', YUP, DrawROI_SaveWhat_Menu, 
04430                                "What", "Which ROIs to save?", SUMA_DrawROI_SaveWhat_help,   
04431                                SUMAg_CF->X->DrawROI->SaveWhatMenu);
04432    XtManageChild (SUMAg_CF->X->DrawROI->SaveWhatMenu[SW_DrawROI_SaveWhat]);
04433       
04434 
04435    XtVaCreateManagedWidget (  "sep", 
04436                               xmSeparatorWidgetClass, rc_save, 
04437                               XmNorientation, XmVERTICAL,NULL);
04438 
04439    pb = XtVaCreateWidget ("BHelp", 
04440       xmPushButtonWidgetClass, rc_save, 
04441       NULL);
04442    XtAddCallback (pb, XmNactivateCallback, MCW_click_help_CB, NULL);  
04443    MCW_register_help(pb , SUMA_help_help ) ;
04444    MCW_register_hint(pb , "Press this button then click on a button/label/menu for more help." ) ;
04445    XtManageChild (pb);
04446     
04447    SUMAg_CF->X->DrawROI->Close_pb = XtVaCreateWidget ("Close", 
04448       xmPushButtonWidgetClass, rc_save, 
04449       NULL);   
04450    XtAddCallback (SUMAg_CF->X->DrawROI->Close_pb, XmNactivateCallback, SUMA_cb_CloseDrawROIWindow, NULL);
04451    MCW_register_hint(SUMAg_CF->X->DrawROI->Close_pb  , "Close Draw ROI window" ) ;
04452    MCW_register_help(SUMAg_CF->X->DrawROI->Close_pb  , SUMA_closeDrawROI_help ) ;
04453    XtManageChild (SUMAg_CF->X->DrawROI->Close_pb);  
04454    
04455    /* manage rc_save */
04456    XtManageChild (rc_save);
04457 
04458    /* manage vertical rc */
04459    XtManageChild (rcv);
04460    
04461    /* manage frame */
04462    XtManageChild (frame);
04463    
04464    /* manage form */
04465    XtManageChild (form);
04466 
04467    /* position the widget relative to the first open viewer */
04468    i=0;
04469    while (i < SUMAg_N_SVv && !SUMAg_SVv[i].X->ViewCont->TopLevelShell && SUMAg_SVv[i].isShaded) ++i; 
04470 
04471    if (i < SUMAg_N_SVv) {
04472       if (LocalHead) fprintf (SUMA_STDERR, "%s: i = %d\n", FuncName, i);
04473       SUMA_PositionWindowRelative (SUMAg_CF->X->DrawROI->AppShell, SUMAg_SVv[i].X->TOPLEVEL, SWP_TOP_RIGHT);
04474    }
04475 
04476    /* realize the widget */
04477    XtRealizeWidget (SUMAg_CF->X->DrawROI->AppShell);
04478    
04479    
04480    SUMA_RETURNe;
04481 }
04482 
04483 /*!
04484    \brief: Creates and initializes the structure for a scrolled list
04485    
04486    \param Label (char *) Label of window containing list. 
04487          Label should be freed (if necessary) after this function returns.
04488    \param SelectPolicy (SUMA_ListSelectPolicy) list selection policy
04489    \param RemoveDups (SUMA_Boolean) YUP: Allow duplicate entries, NOPE: Purge duplicate entries
04490    \param ShowSorted (SUMA_Boolean) YUP: Sort list entries
04491    \param PosRef (Widget) Widget to position list relative to
04492    \param Pos (SUMA_WINDOW_POSITION) position of list relative to PosRef
04493    \param Default_cb pointer to default selection callack function
04494    \param Default_Data (void *) pointer to default callback data, If you specify NULL then 
04495          the SUMA_LIST_WIDGET * is sent in data.
04496    \param Select_cb pointer to selection callback function. That
04497          function should be ready to deal with te SelectionPolicy you have set.
04498          See Motif Programming Manual, section 12.5.
04499          Typically, you will use the same function for Select_cb and Default_cb
04500    \param Select_Data (void *) pointer to select callback data, If you specify NULL then 
04501          the SUMA_LIST_WIDGET * is sent in data.
04502    \param CloseList_cb pointer to close callback function
04503    \param CloseList_Data (void *) pointer to close callback data, If you specify NULL then 
04504          the SUMA_LIST_WIDGET * is sent in data.
04505    \return LW (SUMA_LIST_WIDGET *) allocate and initialized List Widget structure
04506    
04507    \sa SUMA_FreeScrolledList
04508    
04509 */   
04510 SUMA_LIST_WIDGET * SUMA_AllocateScrolledList (char *Label, int SelectPolicy, 
04511                                                 SUMA_Boolean RemoveDups, SUMA_Boolean ShowSorted,
04512                                                 Widget PosRef, SUMA_WINDOW_POSITION Pos,
04513                                                 void (*Default_cb)(Widget w, XtPointer data, XtPointer calldata), void *Default_Data,
04514                                                 void (*Select_cb)(Widget w, XtPointer data, XtPointer calldata), void *Select_Data,
04515                                                 void (*CloseList_cb)(Widget w, XtPointer data, XtPointer calldata), void *CloseList_Data)
04516 {
04517    static char FuncName[]={"SUMA_AllocateScrolledList"};
04518    SUMA_LIST_WIDGET *LW = NULL;
04519 
04520    SUMA_ENTRY;
04521    
04522 
04523    if (!Label) {
04524       SUMA_SLP_Err("Null Label");
04525       SUMA_RETURN(LW);
04526    }
04527    
04528    LW = (SUMA_LIST_WIDGET *) SUMA_malloc(sizeof(SUMA_LIST_WIDGET));
04529    LW->toplevel = NULL;
04530    LW->list = NULL;      
04531    LW->rc = NULL;  
04532    LW->RemoveDups = RemoveDups;
04533    LW->SelectPolicy = SelectPolicy;
04534    LW->ShowSorted = ShowSorted;
04535    LW->Label = (char *)SUMA_calloc(strlen(Label)+1, sizeof(char));
04536    LW->Label = strcpy (LW->Label, Label);
04537    LW->PosRef = PosRef;
04538    LW->Pos = Pos;
04539    LW->CloseList_cb = CloseList_cb;
04540    LW->CloseList_Data = CloseList_Data;
04541    LW->Default_cb = Default_cb;
04542    LW->Default_Data = Default_Data;
04543    LW->Select_cb = Select_cb;
04544    LW->Select_Data = Select_Data;
04545    LW->ALS = NULL;
04546    LW->isShaded = YUP;
04547    SUMA_RETURN(LW);
04548    
04549 }
04550 
04551 /*!
04552    \brief Frees the SUMA_LIST_WIDGET *
04553 */
04554 SUMA_LIST_WIDGET * SUMA_FreeScrolledList (SUMA_LIST_WIDGET *LW)
04555 {
04556    static char FuncName[]={"SUMA_FreeScrolledList"};
04557    
04558    SUMA_ENTRY;
04559    if (LW->Label) SUMA_free(LW->Label);
04560    if (LW->ALS) SUMA_FreeAssembleListStruct(LW->ALS);
04561    if (LW) SUMA_free(LW);
04562    
04563    SUMA_RETURN(NULL);
04564    
04565 }
04566 
04567 /*!
04568    \brief changes the Default_Data Select_Data  callback data for a list widget.
04569    Does not change callbacks although that can be arranged
04570    - Do not change callback data outside of this function
04571    - Make sure you remove callbacks properly or you'll end
04572    up with multiple callbacks
04573    \sa SUMA_CreateScrolledList
04574 */
04575 SUMA_Boolean SUMA_UpdateScrolledListData(SUMA_LIST_WIDGET *LW, void *Default_Data, void *Select_Data, void *CloseList_Data) 
04576 {
04577    static char FuncName[]={"SUMA_UpdateScrolledListData"};
04578    SUMA_Boolean LocalHead = NOPE;
04579 
04580    SUMA_ENTRY;
04581 
04582    if (!LW) SUMA_RETURN(NOPE);
04583    if (!LW->toplevel) { /* no callbacks yet, just assign the data values to their positions in LW */
04584       LW->Default_Data = Default_Data;
04585       LW->Select_Data = Select_Data;
04586       LW->CloseList_Data = CloseList_Data; 
04587       SUMA_RETURN(YUP);
04588    }
04589 
04590    /* need to remove old callbacks before adding new ones SEE ALSO SUMA_CreateScrolledList*/
04591    if (LW->Default_Data !=  Default_Data) {
04592       SUMA_LH("Doing Default Data..."); 
04593       if (!LW->Default_Data) {
04594          XtRemoveCallback(LW->list, XmNdefaultActionCallback, LW->Default_cb, (XtPointer)LW);
04595       } else {
04596          XtRemoveCallback (LW->list, XmNdefaultActionCallback, LW->Default_cb, (XtPointer)LW->Default_Data);
04597       }
04598       if (!Default_Data) {
04599          XtAddCallback (LW->list, XmNdefaultActionCallback, LW->Default_cb, (XtPointer)LW);
04600       } else {
04601          XtAddCallback (LW->list, XmNdefaultActionCallback, LW->Default_cb, (XtPointer)Default_Data);
04602       }
04603       LW->Default_Data =  Default_Data;
04604    }
04605 
04606    if (LW->Select_Data !=  Select_Data) { 
04607       SUMA_LH("Doing Select Data..."); 
04608       switch (LW->SelectPolicy){
04609          case SUMA_LSP_SINGLE:
04610             if (!LW->Select_Data) 
04611                XtRemoveCallback (LW->list, XmNsingleSelectionCallback, LW->Select_cb, (XtPointer)LW);
04612             else
04613                XtRemoveCallback (LW->list, XmNsingleSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04614             break;
04615          case SUMA_LSP_BROWSE:
04616             if (!LW->Select_Data) 
04617                XtRemoveCallback (LW->list, XmNbrowseSelectionCallback, LW->Select_cb, (XtPointer)LW);
04618             else
04619                XtRemoveCallback (LW->list, XmNbrowseSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04620 
04621             break;
04622          case SUMA_LSP_MULTIPLE:
04623             if (!LW->Select_Data) 
04624                XtRemoveCallback (LW->list, XmNmultipleSelectionCallback, LW->Select_cb, (XtPointer)LW);
04625             else
04626                XtRemoveCallback (LW->list, XmNmultipleSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04627 
04628             break;
04629          case SUMA_LSP_EXTENDED:
04630             if (!LW->Select_Data) 
04631                XtRemoveCallback (LW->list, XmNextendedSelectionCallback, LW->Select_cb, (XtPointer)LW);
04632             else
04633                XtRemoveCallback (LW->list, XmNextendedSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04634 
04635             break;
04636          default:
04637             SUMA_SL_Err("Bad selection policy");
04638             SUMA_RETURN(NOPE);
04639             break;
04640       }
04641 
04642       switch (LW->SelectPolicy){
04643          case SUMA_LSP_SINGLE:
04644             if (!Select_Data) 
04645                XtAddCallback (LW->list, XmNsingleSelectionCallback, LW->Select_cb, (XtPointer)LW);
04646             else
04647                XtAddCallback (LW->list, XmNsingleSelectionCallback, LW->Select_cb, (XtPointer)Select_Data); 
04648             break;
04649          case SUMA_LSP_BROWSE:
04650             if (!Select_Data) 
04651                XtAddCallback (LW->list, XmNbrowseSelectionCallback, LW->Select_cb, (XtPointer)LW);
04652             else
04653                XtAddCallback (LW->list, XmNbrowseSelectionCallback, LW->Select_cb, (XtPointer)Select_Data); 
04654 
04655             break;
04656          case SUMA_LSP_MULTIPLE:
04657             if (!Select_Data) 
04658                XtAddCallback (LW->list, XmNmultipleSelectionCallback, LW->Select_cb, (XtPointer)LW);
04659             else
04660                XtAddCallback (LW->list, XmNmultipleSelectionCallback, LW->Select_cb, (XtPointer)Select_Data); 
04661 
04662             break;
04663          case SUMA_LSP_EXTENDED:
04664             if (!Select_Data) 
04665                XtAddCallback (LW->list, XmNextendedSelectionCallback, LW->Select_cb, (XtPointer)LW);
04666             else
04667                XtAddCallback (LW->list, XmNextendedSelectionCallback, LW->Select_cb, (XtPointer)Select_Data); 
04668 
04669             break;
04670          default:
04671             SUMA_SL_Err("Bad selection policy");
04672             SUMA_RETURN(NOPE);
04673             break;
04674       }
04675 
04676       LW->Select_Data =  Select_Data;
04677 
04678    }
04679 
04680    if (LW->CloseList_Data !=  CloseList_Data) {
04681       SUMA_LH("Doing CloseList Data..."); 
04682       if (!LW->CloseList_Data) {
04683          XmRemoveWMProtocolCallback(/* make "Close" window menu work */
04684             LW->toplevel,
04685             XmInternAtom( SUMAg_CF->X->DPY_controller1  , "WM_DELETE_WINDOW" , False ) ,
04686             LW->CloseList_cb, (XtPointer)LW) ;
04687       } else {
04688          XmRemoveWMProtocolCallback(/* make "Close" window menu work */
04689             LW->toplevel,
04690             XmInternAtom( SUMAg_CF->X->DPY_controller1  , "WM_DELETE_WINDOW" , False ) ,
04691             LW->CloseList_cb, (XtPointer)LW->CloseList_Data) ;
04692       }
04693       if (!CloseList_Data) {
04694          XmAddWMProtocolCallback(/* make "Close" window menu work */
04695             LW->toplevel,
04696             XmInternAtom( SUMAg_CF->X->DPY_controller1  , "WM_DELETE_WINDOW" , False ) ,
04697             LW->CloseList_cb, (XtPointer)LW) ;
04698       } else {
04699          XmAddWMProtocolCallback(/* make "Close" window menu work */
04700             LW->toplevel,
04701             XmInternAtom( SUMAg_CF->X->DPY_controller1  , "WM_DELETE_WINDOW" , False ) ,
04702             LW->CloseList_cb, (XtPointer)CloseList_Data) ;
04703       }
04704 
04705       LW->CloseList_Data =  CloseList_Data;         
04706    } 
04707    SUMA_RETURN(YUP);
04708 }
04709 /*!
04710    \brief creates a scrolled list window 
04711    SUMA_CreateScrolledList (  clist, N_clist, Partial, LW);
04712    
04713    \param clist (char **) list of strings. You should free it after you call the function
04714    \param N_clist (int) number of elements in clist
04715    \param Partial (SUMA_Boolean) YUP: add to existing list, NOPE: Replace it. 
04716          If !Partial and !LW->RemoveDups then the previous selection position is lost.
04717    \param LW (SUMA_LIST_WIDGET *) initialized list widget structure.
04718    
04719    \sa SUMA_AllocateScrolledList
04720    \sa SUMA_UpdateScrolledListData
04721    - If LW->toplevel = NULL then a new widget is created, otherwise only the list is updated
04722    
04723                            
04724 */
04725 void SUMA_CreateScrolledList (    char **clist, int N_clist, SUMA_Boolean Partial,  
04726                                   SUMA_LIST_WIDGET *LW)
04727 {
04728    static char FuncName[]={"SUMA_CreateScrolledList"};
04729    XmString  str, *strlist;
04730    char *text;
04731    int i = -1, iclist, u_bound, l_bound = 0, n;
04732    Arg args[20];
04733    SUMA_Boolean New = NOPE;
04734    SUMA_Boolean LocalHead = NOPE;
04735    
04736    
04737    SUMA_ENTRY;
04738    
04739    if (!LW) { /* Never been created */
04740       SUMA_SL_Err ("Null LW!");
04741       SUMA_RETURNe;
04742    }
04743    
04744    if (N_clist <= 0) {
04745       SUMA_SLP_Note ("No ROIs found");
04746       SUMA_RETURNe;
04747    }
04748    
04749    if (!LW->toplevel) { /* widget has never been created or had been destroyed, create it anew */  
04750       /* create the widget */ 
04751       LW->toplevel = XtVaAppCreateShell(LW->Label , "Suma" ,
04752                      topLevelShellWidgetClass , SUMAg_CF->X->DPY_controller1 ,
04753                      NULL ) ;
04754       
04755       /* cancel the kill button's effect */
04756       XtVaSetValues( LW->toplevel,
04757            XmNdeleteResponse, XmDO_NOTHING,
04758            NULL);  
04759              
04760       /* handle the close button from window manager  SEE ALSO  SUMA_UpdateScrolledListData */
04761       if (!LW->CloseList_Data) {
04762          XmAddWMProtocolCallback(/* make "Close" window menu work */
04763             LW->toplevel,
04764             XmInternAtom( SUMAg_CF->X->DPY_controller1  , "WM_DELETE_WINDOW" , False ) ,
04765             LW->CloseList_cb, (XtPointer)LW) ;
04766       } else {
04767          XmAddWMProtocolCallback(/* make "Close" window menu work */
04768             LW->toplevel,
04769             XmInternAtom( SUMAg_CF->X->DPY_controller1  , "WM_DELETE_WINDOW" , False ) ,
04770             LW->CloseList_cb, (XtPointer)LW->CloseList_Data) ;
04771       }   
04772       
04773 
04774       LW->rc = XtVaCreateWidget("Tonka", xmRowColumnWidgetClass, LW->toplevel, NULL);
04775       n = 0;
04776       XtSetArg (args[n], XmNitemCount,      0); n++;
04777       XtSetArg (args[n], XmNlistSizePolicy,   XmCONSTANT   ); n++;
04778       LW->list = XmCreateScrolledList (LW->rc, "Tonka", args, n);
04779 
04780       
04781       
04782       /* add the default selection callback  SEE ALSO  SUMA_UpdateScrolledListData */
04783       if (!LW->Default_Data) {
04784          XtAddCallback (LW->list, XmNdefaultActionCallback, LW->Default_cb, (XtPointer)LW);
04785       } else {
04786          XtAddCallback (LW->list, XmNdefaultActionCallback, LW->Default_cb, (XtPointer)LW->Default_Data);
04787       }        
04788 
04789       /* set the selection policy SEE ALSO  SUMA_UpdateScrolledListData */
04790       switch (LW->SelectPolicy){
04791          case SUMA_LSP_SINGLE:
04792             XtVaSetValues( LW->list, XmNselectionPolicy, XmSINGLE_SELECT, NULL);
04793             if (!LW->Select_Data) 
04794                XtAddCallback (LW->list, XmNsingleSelectionCallback, LW->Select_cb, (XtPointer)LW);
04795             else
04796                XtAddCallback (LW->list, XmNsingleSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04797             break;
04798          case SUMA_LSP_BROWSE:
04799             if (!LW->Select_Data) 
04800                XtAddCallback (LW->list, XmNbrowseSelectionCallback, LW->Select_cb, (XtPointer)LW);
04801             else
04802                XtAddCallback (LW->list, XmNbrowseSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04803             
04804             XtVaSetValues( LW->list, XmNselectionPolicy, XmBROWSE_SELECT, NULL);
04805             break;
04806          case SUMA_LSP_MULTIPLE:
04807             if (!LW->Select_Data) 
04808                XtAddCallback (LW->list, XmNmultipleSelectionCallback, LW->Select_cb, (XtPointer)LW);
04809             else
04810                XtAddCallback (LW->list, XmNmultipleSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04811             
04812             XtVaSetValues( LW->list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
04813             break;
04814          case SUMA_LSP_EXTENDED:
04815             if (!LW->Select_Data) 
04816                XtAddCallback (LW->list, XmNextendedSelectionCallback, LW->Select_cb, (XtPointer)LW);
04817             else
04818                XtAddCallback (LW->list, XmNextendedSelectionCallback, LW->Select_cb, (XtPointer)LW->Select_Data); 
04819             
04820             XtVaSetValues( LW->list, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
04821             break;
04822          default:
04823             SUMA_SL_Err("Bad selection policy");
04824             SUMA_RETURNe;
04825             break;
04826       }
04827        
04828       /* manage it */
04829       if (LocalHead) fprintf(SUMA_STDERR, "%s: Managing ..\n", FuncName);
04830       XtManageChild (LW->list);
04831       XtManageChild (LW->rc);
04832 
04833       SUMA_PositionWindowRelative (LW->toplevel, LW->PosRef, LW->Pos);   
04834 
04835       LW->isShaded = NOPE;
04836       New = YUP;
04837       
04838    } else {
04839       /*map and raise the baby */
04840       XMapRaised(SUMAg_CF->X->DPY_controller1, XtWindow(LW->toplevel));
04841       LW->isShaded = NOPE;
04842    }  
04843 
04844    
04845    /* now cycle through the elements in clist and add them, if they are new, in alphabetical order */
04846    if (!Partial && !LW->RemoveDups) {
04847       if (LocalHead) fprintf (SUMA_STDERR, "%s: New full list, deleting old entries. \n", FuncName);
04848       XmListDeleteAllItems(LW->list);
04849    }else {
04850       if (LocalHead) fprintf (SUMA_STDERR, "%s: Partial list, will add.\n", FuncName);
04851    }
04852    for (iclist=0; iclist < N_clist; iclist++)     {
04853       SUMA_LH(clist[iclist]);
04854       if (LW->ShowSorted) {
04855          l_bound = 0;
04856          /* get the current entries (and number of entries) from the List */
04857          XtVaGetValues (LW->list,
04858                         XmNitemCount, &u_bound,
04859                         XmNitems,     &strlist,
04860                         NULL);
04861          u_bound--;
04862          /* perform binary search */
04863          while (u_bound >= l_bound) {
04864             int i = l_bound + (u_bound - l_bound) / 2;
04865             /* convert the compound string into a regular C string */
04866             if (!XmStringGetLtoR (strlist[i], XmFONTLIST_DEFAULT_TAG, &text))
04867                break;
04868             if (strcmp (text, clist[iclist]) > 0)
04869                u_bound = i - 1; /* newtext comes before item */
04870             else
04871                l_bound = i + 1; /* newtext comes after item */
04872             XtFree (text); /* XmStringGetLtoR() allocates memory ... yuk */
04873          }
04874       } else { /* Not sorted, add to bottom*/
04875         l_bound = 0; 
04876       }
04877       
04878       if (LocalHead) fprintf (SUMA_STDERR,"%s: Adding %s...\n", FuncName, clist[iclist]);
04879       str = XmStringCreateLocalized (clist[iclist]); 
04880 
04881       /* positions indexes start at 1, so increment accordingly */
04882       if (LW->RemoveDups) { 
04883          if (LocalHead) fprintf (SUMA_STDERR,"%s: removing duplicates\n", FuncName);
04884          if (!XmListItemExists(LW->list, str)) XmListAddItemUnselected (LW->list, str, l_bound+1);
04885       } else { 
04886          if (LocalHead) fprintf (SUMA_STDERR,"%s: with duplicates\n", FuncName);
04887          XmListAddItemUnselected (LW->list, str, l_bound+1);
04888       }
04889       XmStringFree (str);
04890    }
04891 
04892 
04893    XtVaSetValues( LW->list,                  
04894                   XmNvisibleItemCount, 10,
04895                   NULL);
04896    
04897 
04898    
04899    if (New) {
04900       /* realize the widget */
04901       XtRealizeWidget (LW->toplevel);
04902    }
04903    
04904    SUMA_RETURNe;
04905 }
04906 
04907 
04908 
04909 /*!
04910    \brief adds arrow fields
04911    SUMA_CreateArrowField (    pw, label, 
04912                               value,  vmin,  vmax,  vstep,
04913                               cwidth, type,
04914                               wrap,
04915                               NewValueCallback,
04916                               cb_data ,
04917                               AF);
04918                               
04919    \param pw (Widget)   Parent widget
04920    \param label (char *) label (NULL for nothing)
04921    \param value (float) current value
04922    \param vmin (float) minimum value
04923    \param vmax (float) maximum value
04924    \param vstep (float) arrow increment
04925    \param cwidth (int) number of columns for text field
04926    \param type (SUMA_VARTYPE) SUMA_int or SUMA_float
04927    \param wrap (SUMA_Boolean) YUP=wrap values, NOPE=clip values
04928    \param NewValueCallback(void *data) (void *) Function to call when there is a new value in town. 
04929    \param cb_data (void *) data to send to callback.
04930                            if NULL data is actually the AF structure pointer itself.
04931    \param hint (char *) if NULL, no hint
04932    \param help (char *) if NULL no help
04933    \param AF (SUMA_ARROW_TEXT_FIELD *) structure defining the arrow field.                        
04934    - AF must be pre-allocated, of course. Its fields are initialized by the values passed to the function
04935 */
04936 void SUMA_CreateArrowField ( Widget pw, char *label,
04937                               float value, float vmin, float vmax, float vstep,
04938                               int cwidth, SUMA_VARTYPE type,
04939                               SUMA_Boolean wrap,
04940                               void (*NewValueCallback)(void *data), void *cb_data,
04941                               char *hint, char *help,
04942                               SUMA_ARROW_TEXT_FIELD *AF)
04943 {
04944    static char FuncName[]={"SUMA_CreateArrowField"};
04945    
04946    SUMA_ENTRY;
04947    
04948    if (!AF) {
04949       SUMA_RegisterMessage (SUMAg_CF->MessageList, "Bad value in text field", FuncName, SMT_Error, SMA_Log);
04950       SUMA_RETURNe;  
04951    }
04952    
04953    AF->step = vstep;
04954    AF->value = value;
04955    AF->min = vmin;
04956    AF->max = vmax;
04957    AF->cwidth = cwidth;
04958    AF->type = type;
04959    AF->NewValueCallback = NewValueCallback;
04960    AF->NewValueCallbackData = cb_data;
04961    AF->modified = NOPE;
04962    AF->wrap = wrap;
04963    AF->rc = XtVaCreateManagedWidget ("Container", 
04964       xmRowColumnWidgetClass, pw,
04965       XmNpacking, XmPACK_TIGHT, 
04966       XmNorientation , XmHORIZONTAL ,
04967       NULL);
04968    if (hint) MCW_register_hint( AF->rc , hint);
04969    if (help) MCW_register_help( AF->rc , help);
04970    
04971    if (label) {
04972       AF->label =  XtVaCreateManagedWidget (label,
04973          xmLabelWidgetClass, AF->rc, 
04974          XmNmarginHeight, 0,
04975          XmNmarginTop, 0,
04976          XmNmarginBottom, 0,
04977          NULL);
04978          if (hint) MCW_register_help( AF->label , hint);
04979          if (help) MCW_register_help( AF->label , help);
04980    }else {
04981       AF->label = NULL;
04982    }
04983 
04984    AF->up = XtVaCreateManagedWidget ("arrow_up",
04985          xmArrowButtonWidgetClass, AF->rc,
04986          XmNarrowDirection,   XmARROW_UP,
04987          XmNmarginHeight, 0,
04988          XmNmarginTop, 0,
04989          XmNmarginBottom, 0,
04990          NULL);
04991    if (hint) MCW_register_help( AF->up , hint);
04992    if (help) MCW_register_help( AF->up , help);
04993 
04994    XtVaSetValues (AF->up, XmNuserData, (XtPointer)AF, NULL);
04995    XtAddCallback (AF->up, XmNarmCallback, SUMA_ATF_start_stop, (XtPointer)1);
04996    XtAddCallback (AF->up, XmNdisarmCallback, SUMA_ATF_start_stop, (XtPointer)1);
04997 
04998    AF->down = XtVaCreateManagedWidget ("arrow_dn",
04999       xmArrowButtonWidgetClass, AF->rc,
05000       XmNarrowDirection,   XmARROW_DOWN,
05001       XmNmarginHeight, 0,
05002       XmNmarginTop, 0,
05003       XmNmarginBottom, 0,
05004       NULL);
05005    if (hint) MCW_register_help( AF->down , hint);
05006    if (help) MCW_register_help( AF->down , help);
05007    XtVaSetValues (AF->down, XmNuserData, (XtPointer)AF, NULL);
05008    XtAddCallback (AF->down, XmNarmCallback, SUMA_ATF_start_stop, (XtPointer)-1);
05009    XtAddCallback (AF->down, XmNdisarmCallback, SUMA_ATF_start_stop, (XtPointer)-1);
05010 
05011    AF->textfield = XtVaCreateManagedWidget ("label",
05012       xmTextFieldWidgetClass, AF->rc,
05013       XmNuserData, (XtPointer)AF,
05014       XmNvalue, "-",
05015       XmNcolumns, AF->cwidth,
05016       XmNmarginHeight, 0,
05017       XmNmarginTop, 0,
05018       XmNmarginBottom, 0,
05019       NULL);
05020    if (hint) MCW_register_hint( AF->textfield , hint);
05021    if (help) MCW_register_help( AF->textfield , help);
05022    
05023    XtAddCallback (AF->textfield, XmNactivateCallback, SUMA_ATF_cb_label_change, (XtPointer)AF);
05024    XtAddCallback (AF->textfield, XmNmodifyVerifyCallback, SUMA_ATF_cb_label_Modify, (XtPointer)AF);
05025    
05026    /* add event handler to nitify when widget was left */
05027    XtInsertEventHandler( AF->textfield ,        /* notify when */
05028                          LeaveWindowMask ,  /* pointer leaves */
05029                          FALSE ,            /* this window */
05030                          SUMA_leave_EV,
05031                          (XtPointer) AF ,
05032                          XtListTail ) ;     /* last in queue */      
05033    XtManageChild (AF->rc);
05034    SUMA_RETURNe;
05035 }
05036 
05037 /*! 
05038    creates a text field.
05039    
05040    \sa SUMA_CreateArrowField 
05041 */
05042 void SUMA_CreateTextField ( Widget pw, char *label,
05043                               int cwidth, 
05044                               void (*NewValueCallback)(void *data),
05045                               char *hint, char *help,
05046                               SUMA_ARROW_TEXT_FIELD *AF)
05047 {
05048    static char FuncName[]={"SUMA_ATF_cb_label_Modify"};
05049 
05050    SUMA_ENTRY;
05051 
05052    /* techincally, one should have a structure that is only for text but that is not necessary, I think */
05053    
05054    AF->up = AF->down = NULL;
05055    AF->step = AF->value = AF->min = AF->max = AF->wrap = 0;
05056    
05057    AF->type = SUMA_string;
05058    AF->NewValueCallback = NewValueCallback;
05059    AF->NewValueCallbackData = NULL;
05060    AF->arrow_action = NOPE;
05061    AF->cwidth = cwidth;
05062    AF->modified = NOPE;
05063 
05064    AF->rc = XtVaCreateManagedWidget ("Container", 
05065       xmRowColumnWidgetClass, pw,
05066       XmNpacking, XmPACK_TIGHT, 
05067       XmNorientation , XmHORIZONTAL ,
05068       NULL);
05069    if (hint) MCW_register_hint( AF->rc , hint);
05070 
05071    if (label) {
05072       AF->label =  XtVaCreateManagedWidget (label,
05073          xmLabelWidgetClass, AF->rc, 
05074          XmNmarginHeight, 0,
05075          XmNmarginTop, 0,
05076          XmNmarginBottom, 0,
05077          NULL);
05078       if (hint) MCW_register_help( AF->label , hint);
05079       if (help) MCW_register_help( AF->label , help);
05080    }else {
05081       AF->label = NULL;
05082    }
05083    
05084    AF->textfield = XtVaCreateManagedWidget ("label",
05085       xmTextFieldWidgetClass, AF->rc,
05086       XmNuserData, (XtPointer)AF,
05087       XmNvalue, "0",
05088       XmNcolumns, AF->cwidth,
05089       XmNmarginHeight, 0,
05090       XmNmarginTop, 0,
05091       XmNmarginBottom, 0,
05092       NULL);
05093    if (hint) MCW_register_hint( AF->textfield , hint);
05094    if (help) MCW_register_help( AF->textfield , help);
05095    
05096    XtAddCallback (AF->textfield, XmNactivateCallback, SUMA_ATF_cb_label_change, (XtPointer)AF);
05097    XtAddCallback (AF->textfield, XmNmodifyVerifyCallback, SUMA_ATF_cb_label_Modify, (XtPointer)AF);
05098    
05099    /* add event handler to nitify when widget was left */
05100    XtInsertEventHandler( AF->textfield ,        /* notify when */
05101                          LeaveWindowMask ,  /* pointer leaves */
05102                          FALSE ,            /* this window */
05103                          SUMA_leave_EV,
05104                          (XtPointer) AF ,
05105                          XtListTail ) ;     /* last in queue */      
05106    XtManageChild (AF->rc);   
05107    SUMA_RETURNe;
05108 } 
05109 
05110 /*!
05111    \brief This function is called when label field has been modified by user keyboard input.
05112    All it does is set AF->modified to YUP
05113    
05114 */
05115 void SUMA_ATF_cb_label_Modify (Widget w, XtPointer client_data, XtPointer call_data)
05116 {
05117    static char FuncName[]={"SUMA_ATF_cb_label_Modify"};
05118    SUMA_ARROW_TEXT_FIELD *AF=NULL;
05119    
05120    SUMA_ENTRY;
05121    
05122    AF = (SUMA_ARROW_TEXT_FIELD *)client_data ;
05123    if (!AF->arrow_action) AF->modified = YUP;
05124    
05125    SUMA_RETURNe;
05126 }
05127 
05128 /*!
05129    \brief This function is called when mouse pointer leaves label field
05130    It only acts if  AF->modified 
05131 */
05132 void SUMA_leave_EV( Widget w , XtPointer client_data ,
05133                   XEvent * ev , Boolean * continue_to_dispatch )
05134 {
05135    SUMA_ARROW_TEXT_FIELD *AF=NULL; 
05136    XLeaveWindowEvent * lev = (XLeaveWindowEvent *) ev ;
05137    XmAnyCallbackStruct cbs ;
05138    static char FuncName[]={"SUMA_leave_EV"};
05139    SUMA_Boolean LocalHead = NOPE;
05140    
05141    SUMA_ENTRY;
05142 
05143    AF = (SUMA_ARROW_TEXT_FIELD *)client_data ;
05144    if( lev->type != LeaveNotify || !AF->modified ) SUMA_RETURNe; 
05145    
05146    if (LocalHead) fprintf (SUMA_STDERR, "%s: Leave notification.\n", FuncName);
05147    SUMA_ATF_cb_label_change( AF->textfield , (XtPointer) AF , NULL ) ;
05148    
05149    SUMA_RETURNe;
05150 }
05151 
05152 /*!
05153    \brief This function is called when the label field is activated by the user
05154    
05155 */
05156 void SUMA_ATF_cb_label_change (Widget w, XtPointer client_data, XtPointer call_data)
05157 {
05158    static char FuncName[]={"SUMA_ATF_cb_label_change"};
05159    SUMA_ARROW_TEXT_FIELD *AF=NULL;
05160    SUMA_Boolean LocalHead = NOPE;
05161    
05162    SUMA_ENTRY;
05163 
05164    /* make call to NewValue callback */
05165    AF = (SUMA_ARROW_TEXT_FIELD *)client_data;
05166    
05167    if (AF->type == SUMA_int || AF->type == SUMA_float) SUMA_ATF_SetValue (AF);
05168    
05169    if (!AF->NewValueCallbackData) {
05170       SUMA_LH("No Callback data.");
05171       AF->NewValueCallback((void*)AF);
05172    } else {
05173       SUMA_LH("Callback data.");
05174       AF->NewValueCallback(AF->NewValueCallbackData);
05175    }
05176    
05177    AF->modified = NOPE;
05178    SUMA_RETURNe;
05179 }
05180 
05181 /*!
05182    \brief function to handle the pressed buttons of the arrow keys
05183    
05184    -Based on code from Motif Programming Manual: arrow_timer.c
05185    
05186  - start_stop is used to start or stop the incremental changes to
05187  * the label's value.  When the button goes down, the reason is
05188  * XmCR_ARM and the timer starts.  XmCR_DISARM disables the timer.
05189  */
05190 void SUMA_ATF_start_stop (Widget w, XtPointer client_data, XtPointer call_data)
05191 {
05192    static char FuncName[]={"SUMA_ATF_start_stop"};
05193    int incr = (int) client_data;
05194    SUMA_ARROW_TEXT_FIELD *AF = NULL;
05195    void *n;
05196    XmArrowButtonCallbackStruct *cbs = 
05197         (XmArrowButtonCallbackStruct *) call_data;
05198    
05199    
05200    SUMA_ENTRY;
05201    
05202    XtVaGetValues(w, XmNuserData, &n, NULL);
05203    AF = (SUMA_ARROW_TEXT_FIELD *)n;
05204    AF->direction = incr;
05205 
05206    if (cbs->reason == XmCR_ARM) {
05207      AF->arrow_action = YUP;
05208      SUMA_ATF_change_value (AF, (XtIntervalId *)1 );
05209    } else if (cbs->reason == XmCR_DISARM) {
05210      if (AF->arrow_timer_id) XtRemoveTimeOut (AF->arrow_timer_id);
05211      /* make call to NewValue callback */
05212      if (!AF->NewValueCallbackData) 
05213          AF->NewValueCallback((void*)AF);
05214      else 
05215          AF->NewValueCallback(AF->NewValueCallbackData);
05216           
05217      AF->arrow_action = NOPE;
05218  
05219    }     
05220 
05221    SUMA_RETURNe;
05222 }
05223 
05224 /*!
05225    \brief A function that is called when the DrawROI value arrow field is set.
05226    
05227    \param data (void *) a typecast of a pointer to a SUMA_ARROW_TEXT_FIELD structure
05228 */
05229 void SUMA_DrawROI_NewValue (void *data)
05230 {
05231    static char FuncName[]={"SUMA_DrawROI_NewValue"};
05232    SUMA_ARROW_TEXT_FIELD *AF=NULL;
05233    SUMA_DRAWN_ROI *DrawnROI=NULL;
05234    static int ErrCnt=0;
05235    DList *list=NULL;
05236    SUMA_Boolean LocalHead = NOPE;
05237    
05238    SUMA_ENTRY;
05239    
05240    AF = (SUMA_ARROW_TEXT_FIELD *)data;
05241    DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
05242    
05243    if (!DrawnROI) SUMA_RETURNe;
05244    
05245    if (AF->value == DrawnROI->iLabel) SUMA_RETURNe;
05246    
05247    if (!DrawnROI->DrawStatus == SUMA_ROI_Finished) {
05248       if (LocalHead) fprintf (SUMA_STDERR, "%s: Changing ROI value from %d to %d\n", 
05249          FuncName, DrawnROI->iLabel, (int)AF->value);   
05250 
05251       DrawnROI->iLabel = (int)AF->value;
05252       ErrCnt = 0;
05253    } else {
05254       if (!ErrCnt) SUMA_SLP_Err ("ROI is marked as finished.\nNew value will not be applied.\n");
05255       ++ErrCnt;
05256       AF->value = (float)DrawnROI->iLabel;
05257       SUMA_ATF_SetString (AF); 
05258    }
05259    
05260    /* if your colors are based on the label, you've got work to do*/
05261    if (DrawnROI->ColorByLabel) {
05262       SUMA_SurfaceObject *SO=NULL;
05263       /* Now update the Paint job on the ROI plane */
05264       SO = SUMA_findSOp_inDOv (DrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
05265       if (!SO) {
05266          SUMA_SLP_Err(  "Failed to find parent surface\n"
05267                         "No color for you!");
05268          SUMA_RETURNe;
05269       }
05270       if (!SUMA_Paint_SO_ROIplanes_w (SO, SUMAg_DOv, SUMAg_N_DOv)) {
05271          SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
05272          SUMA_RETURNe;
05273       }
05274 
05275       if (!list) list = SUMA_CreateList ();
05276       SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_SumaWidget, NULL);
05277       if (!SUMA_Engine (&list)) {
05278          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Engine.\n", FuncName);
05279          SUMA_RETURNe;    
05280       }
05281    }   
05282    SUMA_RETURNe;
05283 }
05284 
05285 /*!
05286    \brief Function to update the order of a colorplane 
05287 
05288    -expects SO in data
05289 */
05290 void SUMA_ColPlane_NewOrder (void *data)
05291 {
05292    static char FuncName[]={"SUMA_ColPlane_NewOrder"};
05293    char sbuf[SUMA_MAX_LABEL_LENGTH];
05294    SUMA_SurfaceObject *SO=NULL;
05295    int Old_Order = -1, i, iMove, NetMove;
05296    SUMA_Boolean Shaded, Decent; 
05297    SUMA_Boolean LocalHead = NOPE;
05298    
05299    SUMA_ENTRY;
05300    
05301    SO = (SUMA_SurfaceObject *)data;
05302    
05303    /* make sure a new order is in order */
05304    if (SO->SurfCont->curColPlane->PlaneOrder == (int)SO->SurfCont->ColPlaneOrder->value) SUMA_RETURNe;
05305    
05306    /* Now show the new order */
05307    if (LocalHead) SUMA_Print_PlaneOrder(SO, NULL);
05308    
05309 
05310    /* Now figure out the direction of the arrow presses */
05311    NetMove = (int)SO->SurfCont->ColPlaneOrder->value - SO->SurfCont->curColPlane->PlaneOrder ; 
05312    
05313    if (LocalHead) fprintf (SUMA_STDERR,"%s:  Net move %d\n", FuncName, NetMove);
05314    iMove = 0;
05315    Decent = YUP;
05316    if (NetMove > 0) {   
05317       do {
05318          Old_Order = SO->SurfCont->curColPlane->PlaneOrder;
05319          if (!SUMA_MovePlaneUp(SO, SO->SurfCont->curColPlane->Name)) {
05320             SUMA_L_Err("Error in SUMA_MovePlaneUp.");
05321             SUMA_RETURNe;
05322          }
05323          
05324          if (SO->SurfCont->curColPlane->PlaneOrder == Old_Order) {
05325             SUMA_LH("Nothing can be done");
05326             Decent = NOPE;
05327          } else {
05328             ++iMove;
05329          } 
05330       } while (iMove < NetMove && Decent);
05331    } else if (NetMove < 0) {
05332       do {
05333          Old_Order = SO->SurfCont->curColPlane->PlaneOrder;
05334          if (!SUMA_MovePlaneDown(SO, SO->SurfCont->curColPlane->Name)) {
05335             SUMA_L_Err("Error in SUMA_MovePlaneDown.");
05336             SUMA_RETURNe;
05337          }
05338          if (SO->SurfCont->curColPlane->PlaneOrder == Old_Order) {
05339             SUMA_LH("Enough");
05340             Decent = NOPE;
05341          } else {
05342             ++iMove;
05343          } 
05344       } while (iMove < -NetMove && Decent);   
05345    } else {
05346       SUMA_LH("Hmmmmm");
05347       Decent = NOPE;
05348    }
05349    
05350    SUMA_LH("Out");
05351    /* Now show the new order */
05352    if(LocalHead) SUMA_Print_PlaneOrder(SO, NULL);
05353    
05354    /* refresh the switch list */
05355    SUMA_IS_SWITCH_COL_PLANE_SHADED(SO, Shaded);
05356    if (!Shaded) {
05357       SUMA_LH("Refreshing Col Plane List");
05358       SUMA_RefreshDsetList (SO);
05359    }
05360 
05361    if (!Decent) {
05362       /* reset order value in widget to its last acceptable value. */
05363       sprintf(sbuf,"%d", SO->SurfCont->curColPlane->PlaneOrder);
05364       SO->SurfCont->ColPlaneOrder->value = SO->SurfCont->curColPlane->PlaneOrder;
05365       SUMA_SET_TEXT_FIELD(SO->SurfCont->ColPlaneOrder->textfield, sbuf); 
05366    }
05367    
05368    SUMA_UpdateColPlaneShellAsNeeded(SO); /* update other open ColPlaneShells */
05369 
05370    if (iMove > 0) { /* something decent was done, act on it */
05371       /* a good remix and redisplay */
05372       SUMA_LH("Remix and redisplay");
05373       SUMA_RemixRedisplay (SO);
05374    }
05375    
05376    
05377    SUMA_RETURNe;
05378    
05379 }
05380 
05381 /*!
05382    \brief Function to update the opacity of a colorplane 
05383    
05384    -expects SO in data
05385 */
05386 void SUMA_ColPlane_NewOpacity (void *data)
05387 {
05388    static char FuncName[]={"SUMA_ColPlane_NewOpacity"};
05389    SUMA_SurfaceObject *SO=NULL;
05390    SUMA_Boolean LocalHead = NOPE;
05391    
05392    SUMA_ENTRY;
05393    
05394    SUMA_LH("Called");
05395    
05396    SO = (SUMA_SurfaceObject *)data;
05397 
05398    /* change the value of the global opacity */
05399    SO->SurfCont->curColPlane->GlobalOpacity = SO->SurfCont->ColPlaneOpacity->value;   
05400    if (LocalHead) fprintf(SUMA_STDERR,"%s: GlobalOpacity of %s set to %f.\n", 
05401          FuncName, SO->SurfCont->curColPlane->Name, SO->SurfCont->curColPlane->GlobalOpacity);
05402    
05403    SUMA_UpdateColPlaneShellAsNeeded(SO); /* update other open ColPlaneShells */
05404 
05405    /* a good remix and redisplay */
05406    SUMA_RemixRedisplay (SO);
05407    
05408    SUMA_RETURNe;
05409 }
05410 
05411 /*!
05412    \brief Function to update the DimFact of a colorplane 
05413    DimFact is the same as BrightFact which is not defined
05414    for explicitly colored planes 
05415    -expects SO in data
05416 */
05417 void SUMA_ColPlane_NewDimFact (void *data)
05418 {
05419    static char FuncName[]={"SUMA_ColPlane_NewDimFact"};
05420    SUMA_SurfaceObject *SO=NULL;
05421    SUMA_Boolean LocalHead = NOPE;
05422    
05423    SUMA_ENTRY;
05424    
05425    SUMA_LH("Called");
05426    
05427    SO = (SUMA_SurfaceObject *)data;
05428 
05429    /* change the value of the dimfact */
05430    SO->SurfCont->curColPlane->DimFact = SO->SurfCont->ColPlaneDimFact->value; 
05431    if (SO->SurfCont->curColPlane->OptScl) 
05432       SO->SurfCont->curColPlane->OptScl->BrightFact = SO->SurfCont->curColPlane->DimFact;
05433       
05434    if (LocalHead) fprintf(SUMA_STDERR,"%s: DimFact of %s set to %f.\n", 
05435          FuncName, SO->SurfCont->curColPlane->Name, SO->SurfCont->curColPlane->DimFact);
05436    
05437    SUMA_UpdateColPlaneShellAsNeeded(SO); /* update other open ColPlaneShells */
05438 
05439    /* need to colorize plane */
05440    SUMA_ColorizePlane(SO->SurfCont->curColPlane);
05441    
05442    /* a good remix and redisplay */
05443    SUMA_RemixRedisplay (SO);
05444    
05445    /* update color label */
05446    SUMA_UpdateNodeLblField(SO);
05447    
05448    SUMA_RETURNe;
05449 }
05450 /*!
05451    \brief Function to set the color remix flag for surface SO and call a redisplay for relevant viewers 
05452 */
05453 SUMA_Boolean SUMA_RemixRedisplay (SUMA_SurfaceObject *SO)
05454 {
05455    static char FuncName[]={"SUMA_RemixRedisplay"};
05456    DList *list=NULL;
05457    SUMA_Boolean LocalHead = NOPE;
05458    
05459    SUMA_ENTRY;
05460    
05461    SUMA_LH("Called");
05462    /* remix colors for all viewers displaying related surfaces */
05463    if (!SUMA_SetRemixFlag(SO->idcode_str, SUMAg_SVv, SUMAg_N_SVv)) {
05464       SUMA_SLP_Err("Failed in SUMA_SetRemixFlag.\n");
05465       SUMA_RETURN(NOPE);
05466    }
05467 
05468    /* redisplay */
05469    if (!list) list = SUMA_CreateList ();
05470    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_RedisplayNow_AllVisible, SES_Suma, NULL); 
05471    if (!SUMA_Engine(&list)) {
05472       SUMA_SLP_Err("Failed to redisplay.");
05473       SUMA_RETURN(NOPE);
05474    }
05475    
05476    SUMA_RETURN(YUP);
05477 }
05478 
05479 /*!
05480    \brief callback to deal with show/hide colorplane toggle
05481    
05482    -expects SO in data
05483 */
05484 void SUMA_cb_ColPlaneShow_toggled (Widget w, XtPointer data, XtPointer client_data)
05485 {
05486    static char FuncName[]={"SUMA_cb_ColPlaneShow_toggled"};
05487    SUMA_SurfaceObject *SO = NULL;
05488    SUMA_Boolean LocalHead = NOPE;
05489    
05490    SUMA_ENTRY;
05491    
05492    SUMA_LH("Called");
05493    
05494    SO = (SUMA_SurfaceObject *)data;
05495    
05496    if (!SO->SurfCont->curColPlane) SUMA_RETURNe;
05497 
05498    SO->SurfCont->curColPlane->Show = XmToggleButtonGetState (SO->SurfCont->ColPlaneShow_tb);
05499    /* set the duplicate button next to int */
05500    XmToggleButtonSetState (SO->SurfCont->Int_tb, SO->SurfCont->curColPlane->Show, NOPE);
05501    
05502    SUMA_UpdateColPlaneShellAsNeeded(SO); /* update other open ColPlaneShells */
05503 
05504    SUMA_RemixRedisplay(SO);
05505    SUMA_UpdateNodeLblField(SO);
05506    
05507    SUMA_RETURNe;
05508 }
05509 
05510 /*!
05511    \brief callback to deal with show only one colorplane toggle
05512    
05513    -expects SO in data
05514 */
05515 void SUMA_cb_ColPlaneShowOne_toggled (Widget w, XtPointer data, XtPointer client_data)
05516 {
05517    static char FuncName[]={"SUMA_cb_ColPlaneShowOne_toggled"};
05518    SUMA_SurfaceObject *SO = NULL;
05519    SUMA_Boolean LocalHead = NOPE;
05520    
05521    SUMA_ENTRY;
05522    
05523    SUMA_LH("Called");
05524    
05525    SO = (SUMA_SurfaceObject *)data;
05526    
05527    if (!SO->SurfCont->curColPlane) SUMA_RETURNe;
05528 
05529    SO->SurfCont->ShowCurOnly = XmToggleButtonGetState (SO->SurfCont->ColPlaneShowOne_tb);
05530    
05531    SUMA_UpdateColPlaneShellAsNeeded(SO); /* update other open ColPlaneShells */
05532 
05533    SUMA_RemixRedisplay(SO);
05534    SUMA_UpdateNodeLblField(SO);
05535    
05536    SUMA_RETURNe;
05537 }
05538 /*!
05539  \brief Function based on arrow_time.c program from Motif Programing Manual
05540  
05541  change_value is called each time the timer expires.  This function
05542  * is also used to initiate the timer.  The "id" represents that timer
05543  * ID returned from the last call to XtAppAddTimeOut().  If id == 1,
05544  * the function was called from start_stop(), not a timeout.  If the value 
05545  * has reached its maximum or minimum, don't restart timer, just return.
05546  * If id == 1, this is the first timeout so make it be longer to allow
05547  * the user to release the button and avoid getting into the "speedy"
05548  * part of the timeouts.
05549  */
05550 void SUMA_ATF_change_value(XtPointer client_data, XtIntervalId *id)
05551 {
05552    static char FuncName[]={"SUMA_ATF_change_value"};
05553    float ArrowTolerance = 0.0001; /* roundoff and truncation headaches ... */
05554    int incr;
05555    SUMA_ARROW_TEXT_FIELD * AF= NULL;
05556    SUMA_Boolean LocalHead = NOPE;
05557    
05558    SUMA_ENTRY;
05559    
05560    AF = (SUMA_ARROW_TEXT_FIELD *)client_data;
05561    
05562    if (!AF->wrap) {
05563       if (AF->value + AF->direction * AF->step > (AF->max + ArrowTolerance) ||
05564         AF->value + AF->direction * AF->step < (AF->min - ArrowTolerance) ) {
05565            SUMA_RETURNe;
05566       }
05567    }
05568    
05569    AF->value += AF->direction * AF->step;
05570    
05571    if (AF->wrap) SUMA_WRAP_VALUE(AF->value, AF->min, AF->max);
05572    
05573    /* round to the tolerance */
05574    if (LocalHead) fprintf (SUMA_STDERR, "%s: Pre Tolerance %f\n", FuncName, AF->value);
05575    /* if no negs allowed, take absolute value. Round off errors can cause AF->value to show -0.00000001 or something ugly like that*/
05576    if (AF->min >= 0.0 && AF->value < 0.0) AF->value = 0.0;
05577    if (LocalHead) fprintf (SUMA_STDERR, "%s: Post Tolerance %f\n", FuncName, AF->value);
05578 
05579    SUMA_ATF_SetString (AF);
05580 
05581    AF->arrow_timer_id =
05582      XtAppAddTimeOut (SUMAg_CF->X->App, (int)id==1? 500 : 100, SUMA_ATF_change_value, (XtPointer)AF);
05583    
05584    /* turn off the modified field because it should only be on when the user edits the field */
05585    SUMA_RETURNe;
05586 }
05587 
05588 /*!
05589    \brief updates string based on ROI value in the Arrowfield 
05590 */
05591 void SUMA_ATF_SetString (SUMA_ARROW_TEXT_FIELD * AF)
05592 {
05593    static char FuncName[]={"SUMA_ATF_SetString"};
05594    char buf[36];
05595    
05596    SUMA_ENTRY;
05597    
05598    if (AF->type == SUMA_int) {
05599       sprintf (buf, "%-4d", (int)AF->value);
05600    }else if (AF->type == SUMA_float) {
05601       sprintf (buf, "%-4.4f", AF->value);
05602    }else {
05603       /* fair enough, must be stringy */
05604    }
05605    XtVaSetValues (AF->textfield, XmNvalue, buf, NULL);
05606    
05607    SUMA_RETURNe;
05608 }
05609 
05610 /*!
05611    \brief sets the value of Arrowfield based on string
05612 */
05613 void SUMA_ATF_SetValue (SUMA_ARROW_TEXT_FIELD * AF)
05614 {
05615    static char FuncName[]={"SUMA_ATF_SetValue"};
05616    float val;
05617    void *n;
05618    SUMA_Boolean LocalHead = NOPE;
05619    
05620    SUMA_ENTRY;
05621    
05622   
05623    XtVaGetValues (AF->textfield, XmNvalue, &n, NULL);
05624    /* YOU DO NOT WANT TO FREE n because n is not a copy of the string in the widget! */
05625    
05626    if (LocalHead) fprintf (SUMA_STDERR, "%s: Read %s\n", FuncName, (char *)n);
05627    
05628    val = strtod ((char *)n, NULL);
05629    if (errno) {
05630       /* bad syntax, reset value*/
05631       if (LocalHead) fprintf (SUMA_STDERR, "%s: Bad syntax.\n", FuncName);
05632       SUMA_RegisterMessage (SUMAg_CF->MessageList, "Bad value in text field", FuncName, SMT_Error, SMA_Log);
05633       SUMA_ATF_SetString (AF);
05634    }else { 
05635       if (AF->type == SUMA_int) {
05636          AF->value = (int)val;    
05637          if (AF->wrap) {
05638             SUMA_WRAP_VALUE(AF->value, AF->min, AF->max);
05639          } else {
05640             SUMA_CLIP_VALUE(AF->value, AF->min, AF->max);
05641          }
05642 
05643          /* now call set string just to be sure users did not enter floats */
05644          SUMA_ATF_SetString (AF);
05645       } else {
05646          AF->value = val;
05647          if (AF->wrap) {
05648             SUMA_WRAP_VALUE(AF->value, AF->min, AF->max);
05649          } else {
05650             SUMA_CLIP_VALUE(AF->value, AF->min, AF->max);
05651          }
05652          /* It is still nice to call SetString because it puts the cursor at the beginning of the field */
05653          SUMA_ATF_SetString (AF);
05654          
05655       }
05656    }
05657    
05658    SUMA_RETURNe;
05659 }
05660 
05661 /*!
05662    \brief Callback for Group button
05663    -Expects sv in data
05664 */
05665 void SUMA_cb_ViewerCont_SwitchGroup (Widget w, XtPointer data, XtPointer call_data)
05666 {
05667    static char FuncName[]={"SUMA_cb_ViewerCont_SwitchGroup"};
05668    SUMA_SurfaceViewer *sv=NULL;
05669    SUMA_LIST_WIDGET *LW = NULL;
05670    SUMA_Boolean LocalHead = NOPE;
05671    
05672    SUMA_ENTRY;
05673    
05674    sv = (SUMA_SurfaceViewer *)data;
05675    
05676    LW = sv->X->ViewCont->SwitchGrouplst;
05677    
05678    if (LW->ALS) {
05679       /* free that old hag */
05680       if (LocalHead) SUMA_S_Err("Freeing the hag.");
05681       LW->ALS = SUMA_FreeAssembleListStruct(LW->ALS);
05682    }
05683    
05684    /* assemble the ROI list */
05685    LW->ALS = SUMA_AssembleGroupList (sv);
05686   
05687    if (!LW->ALS) {
05688       SUMA_SLP_Err("Error assembling list.");
05689       SUMA_RETURNe;
05690    }
05691    
05692    if (LW->ALS->N_clist < 0) {
05693       SUMA_SL_Err("Failed in SUMA_AssembleGroupList");
05694       SUMA_RETURNe;
05695    }
05696    
05697    if (!LW->ALS->N_clist) {
05698       SUMA_SLP_Note ("No Groups to choose from.");
05699       SUMA_RETURNe;
05700    }
05701    
05702    SUMA_CreateScrolledList ( LW->ALS->clist, LW->ALS->N_clist, NOPE,
05703                              LW);
05704                              
05705    SUMA_RETURNe;
05706 }
05707 /*!
05708    \brief Callback for Group button
05709    -Expects sv in data
05710 */
05711 void SUMA_cb_ViewerCont_SwitchState (Widget w, XtPointer data, XtPointer call_data)
05712 {
05713    static char FuncName[]={"SUMA_cb_ViewerCont_SwitchState"};
05714    SUMA_SurfaceViewer *sv=NULL;
05715    SUMA_Boolean LocalHead = NOPE;
05716    
05717    SUMA_ENTRY;
05718    
05719    sv = (SUMA_SurfaceViewer *)data;
05720    
05721    SUMA_SLP_Warn( "Not implemented yet.\n"
05722                   "Use ',' and '.' keys\n");
05723                   
05724    SUMA_RETURNe;
05725 }
05726 
05727 /*!
05728    \brief Callback for Switch Col Plane button
05729    -Expects SO in data
05730 */
05731 void SUMA_cb_SurfCont_SwitchColPlane (Widget w, XtPointer data, XtPointer call_data)
05732 {
05733    static char FuncName[]={"SUMA_cb_SurfCont_SwitchColPlane"};
05734    SUMA_Boolean LocalHead = NOPE;
05735    SUMA_SurfaceObject *SO = NULL;
05736    
05737    SUMA_ENTRY;
05738    
05739    SUMA_LH("Called");
05740    SO = (SUMA_SurfaceObject *)data;
05741    
05742    SUMA_RefreshDsetList (SO);
05743                                                    
05744    SUMA_RETURNe;
05745 }
05746 /*!
05747    \brief Callback for Switch ROI button 
05748    
05749    -Expects LW in data
05750 */
05751 void SUMA_cb_DrawROI_SwitchROI (Widget w, XtPointer data, XtPointer call_data)
05752 {
05753    static char FuncName[]={"SUMA_cb_DrawROI_SwitchROI"};
05754    SUMA_Boolean LocalHead = NOPE;
05755    SUMA_LIST_WIDGET *LW = NULL;
05756    
05757    SUMA_ENTRY;
05758    
05759    LW = (SUMA_LIST_WIDGET *)data;
05760    
05761    if (LW->ALS) {
05762       /* free that old hag */
05763       if (LocalHead) SUMA_S_Err("Freeing the hag.");
05764       LW->ALS = SUMA_FreeAssembleListStruct(LW->ALS);
05765    }
05766    /* assemble the ROI list */
05767    LW->ALS = SUMA_AssembleAllROIList (SUMAg_DOv, SUMAg_N_DOv, YUP);
05768   
05769    if (!LW->ALS) {
05770       SUMA_SLP_Err("Error assembling list.");
05771       SUMA_RETURNe;
05772    }
05773    
05774    if (LW->ALS->N_clist < 0) {
05775       SUMA_SL_Err("Failed in SUMA_AssembleAllROIList");
05776       SUMA_RETURNe;
05777    }
05778    
05779    if (!LW->ALS->N_clist) {
05780       SUMA_SLP_Note ("No ROIs to choose from.");
05781       SUMA_RETURNe;
05782    }
05783    SUMA_CreateScrolledList ( LW->ALS->clist, LW->ALS->N_clist, NOPE,
05784                              LW);
05785                                                 
05786    SUMA_RETURNe;
05787 }
05788 
05789 /*!
05790    \brief Toggles the draw ROI mode
05791 */
05792 void SUMA_cb_DrawROImode_toggled (Widget w, XtPointer data, XtPointer call_data)
05793 {
05794    static char FuncName[] = {"SUMA_cb_DrawROImode_toggled"};
05795    
05796    SUMA_ENTRY;
05797    
05798    SUMAg_CF->ROI_mode = !SUMAg_CF->ROI_mode;
05799    
05800    /* take care of sensitivity of Pen button */
05801    if (!SUMAg_CF->ROI_mode) XtSetSensitive (SUMAg_CF->X->DrawROI->Penmode_tb, 0);
05802    else XtSetSensitive (SUMAg_CF->X->DrawROI->Penmode_tb, 1);
05803 
05804    SUMA_UpdateAllViewerCursor();
05805    
05806    SUMA_RETURNe;
05807 
05808 }
05809 
05810 /*!
05811    \brief Toggles the pen mode
05812 */
05813 
05814 void SUMA_cb_DrawROIPen_toggled (Widget w, XtPointer data, XtPointer call_data)
05815 {
05816    static char FuncName[] = {"SUMA_cb_DrawROIPen_toggled"};
05817    
05818    SUMA_ENTRY;
05819    
05820    SUMAg_CF->Pen_mode = !SUMAg_CF->Pen_mode;
05821    
05822    SUMA_UpdateAllViewerCursor();
05823    
05824    SUMA_RETURNe;
05825 
05826 }
05827 
05828 
05829 /*!
05830    \brief Toggles the Afni link mode
05831 */
05832 void SUMA_cb_AfniLink_toggled (Widget w, XtPointer data, XtPointer call_data)
05833 {
05834    static char FuncName[] = {"SUMA_cb_AfniLink_toggled"};
05835    DList *list=NULL;
05836    SUMA_STANDARD_CMAP cmap;
05837    SUMA_EngineData *ED = NULL;
05838    SUMA_Boolean LocalHead = NOPE;
05839    
05840    SUMA_ENTRY;
05841    
05842    SUMAg_CF->ROI2afni = !SUMAg_CF->ROI2afni;
05843    
05844    /* make sure that is OK */
05845    if (SUMAg_CF->ROI2afni && !SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
05846       SUMAg_CF->ROI2afni = NOPE;
05847       
05848       SUMA_SLP_Err(  "Cannot link to Afni.\n"
05849                      "No connection found.");
05850       XmToggleButtonSetState (SUMAg_CF->X->DrawROI->AfniLink_tb, SUMAg_CF->ROI2afni, NOPE);
05851    }
05852    
05853    if (SUMAg_CF->ROI2afni) {
05854       if (SUMAg_CF->ROI_CM) {
05855          if (LocalHead) fprintf (SUMA_STDERR,"%s: Sending cmap (%s)\n",
05856             FuncName,  SUMAg_CF->ROI_CM->Name);
05857             SUMA_LH("Sending colormap to afni ...");
05858          /* send the color map for ROI to afni */
05859          cmap = SUMA_StandardMapCode (SUMAg_CF->ROI_CM->Name);
05860          if (LocalHead) fprintf (SUMA_STDERR,"%s: Sending cmap %d (%s)\n",
05861             FuncName, cmap, SUMAg_CF->ROI_CM->Name);
05862          list = SUMA_CreateList();
05863          ED = SUMA_InitializeEngineListData (SE_SendColorMapToAfni);
05864          if (!SUMA_RegisterEngineListCommand (  list, ED, 
05865                                                 SEF_i, (void*)&cmap, 
05866                                                 SES_SumaWidget, NULL, NOPE, 
05867                                                 SEI_Head, NULL )) {
05868             fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
05869             SUMA_RETURNe;
05870          }
05871          SUMA_LH("NOW!");
05872          if (!SUMA_Engine (&list)) {
05873             fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
05874          }   
05875       }
05876    }
05877    SUMA_RETURNe;
05878 
05879 }
05880 
05881 
05882 
05883 /*! 
05884    \brief handles a selection from switch ColPlane 
05885    
05886    -expect SO in data
05887 */
05888 void SUMA_cb_SelectSwitchColPlane(Widget w, XtPointer data, XtPointer call_data)
05889 {
05890    static char FuncName[] = {"SUMA_cb_SelectSwitchColPlane"};
05891    SUMA_LIST_WIDGET *LW = NULL;
05892    XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
05893    char *choice=NULL, *choice_trimmed=NULL;
05894    SUMA_Boolean CloseShop = NOPE, Found = NOPE;
05895    int ichoice = -1;
05896    SUMA_OVERLAYS *ColPlane = NULL;
05897    SUMA_SurfaceObject *SO = NULL;
05898    SUMA_Boolean LocalHead=NOPE;
05899    
05900    SUMA_ENTRY;
05901    
05902    SO = (SUMA_SurfaceObject *)data;
05903    LW = SO->SurfCont->SwitchDsetlst;
05904    
05905    if (!LW) {
05906       SUMA_S_Err("NULL LW!");
05907       SUMA_RETURNe;
05908    }
05909    
05910    
05911    if (cbs->reason == XmCR_SINGLE_SELECT) {
05912       if (LocalHead) fprintf (SUMA_STDERR,"%s: Single selection, list widget %s... \n", FuncName, LW->Label);
05913    } else {
05914       if (LocalHead) fprintf (SUMA_STDERR,"%s: Default selection, list widget %s... \n", FuncName, LW->Label);
05915       /*double click or enter on that one, close shop after selection */
05916       CloseShop = YUP;
05917    }
05918 
05919    XmStringGetLtoR (cbs->item, XmFONTLIST_DEFAULT_TAG, &choice);
05920    
05921    if (LocalHead) fprintf (SUMA_STDERR,"%s: Selected item: %s {%s} (%d)\n", FuncName, choice, choice, cbs->item_position);
05922    /* because of sorting, choice cannot be used as an index into clist and oplist in ALS */
05923    Found = NOPE;
05924    ichoice = 0;
05925    do {
05926       if (LocalHead) fprintf (SUMA_STDERR,"%s: Comparing:\n%s\n%s", FuncName, LW->ALS->clist[ichoice], choice);
05927       if (strncmp(LW->ALS->clist[ichoice], choice, strlen(LW->ALS->clist[ichoice])) == 0) Found = YUP; 
05928       else ++ichoice;
05929    } while (ichoice < LW->ALS->N_clist && !Found);
05930    
05931    if (!Found) {
05932       SUMA_SLP_Err("Choice not found.");
05933       SUMA_RETURNe;
05934    }
05935    
05936    XtFree (choice);
05937    
05938    /* now retrieve that choice from the SUMA_ASSEMBLE_LIST_STRUCT structure and initialize the drawing window */
05939    if (LW->ALS) {
05940       if (LocalHead) fprintf (SUMA_STDERR,"%s: N_clist = %d\n", FuncName, LW->ALS->N_clist); 
05941       if (LW->ALS->N_clist > ichoice) {
05942          ColPlane = (SUMA_OVERLAYS *)LW->ALS->oplist[ichoice];
05943          if (LocalHead) fprintf (SUMA_STDERR,"%s: Retrieved ColPlane named %s\n", FuncName, ColPlane->Name);
05944          SUMA_InitializeColPlaneShell(SO, ColPlane);
05945          SUMA_UpdateColPlaneShellAsNeeded(SO); /* update other open ColPlaneShells */
05946          /* If you're viewing one plane at a time, do a remix */
05947          if (SO->SurfCont->ShowCurOnly) SUMA_RemixRedisplay(SO);
05948 
05949       }
05950    } else {
05951       if (LocalHead) fprintf (SUMA_STDERR,"%s: NULL ALS\n", FuncName); 
05952    }
05953 
05954    if (CloseShop) {
05955       SUMA_cb_CloseSwitchColPlane( w,  (XtPointer)SO->SurfCont->SwitchDsetlst,  call_data);
05956    }  
05957    
05958 
05959    SUMA_RETURNe;
05960 }
05961 
05962 /*!
05963    \brief Closes the DrawROI window 
05964    
05965    -expects SUMA_LIST_WIDGET * in client_data
05966 */
05967 void SUMA_cb_CloseSwitchColPlane(Widget w, XtPointer data, XtPointer call_data)
05968 {
05969    static char FuncName[] = {"SUMA_cb_CloseSwitchColPlane"};
05970    SUMA_Boolean LocalHead = NOPE;
05971    SUMA_LIST_WIDGET *LW = NULL;
05972    
05973    SUMA_ENTRY;
05974 
05975    LW = (SUMA_LIST_WIDGET *)data;
05976    
05977    #if defined SUMA_USE_WITHDRAW 
05978       if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing list widget %s...\n", FuncName, LW->Label);
05979       
05980       XWithdrawWindow(SUMAg_CF->X->DPY_controller1, 
05981          XtWindow(LW->toplevel),
05982          XScreenNumberOfScreen(XtScreen(LW->toplevel)));
05983    #elif defined SUMA_USE_DESTROY 
05984          if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying list widget %s...\n", FuncName, LW->Label);
05985          XtDestroyWidget(LW->toplevel);
05986          LW->toplevel = NULL;
05987    #endif
05988    
05989    LW->isShaded = YUP; 
05990 
05991    SUMA_RETURNe;
05992 }
05993 
05994 /*!
05995    \brief default selection action, handles single selection mode
05996    - expects sv in data
05997 */
05998 void SUMA_cb_SelectSwitchGroup(Widget w, XtPointer data, XtPointer call_data)
05999 {
06000    static char FuncName[] = {"SUMA_cb_SelectSwitchGroup"};
06001    SUMA_LIST_WIDGET *LW = NULL;
06002    XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
06003    char *choice=NULL;
06004    SUMA_Boolean CloseShop = NOPE, Found = NOPE;
06005    int ichoice = -1;
06006    char *strn=NULL;
06007    SUMA_SurfaceViewer *sv=NULL;
06008    SUMA_Boolean LocalHead = NOPE;
06009  
06010    SUMA_ENTRY;
06011    
06012    sv = (SUMA_SurfaceViewer *)data;
06013    
06014    LW = sv->X->ViewCont->SwitchGrouplst;
06015    
06016    if (!LW) {
06017       SUMA_S_Err("NULL LW!");
06018       SUMA_RETURNe;
06019    }
06020    if (cbs->reason == XmCR_SINGLE_SELECT) {
06021       if (LocalHead) fprintf (SUMA_STDERR,"%s: Single selection, list widget %s... \n", FuncName, LW->Label);
06022    } else {
06023       if (LocalHead) fprintf (SUMA_STDERR,"%s: Default selection, list widget %s... \n", FuncName, LW->Label);
06024       /*double click or enter on that one, close shop after selection */
06025       CloseShop = YUP;
06026    }
06027    
06028    XmStringGetLtoR (cbs->item, XmFONTLIST_DEFAULT_TAG, &choice);
06029    if (LocalHead) fprintf (SUMA_STDERR,"%s: Selected item: %s (%d)\n", FuncName, choice, cbs->item_position);
06030  
06031    /* because of sorting, choice cannot be used as an index into clist and oplist in ALS */
06032    Found = NOPE;
06033    ichoice = 0;
06034    do {
06035       if (LocalHead) fprintf (SUMA_STDERR,"%s: Comparing:\n%s\n%s", FuncName, LW->ALS->clist[ichoice], choice);
06036       if (strncmp(LW->ALS->clist[ichoice], choice, strlen(LW->ALS->clist[ichoice])) == 0) Found = YUP; 
06037       else ++ichoice;
06038    } while (ichoice < LW->ALS->N_clist && !Found);
06039    
06040    if (!Found) {
06041       SUMA_SLP_Err("Choice not found.");
06042       SUMA_RETURNe;
06043    }
06044    
06045    XtFree (choice);
06046 
06047    /* now retrieve that choice from the SUMA_ASSEMBLE_LIST_STRUCT structure and initialize the drawing window */
06048    if (LW->ALS) {
06049       if (LocalHead) fprintf (SUMA_STDERR,"%s: N_clist = %d\n", FuncName, LW->ALS->N_clist); 
06050       if (LW->ALS->N_clist > ichoice) {
06051          strn = (char *)LW->ALS->clist[ichoice];
06052          if (LocalHead) fprintf (SUMA_STDERR,"%s: Retrieved group labeled %s\n", FuncName, strn);
06053          /* Now we know what group the user wants so go switch groups */
06054          if (!SUMA_SwitchGroups(sv, strn)) { 
06055             SUMA_SLP_Err("Failed to switch groups");
06056          }
06057       }
06058    } else {
06059       if (LocalHead) fprintf (SUMA_STDERR,"%s: NULL ALS\n", FuncName); 
06060    }
06061 
06062    /* Now make the viewer switch group */
06063    
06064    if (CloseShop) {
06065       SUMA_LH("Closing Shop");
06066       SUMA_cb_CloseSwitchGroup( w,  data,  call_data);
06067    }  
06068    
06069    SUMA_RETURNe;
06070 }
06071 
06072 /*!
06073    \brief Closes the SwitchGroup window 
06074    
06075    -expects sv in client_data
06076 */
06077 void SUMA_cb_CloseSwitchGroup(Widget w, XtPointer data, XtPointer call_data)
06078 {
06079    static char FuncName[] = {"SUMA_cb_CloseSwitchGroup"};
06080    SUMA_LIST_WIDGET *LW = NULL;
06081    SUMA_SurfaceViewer *sv=NULL;
06082    SUMA_Boolean LocalHead = NOPE;
06083    
06084    SUMA_ENTRY;
06085 
06086    sv = (SUMA_SurfaceViewer *)data;
06087    
06088    LW = sv->X->ViewCont->SwitchGrouplst;
06089    
06090    #if defined SUMA_USE_WITHDRAW 
06091       if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing list widget %s...\n", FuncName, LW->Label);
06092       
06093       XWithdrawWindow(SUMAg_CF->X->DPY_controller1, 
06094          XtWindow(LW->toplevel),
06095          XScreenNumberOfScreen(XtScreen(LW->toplevel)));
06096    #elif defined SUMA_USE_DESTROY 
06097          if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying list widget %s...\n", FuncName, LW->Label);
06098          XtDestroyWidget(LW->toplevel);
06099          LW->toplevel = NULL;
06100    #endif
06101    
06102    LW->isShaded = YUP; 
06103 
06104    SUMA_RETURNe;
06105 }
06106 
06107 /*!
06108    \brief default selection action, handles single selection mode
06109    
06110    -code snipets from Motif Programming Manual
06111 */
06112 void SUMA_cb_SelectSwitchROI(Widget w, XtPointer data, XtPointer call_data)
06113 {
06114    static char FuncName[] = {"SUMA_cb_SelectSwitchROI"};
06115    SUMA_LIST_WIDGET *LW = NULL;
06116    XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
06117    char *choice=NULL;
06118    SUMA_Boolean CloseShop = NOPE, Found = NOPE;
06119    int ichoice = -1;
06120    SUMA_DRAWN_ROI *DrawnROI = NULL;
06121    SUMA_Boolean LocalHead = NOPE;
06122    
06123    SUMA_ENTRY; 
06124    
06125    LW = (SUMA_LIST_WIDGET *)data;
06126    
06127    if (!LW) {
06128       SUMA_S_Err("NULL LW!");
06129       SUMA_RETURNe;
06130    }
06131    
06132    if (cbs->reason == XmCR_SINGLE_SELECT) {
06133       if (LocalHead) fprintf (SUMA_STDERR,"%s: Single selection, list widget %s... \n", FuncName, LW->Label);
06134    } else {
06135       if (LocalHead) fprintf (SUMA_STDERR,"%s: Default selection, list widget %s... \n", FuncName, LW->Label);
06136       /*double click or enter on that one, close shop after selection */
06137       CloseShop = YUP;
06138    }
06139 
06140    XmStringGetLtoR (cbs->item, XmFONTLIST_DEFAULT_TAG, &choice);
06141    if (LocalHead) fprintf (SUMA_STDERR,"%s: Selected item: %s (%d)\n", FuncName, choice, cbs->item_position);
06142  
06143    /* because of sorting, choice cannot be used as an index into clist and oplist in ALS */
06144    Found = NOPE;
06145    ichoice = 0;
06146    do {
06147       if (LocalHead) fprintf (SUMA_STDERR,"%s: Comparing:\n%s\n%s", FuncName, LW->ALS->clist[ichoice], choice);
06148       if (strncmp(LW->ALS->clist[ichoice], choice, strlen(LW->ALS->clist[ichoice])) == 0) Found = YUP; 
06149       else ++ichoice;
06150    } while (ichoice < LW->ALS->N_clist && !Found);
06151    
06152    if (!Found) {
06153       SUMA_SLP_Err("Choice not found.");
06154       SUMA_RETURNe;
06155    }
06156    
06157    XtFree (choice);
06158 
06159    /* now retrieve that choice from the SUMA_ASSEMBLE_LIST_STRUCT structure and initialize the drawing window */
06160    if (LW->ALS) {
06161       if (LocalHead) fprintf (SUMA_STDERR,"%s: N_clist = %d\n", FuncName, LW->ALS->N_clist); 
06162       if (LW->ALS->N_clist > ichoice) {
06163          DrawnROI = (SUMA_DRAWN_ROI *)LW->ALS->oplist[ichoice];
06164          if (LocalHead) fprintf (SUMA_STDERR,"%s: Retrieved DrawnROI labeled %s\n", FuncName, DrawnROI->Label);
06165          SUMA_InitializeDrawROIWindow(DrawnROI);
06166       }
06167    } else {
06168       if (LocalHead) fprintf (SUMA_STDERR,"%s: NULL ALS\n", FuncName); 
06169    }
06170 
06171    if (CloseShop) {
06172       SUMA_cb_CloseSwitchROI( w,  data,  call_data);
06173    }  
06174    
06175    SUMA_RETURNe;
06176 }
06177 
06178 /*!
06179    \brief Closes the SwitchROI window 
06180    
06181    -expects SUMA_LIST_WIDGET * in client_data
06182 */
06183 void SUMA_cb_CloseSwitchROI(Widget w, XtPointer data, XtPointer call_data)
06184 {
06185    static char FuncName[] = {"SUMA_cb_CloseSwitchROI"};
06186    SUMA_Boolean LocalHead = NOPE;
06187    SUMA_LIST_WIDGET *LW = NULL;
06188    
06189    SUMA_ENTRY;
06190 
06191    LW = (SUMA_LIST_WIDGET *)data;
06192    
06193    #if defined SUMA_USE_WITHDRAW 
06194       if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing list widget %s...\n", FuncName, LW->Label);
06195       
06196       XWithdrawWindow(SUMAg_CF->X->DPY_controller1, 
06197          XtWindow(LW->toplevel),
06198          XScreenNumberOfScreen(XtScreen(LW->toplevel)));
06199    #elif defined SUMA_USE_DESTROY 
06200          if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying list widget %s...\n", FuncName, LW->Label);
06201          XtDestroyWidget(LW->toplevel);
06202          LW->toplevel = NULL;
06203    #endif
06204    
06205    LW->isShaded = YUP; 
06206 
06207    SUMA_RETURNe;
06208 }
06209 /*!
06210    \brief Closes the DrawROI window
06211 */
06212 void SUMA_cb_CloseDrawROIWindow(Widget w, XtPointer data, XtPointer call_data)
06213 {
06214    static char FuncName[] = {"SUMA_cb_CloseDrawROIWindow"};
06215    SUMA_Boolean Shaded = NOPE, LocalHead = NOPE;
06216    
06217    SUMA_ENTRY;
06218    
06219    if (!SUMAg_CF->X->DrawROI->AppShell) SUMA_RETURNe;
06220    
06221    /* if the ROI selection list is open, close it */
06222    /* Close the ROIlist window if it is open */
06223    SUMA_IS_DRAW_ROI_SWITCH_ROI_SHADED(Shaded);
06224    if (!Shaded) {
06225       if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing switch ROI window ...\n", FuncName);
06226       SUMA_cb_CloseSwitchROI(NULL, (XtPointer) SUMAg_CF->X->DrawROI->SwitchROIlst, NULL);
06227    }
06228    
06229    #if defined SUMA_USE_WITHDRAW 
06230       if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing DrawROI window...\n", FuncName);
06231       
06232       XWithdrawWindow(SUMAg_CF->X->DPY_controller1, 
06233          XtWindow(SUMAg_CF->X->DrawROI->AppShell),
06234          XScreenNumberOfScreen(XtScreen(SUMAg_CF->X->DrawROI->AppShell)));
06235    #elif defined SUMA_USE_DESTROY 
06236       if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying DrawROI window...\n", FuncName);
06237       XtDestroyWidget(SUMAg_CF->X->DrawROI->AppShell);
06238       SUMAg_CF->X->DrawROI->AppShell = NULL;
06239    #endif
06240    
06241    SUMA_RETURNe;
06242 }
06243 /*!
06244    \brief creates the SUMA controller window. Expects sv  input
06245 */
06246 void SUMA_cb_createSumaCont(Widget w, XtPointer data, XtPointer callData)
06247 {
06248    static char FuncName[] = {"SUMA_cb_createSumaCont"};
06249    Widget rc, pb_close, pb_new, pb_done, pb_bhelp, LockFrame, AppFrame, form, tb, rb, rc_m;
06250    int i;
06251    SUMA_Boolean LocalHead = NOPE;
06252    
06253    SUMA_ENTRY;
06254    
06255    if (SUMAg_CF->X->SumaCont->AppShell) {
06256       fprintf (SUMA_STDERR,"Error %s: SUMAg_CF->X->SumaCont->AppShell!=NULL. Should not be here.\n", FuncName);
06257       SUMA_RETURNe;
06258    }
06259 
06260    /* create as a separate application shell, you do not want a parent to this controller that
06261    can be closed or withdrawn temporarily */
06262    SUMAg_CF->X->SumaCont->AppShell = XtVaAppCreateShell("Suma Controller" , "Suma" ,
06263       topLevelShellWidgetClass , SUMAg_CF->X->DPY_controller1 ,
06264       NULL ) ;
06265    
06266   
06267    /* turn off default delete response. If you do not do that, you will suffer.*/
06268    XtVaSetValues( SUMAg_CF->X->SumaCont->AppShell,
06269            XmNdeleteResponse, XmDO_NOTHING,
06270            NULL);  
06271              
06272    /* handle the close button from window manager */
06273    XmAddWMProtocolCallback(/* make "Close" window menu work */
06274       SUMAg_CF->X->SumaCont->AppShell,
06275       XmInternAtom( SUMAg_CF->X->DPY_controller1 , "WM_DELETE_WINDOW" , False ) ,
06276       SUMA_cb_closeSumaCont, NULL) ;
06277    
06278    /* create a form widget, manage it at the end ...*/
06279    form = XtVaCreateWidget ("dialog", 
06280       xmFormWidgetClass, SUMAg_CF->X->SumaCont->AppShell,
06281       XmNborderWidth , 0 ,
06282       XmNmarginHeight , SUMA_MARGIN ,
06283       XmNmarginWidth  , SUMA_MARGIN ,
06284       XmNshadowThickness, 2,
06285       XmNshadowType, XmSHADOW_ETCHED_IN,
06286       NULL); 
06287       
06288    /* a LockFrame to put the lockstuff in */
06289    LockFrame = XtVaCreateWidget ("dialog",
06290       xmFrameWidgetClass, form,
06291       XmNleftAttachment , XmATTACH_FORM ,
06292       XmNtopAttachment  , XmATTACH_FORM ,
06293       XmNshadowType , XmSHADOW_ETCHED_IN ,
06294       XmNshadowThickness , 5 ,
06295       XmNtraversalOn , False ,
06296       NULL); 
06297    
06298       /* this one requires Motif 1.2 or newer */
06299       XtVaCreateManagedWidget ("Lock",
06300          xmLabelWidgetClass, LockFrame, 
06301          XmNchildType, XmFRAME_TITLE_CHILD,
06302          XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
06303          NULL);
06304    
06305    /* row column Lock rowcolumns */
06306    rc = XtVaCreateWidget ("rowcolumn",
06307          xmRowColumnWidgetClass, LockFrame,
06308          XmNpacking, XmPACK_TIGHT, 
06309          XmNorientation , XmHORIZONTAL ,
06310          XmNmarginHeight, SUMA_MARGIN ,
06311          XmNmarginWidth , SUMA_MARGIN ,
06312          NULL);
06313 
06314    for (i = 0; i < SUMA_MAX_SURF_VIEWERS; i++) {
06315       char stmp[3];
06316       int tmpfac;
06317       
06318       rc_m = XtVaCreateManagedWidget ("rowcolumn",
06319          xmRowColumnWidgetClass, rc,
06320          XmNpacking, XmPACK_TIGHT, 
06321          XmNorientation , XmVERTICAL ,
06322          NULL);
06323          
06324       sprintf(stmp,"%c", 65+i);
06325       w = XtVaCreateManagedWidget (stmp,
06326          xmLabelWidgetClass, rc_m,
06327          NULL);
06328 
06329       SUMAg_CF->X->SumaCont->Lock_rbg->rb[i] = XtVaCreateWidget("radiobox",
06330          xmRowColumnWidgetClass, rc_m,
06331          XmNorientation , XmVERTICAL ,
06332          XmNpacking,      XmPACK_TIGHT,
06333          XmNradioBehavior, True,
06334          XmNnumColumns,   1,
06335          NULL); 
06336       
06337       tmpfac = SUMAg_CF->X->SumaCont->Lock_rbg->N_but;
06338        
06339       SUMAg_CF->X->SumaCont->Lock_rbg->tb[tmpfac*i] = XtVaCreateManagedWidget("-", 
06340       xmToggleButtonWidgetClass, SUMAg_CF->X->SumaCont->Lock_rbg->rb[i], NULL);
06341       XtAddCallback (SUMAg_CF->X->SumaCont->Lock_rbg->tb[tmpfac*i], 
06342                      XmNvalueChangedCallback, SUMA_cb_XHlock_toggled, 
06343                      (XtPointer)(tmpfac*i));
06344        
06345       SUMAg_CF->X->SumaCont->Lock_rbg->tb[tmpfac*i+1] = XtVaCreateManagedWidget("i", 
06346       xmToggleButtonWidgetClass, SUMAg_CF->X->SumaCont->Lock_rbg->rb[i], NULL);
06347       XtAddCallback (SUMAg_CF->X->SumaCont->Lock_rbg->tb[tmpfac*i+1], 
06348                      XmNvalueChangedCallback, SUMA_cb_XHlock_toggled,  
06349                      (XtPointer)(tmpfac*i+1));
06350       
06351       SUMAg_CF->X->SumaCont->Lock_rbg->tb[tmpfac*i+2] = XtVaCreateManagedWidget("c", 
06352       xmToggleButtonWidgetClass, SUMAg_CF->X->SumaCont->Lock_rbg->rb[i], NULL);
06353       XtAddCallback (SUMAg_CF->X->SumaCont->Lock_rbg->tb[tmpfac*i+2], 
06354                      XmNvalueChangedCallback, SUMA_cb_XHlock_toggled,  
06355                      (XtPointer)(tmpfac*i+2));
06356       
06357       XtManageChild (SUMAg_CF->X->SumaCont->Lock_rbg->rb[i]);
06358       
06359       /* put some help on the radiobox and its children*/
06360       MCW_reghelp_children( SUMAg_CF->X->SumaCont->Lock_rbg->rb[i] , SUMA_LockSumaCont_help );
06361       
06362       /* initialize radio button created */
06363       SUMA_set_Lock_rb (SUMAg_CF->X->SumaCont->Lock_rbg, i, SUMAg_CF->Locked[i]);
06364       
06365       XtVaCreateManagedWidget ("sep", xmSeparatorWidgetClass, rc_m, NULL);
06366       
06367       SUMAg_CF->X->SumaCont->LockView_tbg[i] = XtVaCreateManagedWidget("v", 
06368          xmToggleButtonWidgetClass, rc_m, NULL);
06369       XtAddCallback (SUMAg_CF->X->SumaCont->LockView_tbg[i], XmNvalueChangedCallback, SUMA_cb_XHviewlock_toggled, (XtPointer) i);
06370 
06371       /* put some help on this buton*/
06372       MCW_reghelp_children( rc_m , SUMA_LockViewSumaCont_help );
06373             
06374    }  
06375    XtManageChild (rc);
06376    XtManageChild (LockFrame);
06377       
06378    
06379    /* a vertical separator */
06380    XtVaCreateManagedWidget ("sep", 
06381                            xmSeparatorGadgetClass, rc, 
06382                            XmNorientation, XmVERTICAL,
06383                            NULL);
06384 
06385    /* a radio box for the all buttons */
06386    rc_m = XtVaCreateManagedWidget ("rowcolumn",
06387          xmRowColumnWidgetClass, rc,
06388          XmNpacking, XmPACK_TIGHT, 
06389          XmNorientation , XmVERTICAL ,
06390          NULL);
06391          
06392    w = XtVaCreateManagedWidget ("All",
06393       xmLabelWidgetClass, rc_m,
06394       NULL);
06395 
06396    SUMAg_CF->X->SumaCont->Lock_rbg->arb = XtVaCreateWidget("radiobox",
06397       xmRowColumnWidgetClass, rc_m,
06398       XmNorientation , XmVERTICAL ,
06399       XmNpacking,      XmPACK_TIGHT,
06400       XmNradioBehavior, True,
06401       XmNnumColumns,   1,
06402       NULL);
06403 
06404    SUMAg_CF->X->SumaCont->Lock_rbg->atb[0] = XtVaCreateManagedWidget("-", 
06405    xmToggleButtonWidgetClass, SUMAg_CF->X->SumaCont->Lock_rbg->arb, NULL);
06406    XtAddCallback (SUMAg_CF->X->SumaCont->Lock_rbg->atb[0], 
06407                   XmNvalueChangedCallback, SUMA_cb_XHalock_toggled, 
06408                   (XtPointer)(0));
06409 
06410    SUMAg_CF->X->SumaCont->Lock_rbg->atb[1] = XtVaCreateManagedWidget("i", 
06411    xmToggleButtonWidgetClass, SUMAg_CF->X->SumaCont->Lock_rbg->arb, NULL);
06412    XtAddCallback (SUMAg_CF->X->SumaCont->Lock_rbg->atb[1], 
06413                   XmNvalueChangedCallback, SUMA_cb_XHalock_toggled,  
06414                   (XtPointer)(1));
06415 
06416    SUMAg_CF->X->SumaCont->Lock_rbg->atb[2] = XtVaCreateManagedWidget("c", 
06417    xmToggleButtonWidgetClass, SUMAg_CF->X->SumaCont->Lock_rbg->arb, NULL);
06418    XtAddCallback (SUMAg_CF->X->SumaCont->Lock_rbg->atb[2], 
06419                   XmNvalueChangedCallback, SUMA_cb_XHalock_toggled,  
06420                   (XtPointer)(2));
06421 
06422    XtManageChild (SUMAg_CF->X->SumaCont->Lock_rbg->arb);
06423 
06424    /* put some help on the radiobox and its children*/
06425    MCW_reghelp_children( SUMAg_CF->X->SumaCont->Lock_rbg->arb , SUMA_LockSumaCont_help );
06426 
06427    /* initialize radio button created */
06428    SUMA_set_Lock_arb (SUMAg_CF->X->SumaCont->Lock_rbg);   
06429          
06430    XtVaCreateManagedWidget ("sep", xmSeparatorGadgetClass, rc_m, NULL);
06431       
06432    SUMAg_CF->X->SumaCont->LockAllView_tb = XtVaCreateManagedWidget("v", 
06433       xmToggleButtonWidgetClass, rc_m, NULL);
06434    XtAddCallback (SUMAg_CF->X->SumaCont->LockAllView_tb, XmNvalueChangedCallback, SUMA_cb_XHaviewlock_toggled, NULL);
06435    
06436    /* a frame to put the Close button in */
06437    AppFrame = XtVaCreateWidget ("dialog",
06438       xmFrameWidgetClass, form,
06439       XmNleftAttachment , XmATTACH_FORM ,
06440       XmNtopAttachment  , XmATTACH_WIDGET ,
06441       XmNtopWidget, LockFrame,
06442       XmNshadowType , XmSHADOW_ETCHED_IN ,
06443       XmNshadowThickness , 5 ,
06444       XmNtraversalOn , False ,
06445       NULL); 
06446    
06447    
06448    rc = XtVaCreateManagedWidget ("rowcolumn",
06449          xmRowColumnWidgetClass, AppFrame,
06450          XmNpacking, XmPACK_COLUMN, 
06451          XmNorientation , XmVERTICAL ,
06452          XmNnumColumns, 2, 
06453          NULL);
06454          
06455    pb_new = XtVaCreateWidget ("Viewer", 
06456       xmPushButtonWidgetClass, rc, 
06457       NULL);
06458    XtAddCallback (pb_new, XmNactivateCallback, SUMA_cb_newSumaCont, NULL);
06459    MCW_register_hint( pb_new , "Opens a new viewer" ) ;
06460    MCW_register_help( pb_new , SUMA_viewerSumaCont_help );
06461    XtManageChild (pb_new); 
06462 
06463    pb_close = XtVaCreateWidget ("Close", 
06464       xmPushButtonWidgetClass, rc, 
06465       NULL);   
06466    XtAddCallback (pb_close, XmNactivateCallback, SUMA_cb_closeSumaCont, NULL);
06467    MCW_register_hint( pb_close , "Close SUMA controller" ) ;
06468    MCW_register_help( pb_close , SUMA_closeSumaCont_help ) ;
06469    XtManageChild (pb_close); 
06470    
06471    pb_bhelp = XtVaCreateWidget ("BHelp", 
06472       xmPushButtonWidgetClass, rc, 
06473       NULL);
06474    XtAddCallback (pb_bhelp, XmNactivateCallback, MCW_click_help_CB, NULL);
06475    MCW_register_help(pb_bhelp , SUMA_help_help ) ;
06476    MCW_register_hint(pb_bhelp  , "Press this button then click on a button/label/menu for more help." ) ;
06477    
06478    XtManageChild (pb_bhelp); 
06479    
06480    SUMAg_CF->X->SumaCont->quit_pb = XtVaCreateWidget ("done", 
06481       xmPushButtonWidgetClass, rc, 
06482       NULL);
06483    XtAddCallback (SUMAg_CF->X->SumaCont->quit_pb, XmNactivateCallback, SUMA_cb_doneSumaCont, NULL);
06484    MCW_register_hint( SUMAg_CF->X->SumaCont->quit_pb , "Click twice in 5 seconds to quit application." ) ;
06485    MCW_set_widget_bg( SUMAg_CF->X->SumaCont->quit_pb , MCW_hotcolor(SUMAg_CF->X->SumaCont->quit_pb) , 0 ) ;
06486 
06487    XtManageChild (SUMAg_CF->X->SumaCont->quit_pb); 
06488   
06489    XtManageChild (AppFrame);
06490    
06491    /* manage the remaing widgets */
06492    XtManageChild (form);
06493    
06494    /* realize the widget */
06495    XtRealizeWidget (SUMAg_CF->X->SumaCont->AppShell);
06496    
06497    SUMA_RETURNe;
06498 }
06499 
06500 /*!
06501    \brief Close all viewers and exit SUMA
06502    
06503    based on afni's AFNI_quit_CB
06504 */
06505 
06506 void  SUMA_cb_doneSumaCont(Widget wcall, XtPointer cd1, XtPointer cbs)
06507 {
06508    static char FuncName[] = {"SUMA_cb_doneSumaCont"};
06509    XmPushButtonCallbackStruct * pbcbs = (XmPushButtonCallbackStruct *) cbs ;
06510    SUMA_Boolean LocalHead = NOPE;
06511    
06512    SUMA_ENTRY;
06513 
06514    /* NULL widget --> reset button to lowercase */
06515    if( wcall == NULL ){
06516       if (LocalHead) fprintf (SUMA_STDERR, "%s: Resetting button.\n", FuncName); 
06517       if( SUMAg_CF->X->SumaCont->quit_first == NOPE ){
06518          MCW_set_widget_label( SUMAg_CF->X->SumaCont->quit_pb , "done " ) ;
06519          SUMAg_CF->X->SumaCont->quit_first = YUP ;
06520       }
06521       SUMA_RETURNe ;
06522    }
06523    
06524    /* Press of button with Shift or Control key pressed --> Death Now */
06525    if( pbcbs != NULL                       &&
06526        pbcbs->event != NULL                &&
06527        pbcbs->event->type == ButtonRelease &&
06528        ((XButtonEvent *)(pbcbs->event))->state &  /* note single & here! */
06529        (ShiftMask|ControlMask|Button2Mask|Button3Mask) ){
06530 
06531       if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing display.\n", FuncName); 
06532       XtCloseDisplay( SUMAg_CF->X->DPY_controller1 ) ;
06533       exit(0) ;
06534    }
06535    
06536    /* First press --> just change button label */
06537 
06538    if( SUMAg_CF->X->SumaCont->quit_first ){
06539       MCW_set_widget_label( SUMAg_CF->X->SumaCont->quit_pb , "DONE " ) ;
06540       SUMAg_CF->X->SumaCont->quit_first = NOPE ;
06541 
06542       /* if not re-pressed in 5 seconds, will reset to lowercase */
06543       if (LocalHead) fprintf (SUMA_STDERR, "%s: First Press, adding time out.\n", FuncName);
06544       (void) XtAppAddTimeOut(
06545                XtWidgetToApplicationContext(SUMAg_CF->X->SumaCont->quit_pb) ,
06546                5000 , SUMA_quit_timeout_CB , NULL ) ;
06547 
06548        SUMA_RETURNe;
06549    }
06550    
06551    /* close up */
06552    if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing shop...\n", FuncName);
06553    XtCloseDisplay( SUMAg_CF->X->DPY_controller1 ) ;
06554    exit(0) ;
06555 
06556    SUMA_RETURNe;
06557 }
06558 void SUMA_quit_timeout_CB( XtPointer client_data , XtIntervalId * id )
06559 {
06560    static char FuncName[] = {"SUMA_quit_timeout_CB"};
06561 
06562    SUMA_ENTRY;
06563 
06564    SUMA_cb_doneSumaCont(NULL, NULL, NULL);
06565 
06566    SUMA_RETURNe; 
06567 }
06568 
06569 void SUMA_cb_XHlock_toggled(Widget w, XtPointer client_data, XtPointer callData)
06570 {
06571    static char FuncName[] = {"SUMA_cb_XHlock_toggled"};
06572    SUMA_Boolean LocalHead = NOPE;
06573    int cd, i, j;
06574    
06575    cd = (int) client_data;
06576    
06577    SUMA_ENTRY;
06578 
06579    i = cd / SUMAg_CF->X->SumaCont->Lock_rbg->N_but;
06580    j = cd % SUMAg_CF->X->SumaCont->Lock_rbg->N_but;
06581    fprintf (SUMA_STDERR, "%s: Viewer %c Lock=%d.\n", FuncName, 65+i, j);
06582    SUMAg_CF->Locked[i] = j;
06583    
06584    /* now call the function to set the All lock buttons */
06585    SUMA_set_Lock_arb (SUMAg_CF->X->SumaCont->Lock_rbg);
06586 
06587    SUMA_RETURNe;
06588 }
06589 
06590 void SUMA_cb_XHalock_toggled (Widget w, XtPointer client_data, XtPointer callData)
06591 {
06592    static char FuncName[] = {"SUMA_cb_XHalock_toggled"};
06593    int i;
06594    DList *list=NULL;
06595    SUMA_EngineData *ED = NULL;
06596    
06597    SUMA_ENTRY;
06598  
06599    i = (int) client_data;
06600    
06601 
06602    list = SUMA_CreateList();
06603    ED = SUMA_InitializeEngineListData (SE_SetLockAllCrossHair);
06604    if (!SUMA_RegisterEngineListCommand (  list, ED, 
06605                                           SEF_i, (void*)&i, 
06606                                           SES_SumaWidget, NULL, NOPE, 
06607                                           SEI_Head, NULL )) {
06608       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
06609       SUMA_RETURNe;
06610    }
06611    
06612    if (!SUMA_Engine (&list)) {
06613       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
06614    }
06615                   
06616    SUMA_RETURNe;
06617 }
06618 
06619 void SUMA_cb_XHaviewlock_toggled (Widget w, XtPointer client_data, XtPointer callData)
06620 {
06621    static char FuncName[] = {"SUMA_cb_XHaviewlock_toggled"};
06622    DList *list=NULL;
06623    SUMA_EngineData *ED = NULL;
06624 
06625    SUMA_ENTRY;
06626    
06627    list = SUMA_CreateList();
06628    ED = SUMA_InitializeEngineListData (SE_ToggleLockAllViews);
06629    if (!SUMA_RegisterEngineListCommand (  list, ED, 
06630                                           SEF_Empty, NULL, 
06631                                           SES_SumaWidget, NULL, NOPE, 
06632                                           SEI_Head, NULL )) {
06633       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
06634       SUMA_RETURNe;
06635    }
06636    if (!SUMA_Engine (&list)) {
06637       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
06638    }
06639   
06640    
06641    SUMA_RETURNe;   
06642    
06643 }
06644 
06645 void SUMA_cb_XHviewlock_toggled(Widget w, XtPointer client_data, XtPointer callData)
06646 {
06647    static char FuncName[] = {"SUMA_cb_XHviewlock_toggled"};
06648    SUMA_Boolean LocalHead = NOPE;
06649    DList *list=NULL;
06650    SUMA_EngineData *ED = NULL;
06651    int i = (int) client_data;
06652    
06653    SUMA_ENTRY;
06654    
06655    list = SUMA_CreateList ();
06656    ED = SUMA_InitializeEngineListData (SE_ToggleLockView);
06657    if (!SUMA_RegisterEngineListCommand (  list, ED, 
06658                                           SEF_i, (void*)&i, 
06659                                           SES_SumaWidget, NULL, NOPE, 
06660                                           SEI_Head, NULL )) {
06661       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
06662       SUMA_RETURNe;
06663    }
06664    if (!SUMA_Engine (&list)) {
06665       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
06666    }
06667    
06668    SUMA_RETURNe;
06669 }
06670 
06671 /*!
06672    \brief open a new viewer, expects nothing in data
06673 */
06674 
06675 void SUMA_cb_newSumaCont(Widget w, XtPointer client_data, XtPointer callData)
06676 {
06677    static char FuncName[] = {"SUMA_cb_newSumaCont"};
06678    SUMA_Boolean LocalHead = NOPE;
06679    
06680    SUMA_ENTRY;
06681    
06682    fprintf(SUMA_STDOUT, "%s: Opening a new controller...\n", FuncName);
06683    /* open a new controller */
06684    if (!SUMA_X_SurfaceViewer_Create ()) {
06685       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_X_SurfaceViewer_Create.\n", FuncName);
06686       SUMA_RETURNe;
06687    } 
06688    
06689    SUMA_RETURNe;
06690 }
06691 /*!
06692    \brief Close the suma controller, expects nothing in data
06693 */
06694 void SUMA_cb_closeSumaCont(Widget w, XtPointer data, XtPointer callData)
06695 {
06696    static char FuncName[] = {"SUMA_cb_closeSumaCont"};
06697    SUMA_Boolean LocalHead = NOPE;
06698    
06699    SUMA_ENTRY;
06700    
06701    if (!SUMAg_CF->X->SumaCont->AppShell) SUMA_RETURNe;
06702    
06703    #ifdef SUMA_USE_WITHDRAW 
06704       if (LocalHead) fprintf (SUMA_STDERR,"%s: Withdrawing Suma Controller...\n", FuncName);
06705       
06706       XWithdrawWindow(SUMAg_CF->X->DPY_controller1, 
06707          XtWindow(SUMAg_CF->X->SumaCont->AppShell),
06708          XScreenNumberOfScreen(XtScreen(SUMAg_CF->X->SumaCont->AppShell)));
06709    #endif
06710    #ifdef SUMA_USE_DESTROY 
06711       if (LocalHead) fprintf (SUMA_STDERR,"%s: Destroying Suma Controller...\n", FuncName);
06712       XtDestroyWidget(SUMAg_CF->X->SumaCont->AppShell);
06713       SUMAg_CF->X->SumaCont->AppShell = NULL;
06714    #endif
06715    
06716    SUMA_RETURNe;
06717 
06718 }
06719 
06720 /*! 
06721 
06722    \brief climb widget tree until we get to the top.  Return the Shell 
06723    tw = SUMA_GetTopShell(w);
06724    
06725    \param w (Widget) widget for which the top widget is sought
06726    \return tw (Widget) top widget
06727    
06728  * Written by Dan Heller and Paula Ferguson.  
06729  * Copyright 1994, O'Reilly & Associates, Inc.
06730  * see full notice in the beginning of this file
06731    
06732 */
06733 Widget SUMA_GetTopShell(Widget w)
06734 {
06735     while (w && !XtIsWMShell (w))
06736         w = XtParent (w);
06737     return w;
06738 }
06739 
06740 /*!
06741    \brief Sets a button on a radio box
06742 */
06743 
06744 void SUMA_set_Lock_rb (SUMA_rb_group * Lock_rbg, int irb, int but)
06745 {
06746    static char FuncName[] = {"SUMA_set_Lock_rb"};
06747    SUMA_Boolean LocalHead = NOPE;
06748    Widget w;
06749    int i, itb, ifb;
06750    
06751    SUMA_ENTRY;
06752       
06753    ifb = irb*Lock_rbg->N_but; /* index of first button in radio box irb */
06754    itb = ifb+but; /* index of button to modify */
06755    
06756    i = 0;
06757    while (i<Lock_rbg->N_but) {
06758       /* get the widget of the button in question */
06759       w = Lock_rbg->tb[ifb+i];
06760       if (!w) SUMA_RETURNe; /* this happens before opening the SUMA controller */
06761       if ( (ifb + i) == itb) XmToggleButtonSetState (w, YUP, NOPE);
06762        else XmToggleButtonSetState (w, NOPE, NOPE);
06763       ++i;
06764    }
06765    
06766    SUMA_RETURNe;   
06767 
06768 }  
06769       
06770 void SUMA_set_Lock_arb (SUMA_rb_group * Lock_rbg)
06771 {
06772    static char FuncName[] = {"SUMA_set_Lock_arb"};
06773    int i, sumlock;
06774    
06775    SUMA_ENTRY;
06776    
06777    if (!Lock_rbg->atb[0]) SUMA_RETURNe;
06778    /* find out if all buttons are set to the same value */
06779    sumlock = 0;
06780    for (i=0; i < SUMA_MAX_SURF_VIEWERS; ++i) {
06781       sumlock += SUMAg_CF->Locked[i];
06782    } 
06783    
06784    if (sumlock == SUMA_MAX_SURF_VIEWERS * SUMA_No_Lock) { /* all no lock */
06785          XmToggleButtonSetState (Lock_rbg->atb[0], YUP, NOPE);
06786          XmToggleButtonSetState (Lock_rbg->atb[1], NOPE, NOPE);
06787          XmToggleButtonSetState (Lock_rbg->atb[2], NOPE, NOPE);
06788    }else if (sumlock == SUMA_MAX_SURF_VIEWERS * SUMA_I_Lock) {
06789          XmToggleButtonSetState (Lock_rbg->atb[0], NOPE, NOPE);
06790          XmToggleButtonSetState (Lock_rbg->atb[1], YUP, NOPE);
06791          XmToggleButtonSetState (Lock_rbg->atb[2], NOPE, NOPE);
06792    }else if (sumlock == SUMA_MAX_SURF_VIEWERS * SUMA_XYZ_Lock) {
06793          XmToggleButtonSetState (Lock_rbg->atb[0], NOPE, NOPE);
06794          XmToggleButtonSetState (Lock_rbg->atb[1], NOPE, NOPE);
06795          XmToggleButtonSetState (Lock_rbg->atb[2], YUP, NOPE);
06796    }else {
06797          XmToggleButtonSetState (Lock_rbg->atb[0], NOPE, NOPE);
06798          XmToggleButtonSetState (Lock_rbg->atb[1], NOPE, NOPE);
06799          XmToggleButtonSetState (Lock_rbg->atb[2], NOPE, NOPE);
06800    }
06801    
06802    SUMA_RETURNe;   
06803 
06804 }
06805 
06806 void SUMA_set_LockView_atb (void)
06807 {
06808    static char FuncName[] = {"SUMA_set_LockView_atb"};
06809    int i, sumlock;
06810    
06811    SUMA_ENTRY;
06812    
06813    /* find out if all buttons are set to the same value */
06814    sumlock = 0;
06815    for (i=0; i < SUMA_MAX_SURF_VIEWERS; ++i) {
06816       sumlock += SUMAg_CF->ViewLocked[i];
06817    } 
06818 
06819    if (sumlock == SUMA_MAX_SURF_VIEWERS) { /* all locked */
06820       XmToggleButtonSetState (SUMAg_CF->X->SumaCont->LockAllView_tb, YUP, NOPE);
06821    }else if (sumlock == NOPE) { /* none locked */
06822       XmToggleButtonSetState (SUMAg_CF->X->SumaCont->LockAllView_tb, NOPE, NOPE);
06823    }else {/* a mix and match */
06824       /* do nothing for now */
06825    }
06826    
06827    SUMA_RETURNe;   
06828 }
06829 
06830 /*!
06831    \brief opens a text window with information about the surface viewer  
06832    -expects sv pointer in userdata
06833    Feb 23 04: Now requiring sv in client_data. Other widgets will be calling
06834    this function too so w should not be used
06835 */
06836 void SUMA_cb_moreViewerInfo (Widget w, XtPointer client_data, XtPointer callData)
06837 {
06838    static char FuncName[] = {"SUMA_cb_moreViewerInfo"};
06839    SUMA_SurfaceViewer *sv=NULL;
06840    void *n=NULL;
06841    char *s = NULL, stmp[100];
06842    SUMA_Boolean LocalHead = NOPE;
06843    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell = NULL;
06844    int isv;
06845    
06846    SUMA_ENTRY;
06847    
06848    #if 0
06849    /* The userdata way , 
06850    not setup for all widgets calling this function .... */
06851    XtVaGetValues (w,
06852                   XmNuserData, &n,
06853                   NULL);
06854    sv = (SUMA_SurfaceViewer *)n;
06855    #else
06856    /* the good old way, Feb 23 04 */          
06857    sv = (SUMA_SurfaceViewer *)client_data;
06858    #endif
06859    
06860    isv = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
06861 
06862    /* check to see if window is already open, if it is, just raise it */
06863    if (sv->X->ViewCont->ViewerInfo_TextShell) {
06864       XRaiseWindow (SUMAg_CF->X->DPY_controller1, XtWindow(sv->X->ViewCont->ViewerInfo_TextShell->toplevel));
06865       SUMA_RETURNe;
06866    }
06867    
06868    /* for the string of the surface info */
06869    s = SUMA_SurfaceViewer_StructInfo(sv, 1);
06870    
06871    #if 1
06872    if (s) {
06873       TextShell =  SUMA_CreateTextShellStruct (SUMA_ViewerInfo_open, (void *)sv, 
06874                                                SUMA_ViewerInfo_destroyed, (void *)sv);
06875       if (!TextShell) {
06876          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CreateTextShellStruct.\n", FuncName);
06877          SUMA_RETURNe;
06878       }
06879       sprintf(stmp, "[%c] Viewer Info", 65+isv);
06880       sv->X->ViewCont->ViewerInfo_TextShell = SUMA_CreateTextShell(s, stmp, TextShell);
06881       SUMA_free(s);
06882    }else {
06883       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_SurfaceViewer_StructInfo.\n", FuncName);
06884    }   
06885    #else 
06886       fprintf (SUMA_STDERR, "%s\n", s);
06887       SUMA_free(s); 
06888    #endif
06889 
06890     
06891    SUMA_RETURNe;
06892 }
06893 /*!
06894    \brief Function called when Surface Info window is open
06895 */
06896 void SUMA_ViewerInfo_open (void *p) 
06897 {
06898    static char FuncName[] = {"SUMA_ViewerInfo_open"};
06899    SUMA_SurfaceViewer *sv= NULL;
06900   
06901    SUMA_ENTRY;
06902    
06903    sv = (SUMA_SurfaceViewer *)p;
06904    MCW_invert_widget (sv->X->ViewCont->ViewerInfo_pb);
06905    
06906    
06907    SUMA_RETURNe;
06908 }
06909 
06910 /*!
06911    \brief Function called when Viewer Info window is destroyed
06912 */
06913 void SUMA_ViewerInfo_destroyed (void *p) 
06914 {
06915    static char FuncName[] = {"SUMA_ViewerInfo_destroyed"};
06916    SUMA_SurfaceViewer *sv= NULL;
06917    
06918    SUMA_ENTRY;
06919 
06920    sv = (SUMA_SurfaceViewer *)p;
06921    MCW_invert_widget (sv->X->ViewCont->ViewerInfo_pb);
06922    
06923    sv->X->ViewCont->ViewerInfo_TextShell = NULL;
06924    SUMA_RETURNe;
06925 }
06926 
06927 
06928 /*!
06929    \brief Opens a text viewer with SUMA's structure info
06930    - expects nothing for input 
06931 */
06932 void SUMA_cb_moreSumaInfo (Widget w, XtPointer client_data, XtPointer callData)
06933 {
06934    static char FuncName[] = {"SUMA_cb_moreSumaInfo"};
06935    SUMA_SurfaceObject *SO=NULL;
06936    void *n=NULL;
06937    char *s = NULL;
06938    SUMA_Boolean LocalHead = NOPE;
06939    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell = NULL;
06940    
06941    SUMA_ENTRY;
06942    
06943    /* check to see if window is already open, if it is, just raise it */
06944    if (SUMAg_CF->X->SumaCont->SumaInfo_TextShell) {
06945       XRaiseWindow (SUMAg_CF->X->DPY_controller1, XtWindow(SUMAg_CF->X->SumaCont->SumaInfo_TextShell->toplevel));
06946       SUMA_RETURNe;
06947    }
06948    
06949    /* for the string of the surface info */
06950    s = SUMA_CommonFieldsInfo (SUMAg_CF, 1);
06951    
06952    if (s) {
06953       TextShell =  SUMA_CreateTextShellStruct (SUMA_SumaInfo_open, NULL, 
06954                                                SUMA_SumaInfo_destroyed, NULL);
06955       if (!TextShell) {
06956          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CreateTextShellStruct.\n", FuncName);
06957          SUMA_RETURNe;
06958       }
06959       SUMAg_CF->X->SumaCont->SumaInfo_TextShell = SUMA_CreateTextShell(s, "SUMA", TextShell);
06960       SUMA_free(s);
06961    }else {
06962       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CommonFieldsInfo.\n", FuncName);
06963    }   
06964 
06965     
06966    SUMA_RETURNe;
06967 }
06968 
06969 /*!
06970    \brief Function called when Suma Info window is open
06971 */
06972 void SUMA_SumaInfo_open (void *p) 
06973 {
06974    static char FuncName[] = {"SUMA_SumaInfo_open"};
06975   
06976    SUMA_ENTRY;
06977    
06978    /* nothing to do here ... */
06979    
06980    SUMA_RETURNe;
06981 }
06982 
06983 /*!
06984    \brief Function called when Suma Info window is destroyed
06985 */
06986 void SUMA_SumaInfo_destroyed (void *p) 
06987 {
06988    static char FuncName[] = {"SUMA_SumaInfo_destroyed"};
06989    SUMA_SurfaceObject *SO= NULL;
06990    
06991    SUMA_ENTRY;
06992 
06993    SUMAg_CF->X->SumaCont->SumaInfo_TextShell = NULL;
06994    SUMA_RETURNe;
06995 }
06996 
06997 /*! 
06998    \brief opens a text window with information about the surface object in focus 
06999    -expects SO pointer in userdata
07000    Feb 23 04: Now requiring sv in client_data. Other widgets will be calling
07001    this function too, so w should not be used
07002 */
07003 void SUMA_cb_moreSurfInfo (Widget w, XtPointer client_data, XtPointer callData)
07004 {
07005    static char FuncName[] = {"SUMA_cb_moreSurfInfo"};
07006    SUMA_SurfaceObject *SO=NULL;
07007    void *n=NULL;
07008    char *s = NULL;
07009    void **curSOp;
07010    SUMA_Boolean LocalHead = NOPE;
07011    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell = NULL;
07012    
07013    SUMA_ENTRY;
07014    #if 0
07015    XtVaGetValues (w,
07016                   XmNuserData, &n,
07017                   NULL);
07018                   
07019    SO = (SUMA_SurfaceObject *)n;
07020    #else
07021    curSOp = (void **)client_data;
07022    SO = (SUMA_SurfaceObject *)(*curSOp);
07023    #endif
07024   
07025    /* check to see if window is already open, if it is, just raise it */
07026    if (SO->SurfCont->SurfInfo_TextShell) {
07027       XRaiseWindow (SUMAg_CF->X->DPY_controller1, XtWindow(SO->SurfCont->SurfInfo_TextShell->toplevel));
07028       SUMA_RETURNe;
07029    }
07030    
07031    /* for the string of the surface info */
07032    s = SUMA_SurfaceObject_Info (SO, SUMAg_CF->DsetList);
07033    
07034    if (s) {
07035       TextShell =  SUMA_CreateTextShellStruct (SUMA_SurfInfo_open, (void *)SO, 
07036                                                SUMA_SurfInfo_destroyed, (void *)SO);
07037       if (!TextShell) {
07038          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CreateTextShellStruct.\n", FuncName);
07039          SUMA_RETURNe;
07040       }
07041       SO->SurfCont->SurfInfo_TextShell = SUMA_CreateTextShell(s, SO->Label, TextShell);
07042       SUMA_free(s);
07043    }else {
07044       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_SurfaceObject_Info.\n", FuncName);
07045    }   
07046 
07047     
07048    SUMA_RETURNe;
07049 }
07050 
07051 /*!
07052    \brief Function called when Surface Info window is open
07053 */
07054 void SUMA_SurfInfo_open (void *p) 
07055 {
07056    static char FuncName[] = {"SUMA_SurfInfo_open"};
07057    SUMA_SurfaceObject *SO= NULL;
07058   
07059    SUMA_ENTRY;
07060    
07061    SO = (SUMA_SurfaceObject *)p;
07062    MCW_invert_widget (SO->SurfCont->SurfInfo_pb);
07063    
07064    
07065    SUMA_RETURNe;
07066 }
07067 
07068 /*!
07069    \brief Function called when Surface Info window is destroyed
07070 */
07071 void SUMA_SurfInfo_destroyed (void *p) 
07072 {
07073    static char FuncName[] = {"SUMA_SurfInfo_destroyed"};
07074    SUMA_SurfaceObject *SO= NULL;
07075    
07076    SUMA_ENTRY;
07077 
07078    SO = (SUMA_SurfaceObject *)p;
07079    MCW_invert_widget (SO->SurfCont->SurfInfo_pb);
07080    
07081    SO->SurfCont->SurfInfo_TextShell = NULL;
07082    SUMA_RETURNe;
07083 }
07084 
07085 /*!
07086    \brief calls XtDestroyWidget on to top level shell of w and frees the TextShell pointer in clientdata. 
07087 */
07088 void SUMA_DestroyTextShell (Widget w, XtPointer ud, XtPointer cd) 
07089 {
07090    static char FuncName[] = {"SUMA_DestroyTextShell"};
07091    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell=NULL;
07092    
07093    SUMA_ENTRY;
07094    
07095    TextShell = (SUMA_CREATE_TEXT_SHELL_STRUCT *)ud;
07096    
07097    if (TextShell->DestroyCallBack) {
07098       /* call destroy callback */
07099       TextShell->DestroyCallBack(TextShell->DestroyData);
07100    }
07101    if (TextShell) SUMA_free(TextShell);
07102    
07103    XtDestroyWidget(SUMA_GetTopShell(w));
07104 
07105    SUMA_RETURNe;
07106 }
07107 
07108 
07109 /*!
07110    \brief Creates the structure used to pass widget and options back and forth from SUMA_CreateTextShell
07111    TextShellStruct = SUMA_CreateTextShellStruct (void (*opencallback)(void *data), void *opendata, 
07112                                                             void (*closecallback)(void*data), void *closedata);
07113                                                             
07114    - callbacks and their data are stored in their respective fields in TextShellStruct
07115    - All widgets are set to NULL
07116    
07117 */
07118 
07119 SUMA_CREATE_TEXT_SHELL_STRUCT * SUMA_CreateTextShellStruct (void (*opencallback)(void *data), void *opendata, 
07120                                                             void (*closecallback)(void*data), void *closedata)
07121 {
07122    static char FuncName[] = {"SUMA_CreateTextShellStruct"};
07123    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell=NULL;
07124    
07125    SUMA_ENTRY;
07126    
07127    TextShell = (SUMA_CREATE_TEXT_SHELL_STRUCT *) SUMA_malloc (sizeof(SUMA_CREATE_TEXT_SHELL_STRUCT));
07128    if (!TextShell) {
07129       fprintf (SUMA_STDERR, "Error %s: Failed to allocate for TextShell.\n", FuncName);
07130       SUMA_RETURN (NULL);
07131    }
07132    TextShell->text_w =  TextShell->search_w = TextShell->text_output = TextShell->toplevel = NULL;
07133    TextShell->case_sensitive = NOPE;
07134    TextShell->allow_edit = NOPE;
07135    TextShell->OpenCallBack = opencallback;
07136    TextShell->OpenData = opendata;
07137    TextShell->DestroyCallBack = closecallback;
07138    TextShell->DestroyData = closedata;
07139    TextShell->CursorAtBottom = NOPE;
07140    
07141    SUMA_RETURN (TextShell);
07142 }  
07143 
07144 /*!
07145    \brief Opens a window with text information in it. 
07146    
07147    \param s (char *) string to display, must be null terminated.
07148    \param title (char *) title of window
07149    \param TextShell (SUMA_CreateTextShell *) containing options for SUMA_CreateTextShell
07150       if TextShell->toplevel then only the log message is updated, otherwise the window is created.
07151    \return TextShell (SUMA_CreateTextShell *) same structure sent to function but with widgets fields filled. 
07152    
07153    \sa SUMA_CreateTextShellStruct
07154    
07155    - based on example SUMA_search_text from "Motif Programming Manual"
07156    see copyright notice in beginning of SUMA_display.c
07157 */   
07158 SUMA_CREATE_TEXT_SHELL_STRUCT * SUMA_CreateTextShell (char *s, char *title, SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell)
07159 {
07160    static char FuncName[] = {"SUMA_CreateTextShell"};
07161    Widget rowcol_v, rowcol_h, close_w, form, frame, toggle_case_w;
07162    int n;
07163    SUMA_Boolean LocalHead = NOPE;
07164    Pixel fg_pix;
07165    Arg args[20];
07166    
07167    SUMA_ENTRY;
07168 
07169    if (TextShell->OpenCallBack) { /* do the opening callback */
07170       if (LocalHead) fprintf (SUMA_STDERR, "%s: Calling OpenCallBack.\n", FuncName);
07171       TextShell->OpenCallBack(TextShell->OpenData);
07172    }
07173    
07174    if (!TextShell->toplevel) { /* need to create window */
07175       if (LocalHead) fprintf (SUMA_STDERR, "%s: Creating new text shell window.\n", FuncName);
07176       TextShell->toplevel = XtVaAppCreateShell (title, "Suma",
07177          topLevelShellWidgetClass, SUMAg_CF->X->DPY_controller1 ,
07178          XmNdeleteResponse, XmDO_NOTHING,
07179          NULL);  
07180 
07181       XmAddWMProtocolCallback(/* make "Close" window menu work */
07182          TextShell->toplevel,
07183          XmInternAtom( SUMAg_CF->X->DPY_controller1 , "WM_DELETE_WINDOW" , False ) ,
07184          SUMA_DestroyTextShell, TextShell) ;
07185 
07186       form = XtVaCreateWidget ("textoutput",
07187         xmFormWidgetClass, TextShell->toplevel, NULL);
07188 
07189 
07190       rowcol_v = XtVaCreateWidget ("rowcol_v",
07191         xmRowColumnWidgetClass, form, NULL);
07192 
07193       rowcol_h = XtVaCreateWidget ("rowcol_h",
07194         xmRowColumnWidgetClass, rowcol_v,
07195         XmNorientation,  XmHORIZONTAL,
07196         NULL);
07197       XtVaCreateManagedWidget ("Search Pattern:",
07198         xmLabelWidgetClass, rowcol_h, NULL);
07199 
07200       TextShell->search_w = XtVaCreateManagedWidget ("SUMA_search_text",
07201         xmTextFieldWidgetClass, rowcol_h, NULL);
07202 
07203       XtVaGetValues (TextShell->search_w, XmNforeground, &fg_pix, NULL);
07204       toggle_case_w = XtVaCreateManagedWidget ("Case Sensitive",
07205          xmToggleButtonWidgetClass, rowcol_h,
07206          XmNset, TextShell->case_sensitive,
07207          XmNselectColor, fg_pix, 
07208          NULL);
07209       XtAddCallback (toggle_case_w, XmNvalueChangedCallback,SUMA_cb_ToggleCaseSearch, TextShell);
07210 
07211       close_w = XtVaCreateManagedWidget ("Close", 
07212          xmPushButtonWidgetClass, rowcol_h, NULL);
07213       XtAddCallback (close_w, XmNactivateCallback, SUMA_DestroyTextShell, TextShell);    
07214 
07215       XtManageChild (rowcol_h);
07216 
07217       TextShell->text_output = XtVaCreateManagedWidget ("text_output",
07218         xmTextWidgetClass, rowcol_v,
07219         XmNeditable,              False,
07220         XmNcursorPositionVisible, False,
07221         XmNshadowThickness,       0,
07222         XmNhighlightThickness,    0,
07223         NULL);
07224 
07225       XtManageChild (rowcol_v);
07226 
07227       n = 0;
07228       XtSetArg (args[n], XmNrows,      10); n++;
07229       XtSetArg (args[n], XmNcolumns,   80); n++;
07230       XtSetArg (args[n], XmNeditMode,  XmMULTI_LINE_EDIT); n++;
07231       XtSetArg (args[n], XmNeditable, TextShell->allow_edit); n++;
07232       XtSetArg (args[n], XmNscrollHorizontal,  False); n++;
07233       XtSetArg (args[n], XmNwordWrap,  True); n++;
07234       XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
07235       XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
07236       XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
07237       XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
07238       XtSetArg (args[n], XmNtopWidget, rowcol_v); n++;
07239 
07240       TextShell->text_w = XmCreateScrolledText (form, "text_w", args, n);
07241       if (!s) {
07242          XmTextSetString (TextShell->text_w, "No Messages.\n---------------\n");
07243       } else {
07244          XmTextSetString (TextShell->text_w, s);
07245       }   
07246       XtManageChild (TextShell->text_w);
07247 
07248       XtAddCallback (TextShell->search_w, XmNactivateCallback, SUMA_cb_search_text, TextShell);
07249 
07250       XtManageChild (form);
07251 
07252       /* pop it up if it is a topLevelShellWidgetClass */
07253       XtPopup(TextShell->toplevel, XtGrabNone);   
07254 
07255       XtRealizeWidget (TextShell->toplevel);
07256    } else { /* already created, just replace text and perhaps title (in the future)*/
07257       if (LocalHead) fprintf (SUMA_STDERR, "%s: Setting string in previously created text shell window.\n", FuncName);
07258       if (!s) XmTextSetString (TextShell->text_w, "No Messages.\n---------------\n");
07259       else XmTextSetString (TextShell->text_w, s);
07260       if (TextShell->CursorAtBottom) {
07261          XmTextSetInsertionPosition(TextShell->text_w, XmTextGetLastPosition (TextShell->text_w));
07262       }
07263    }
07264    SUMA_RETURN(TextShell);
07265 }
07266 
07267 /*! \brief toggles case sensitive search 
07268    - Expects a SUMA_CREATE_TEXT_SHELL_STRUCT pointer in clientdata:
07269 */
07270 
07271 void SUMA_cb_ToggleCaseSearch (Widget widget, XtPointer client_data, XtPointer call_data)
07272 {
07273    static char FuncName[]={"SUMA_cb_ToggleCaseSearch"};
07274    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell;
07275    
07276    SUMA_ENTRY;
07277 
07278    TextShell = (SUMA_CREATE_TEXT_SHELL_STRUCT *)client_data;
07279    TextShell->case_sensitive = !TextShell->case_sensitive;
07280    
07281    SUMA_RETURNe;   
07282 }
07283 /*!
07284     \brief searches text in a text widget for a string specified in a textfield widget and
07285     writes the results in a text_output text widget.
07286 
07287    - Expects a structure SUMA_CREATE_TEXT_SHELL_STRUCT pointer in clientdata:
07288       text_w (Widget)
07289       search_w (Widget)
07290       text_output (Widget)
07291       
07292    - Based on search_text() from "Motif Programming Manual"
07293 */
07294 void SUMA_cb_search_text(Widget widget, XtPointer client_data, XtPointer call_data)
07295 {
07296    char *search_pat, *p, *string, buf[32];
07297    XmTextPosition pos;
07298    int len, i;
07299    Boolean found = False;
07300    SUMA_Boolean LocalHead = NOPE;
07301    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell;
07302    static char FuncName[]={"SUMA_cb_search_text"};
07303    
07304    SUMA_ENTRY;
07305    
07306    
07307    TextShell = (SUMA_CREATE_TEXT_SHELL_STRUCT *)client_data;
07308    if (!TextShell) { SUMA_SL_Err("Unexpected NULL TextShell"); SUMA_RETURNe; }
07309    
07310    /* get the text that is about to be searched */
07311    if (!(string = XmTextGetString (TextShell->text_w)) || !*string) {
07312      XmTextSetString (TextShell->text_output, "No text to search.");
07313      if (string) XtFree (string); /* may have been ""; free it */
07314      SUMA_RETURNe;
07315    }
07316    len = strlen(string);
07317    if (!TextShell->case_sensitive) {
07318       if (LocalHead) fprintf (SUMA_STDERR,"%s: Case insensitive search.\n", FuncName);
07319       /* turn string to lowercase */
07320       for (i=0; i < len; ++i) string[i] = tolower(string[i]);   
07321    }
07322    
07323    /* get the pattern we're going to search for in the text. */
07324    if (!(search_pat = XmTextGetString (TextShell->search_w)) || !*search_pat) {
07325      XmTextSetString (TextShell->text_output, "Specify a search pattern.");
07326      XtFree (string); /* this we know is a string; free it */
07327      if (search_pat) XtFree (search_pat); /* this may be "", XtFree() checks.. */
07328      SUMA_RETURNe;
07329    }
07330    len = strlen (search_pat);
07331    
07332    if (!TextShell->case_sensitive) {
07333       /* turn search_pat to lowercase */
07334       for (i=0; i < len; ++i) search_pat[i] = tolower(search_pat[i]);  
07335    }
07336    /* start searching at current cursor position + 1 to find
07337    * the -next- occurrance of string.  we may be sitting on it.
07338    */
07339    pos = XmTextGetCursorPosition (TextShell->text_w);
07340    for (p = &string[pos+1]; (p = index (p, *search_pat)); p++)
07341      if (!strncmp (p, search_pat, len)) {
07342          found = True;
07343          break;
07344      }
07345    if (!found) { /* didn't find pattern? */
07346      /* search from beginning till we've passed "pos" */
07347      for (p = string;
07348              (p = index (p, *search_pat)) && p - string <= pos; p++)
07349          if (!strncmp (p, search_pat, len)) {
07350              found = True;
07351              break;
07352          }
07353    }
07354    if (!found)
07355      XmTextSetString (TextShell->text_output, "Pattern not found.");
07356    else {
07357      pos = (XmTextPosition)(p - string);
07358      sprintf (buf, "Pattern found at position %ld.", pos);
07359      XmTextSetString (TextShell->text_output, buf);
07360      XmTextSetInsertionPosition (TextShell->text_w, pos);
07361      XmTextSetHighlight(TextShell->text_w, pos, pos+len, XmHIGHLIGHT_SELECTED);
07362    }
07363    if (string) XtFree (string);
07364    if (search_pat) XtFree (search_pat);
07365    
07366    SUMA_RETURNe;
07367 }
07368 
07369 /*!
07370    \brief sets the saving mode 
07371    - expects a SUMA_MenuCallBackData * in  client_data
07372    Nothing in client_data->ContID and Menubutton in client_data->callback_data
07373 */
07374 void SUMA_cb_SetDrawROI_SaveMode(Widget widget, XtPointer client_data, XtPointer call_data)
07375 {
07376    static char FuncName[]={"SUMA_cb_SetDrawROI_SaveMode"};
07377    SUMA_MenuCallBackData *datap=NULL;
07378    SUMA_Boolean LocalHead = NOPE;
07379    
07380    SUMA_ENTRY;
07381    
07382    datap = (SUMA_MenuCallBackData *)client_data;
07383    
07384    if (LocalHead) fprintf(SUMA_STDERR,"%s: Setting SaveMode to %d\n", FuncName, (int)datap->callback_data);
07385    SUMAg_CF->X->DrawROI->SaveMode = (int)datap->callback_data; 
07386    
07387    SUMA_RETURNe;
07388 }
07389 
07390 
07391 /*!
07392    \brief sets the "saving what" parameter
07393    - expects a SUMA_MenuCallBackData * in  client_data
07394    Nothing in client_data->ContID and Menubutton in client_data->callback_data
07395 */
07396 void SUMA_cb_SetDrawROI_WhatDist(Widget widget, XtPointer client_data, XtPointer call_data)
07397 {
07398    static char FuncName[]={"SUMA_cb_SetDrawROI_WhatDist"};
07399    SUMA_MenuCallBackData *datap=NULL;
07400    SUMA_Boolean LocalHead = NOPE;
07401    
07402    SUMA_ENTRY;
07403    
07404    datap = (SUMA_MenuCallBackData *)client_data;
07405 
07406    if (LocalHead) fprintf(SUMA_STDERR,"%s: Setting WhatDist to %d\n", FuncName, (int)datap->callback_data);
07407    SUMAg_CF->X->DrawROI->WhatDist = (int)datap->callback_data; 
07408    
07409    SUMA_RETURNe;
07410 } 
07411 
07412 /*!
07413    \brief sets the " what distance" parameter
07414    - expects a SUMA_MenuCallBackData * in  client_data
07415    Nothing in client_data->ContID and Menubutton in client_data->callback_data
07416 */
07417 void SUMA_cb_SetDrawROI_SaveWhat(Widget widget, XtPointer client_data, XtPointer call_data)
07418 {
07419    static char FuncName[]={"SUMA_cb_SetDrawROI_SaveWhat"};
07420    SUMA_MenuCallBackData *datap=NULL;
07421    SUMA_Boolean LocalHead = NOPE;
07422    
07423    SUMA_ENTRY;
07424    
07425    datap = (SUMA_MenuCallBackData *)client_data;
07426    
07427    if (LocalHead) fprintf(SUMA_STDERR,"%s: Setting SaveWhat to %d\n", FuncName, (int)datap->callback_data);
07428    SUMAg_CF->X->DrawROI->SaveWhat = (int)datap->callback_data; 
07429    
07430    SUMA_RETURNe;
07431 }
07432    
07433 /*!
07434    \brief sets the rendering mode of a surface 
07435    
07436    - expects a SUMA_MenuCallBackData * in  client_data
07437    with SO as client_data->ContID and Menubutton in client_data->callback_data
07438 */
07439 void SUMA_cb_SetRenderMode(Widget widget, XtPointer client_data, XtPointer call_data)
07440 {
07441    static char FuncName[]={"SUMA_cb_SetRenderMode"};
07442    DList *list = NULL;
07443    DListElmt *Elmnt = NULL;
07444    SUMA_EngineData *ED = NULL;
07445    SUMA_MenuCallBackData *datap=NULL;
07446    SUMA_SurfaceObject *SO = NULL;
07447    void **curSOp;
07448    int imenu = 0;
07449    
07450    SUMA_ENTRY;
07451 
07452    /* get the surface object that the setting belongs to */
07453    datap = (SUMA_MenuCallBackData *)client_data;
07454    curSOp = (void **)datap->ContID;
07455    SO = (SUMA_SurfaceObject *)(*curSOp);
07456    imenu = (int)datap->callback_data; 
07457    
07458    switch (imenu) {
07459       case SW_SurfCont_RenderViewerDefault:
07460          imenu = SRM_ViewerDefault;
07461          break;
07462       case SW_SurfCont_RenderFill:
07463          imenu = SRM_Fill;
07464          break;
07465       case SW_SurfCont_RenderLine:
07466          imenu = SRM_Line;
07467          break;
07468       case SW_SurfCont_RenderPoints:
07469          imenu = SRM_Points;
07470          break;
07471       default: 
07472          fprintf (SUMA_STDERR, "Error %s: Unexpected widget index.\n", FuncName);
07473          break;
07474    }
07475    
07476    
07477    /* make a call to SUMA_Engine */
07478    if (!list) list = SUMA_CreateList ();
07479    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_SumaWidget, NULL);   
07480    ED = SUMA_InitializeEngineListData (SE_SetRenderMode);
07481    Elmnt = SUMA_RegisterEngineListCommand ( list, ED,
07482                                          SEF_i, (void *)&imenu,
07483                                          SES_SumaWidget, NULL, NOPE,
07484                                          SEI_Head, NULL);
07485    if (!SUMA_RegisterEngineListCommand ( list, ED,
07486                                          SEF_vp, (void *)SO,
07487                                          SES_SumaWidget, NULL, NOPE,
07488                                          SEI_In, Elmnt)) {
07489       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_RegisterEngineListCommand.\n", FuncName);
07490       SUMA_RETURNe;                                     
07491    }
07492    
07493    
07494    if (!SUMA_Engine (&list)) {
07495       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Engine.\n", FuncName);
07496       SUMA_RETURNe;    
07497    }
07498    
07499    SUMA_RETURNe;
07500 }
07501 /*!
07502    \brief pops a SUMA message
07503 */
07504 void SUMA_PopUpMessage (SUMA_MessageData *MD)
07505 {
07506    static char FuncName[]={"SUMA_PopUpMessage"};
07507    Widget Parent_w=NULL, wmsg = NULL;
07508    int ii;
07509    
07510    SUMA_ENTRY;
07511    
07512    if (!SUMAg_N_SVv) {
07513       /* no graphics here, get out */
07514       SUMA_RETURNe;
07515    }
07516    
07517    /* find a decent popup message parent */
07518    ii=0;
07519    while ((SUMAg_SVv[ii].isShaded || !SUMAg_SVv[ii].X->TOPLEVEL) && (ii < SUMAg_N_SVv)) {
07520       ++ii;   
07521    }
07522    
07523    
07524    if (ii < SUMAg_N_SVv)
07525       Parent_w = SUMAg_SVv[ii].X->TOPLEVEL;
07526    else { 
07527       /* try again but with one that could be shaded */
07528       ii=0;
07529       while (!SUMAg_SVv[ii].X->TOPLEVEL && (ii < SUMAg_N_SVv)) {
07530          ++ii;   
07531       }
07532       if (ii >= SUMAg_N_SVv) {
07533          fprintf (SUMA_STDERR, "Error %s: This should not be happening.\n", FuncName);
07534          SUMA_RETURNe;  
07535       }else Parent_w = SUMAg_SVv[ii].X->TOPLEVEL;
07536    }
07537    
07538    if (MD->Action ==  SMA_LogAndPopup) {
07539       wmsg = NULL;
07540       switch (MD->Type) {
07541          case SMT_Notice:
07542             wmsg = MCW_popup_message(Parent_w, SUMA_FormatMessage (MD), MCW_USER_KILL | MCW_TIMER_KILL);
07543             break;
07544          case SMT_Warning:
07545             wmsg = MCW_popup_message(Parent_w, SUMA_FormatMessage (MD), MCW_USER_KILL | MCW_TIMER_KILL);
07546             break;
07547          case SMT_Error:
07548             wmsg = MCW_popup_message(Parent_w, SUMA_FormatMessage (MD), MCW_USER_KILL);
07549             break;
07550          case SMT_Critical:
07551             wmsg = MCW_popup_message(Parent_w, SUMA_FormatMessage (MD), MCW_CALLER_KILL);
07552             break;
07553          case SMT_Text:
07554             wmsg = MCW_popup_message(Parent_w, SUMA_FormatMessage (MD), MCW_CALLER_KILL | MCW_TIMER_KILL);
07555             break;
07556          default:
07557             break;
07558       }
07559       if (wmsg) {
07560          SUMA_PositionWindowRelative (wmsg, NULL, SWP_POINTER_OFF);
07561       }
07562    }
07563    
07564    SUMA_RETURNe;   
07565 
07566 }
07567 
07568 /*!
07569    \brief forms the message string.
07570 */
07571 char * SUMA_FormatMessage (SUMA_MessageData *MD) 
07572 {
07573    static char FuncName[]={"SUMA_FormatMessage"};
07574    char *s=NULL;
07575 
07576    SUMA_ENTRY;
07577 
07578    s = (char *)SUMA_calloc (strlen(MD->Message)+strlen(MD->Source)+100, sizeof(char));
07579    if (!s) {
07580       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07581       SUMA_RETURN(NULL);
07582    }
07583    switch (MD->Type) {
07584       case SMT_Notice:
07585          sprintf(s,"Notice %s:\n%s\n", MD->Source, MD->Message);
07586          break;
07587       case SMT_Warning:
07588          sprintf(s,"Warning %s:\n%s\n", MD->Source, MD->Message);
07589          break;
07590       case SMT_Error:
07591          sprintf(s,"Error %s:\n%s\n", MD->Source, MD->Message);
07592          break;
07593       case SMT_Critical:
07594          sprintf(s,"Critical Error %s:\n%s\n", MD->Source, MD->Message);
07595          break;
07596       case SMT_Text:
07597          sprintf(s,"%s", MD->Message);
07598          break;
07599       default:
07600          sprintf(s,"BAD MESSAGE.\n");
07601          break;
07602    }
07603    
07604    SUMA_RETURN (s);
07605 }
07606 
07607 
07608 /*!
07609    \brief opens the DRAW ROI window 
07610    
07611    - expects a SUMA_MenuCallBackData * in  client_data
07612    with sv index as client_data->ContID 
07613 */
07614 void SUMA_cb_ToolsDrawROI (Widget w, XtPointer client_data, XtPointer call_data)
07615 {
07616    static char FuncName[]={"SUMA_cb_ToolsDrawROI"};
07617    int isv;
07618    DList *list = NULL;
07619    SUMA_MenuCallBackData * datap=NULL;
07620    
07621    SUMA_ENTRY;
07622 
07623    /* get the surface viewer that the command was made in */
07624    datap = (SUMA_MenuCallBackData *)client_data;
07625    isv = (int)datap->ContID;
07626 
07627    /* register a call to open the ROI editor */
07628    if (!list) list = SUMA_CreateList ();
07629    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_OpenDrawROI, SES_SumaWidget, (void*)&SUMAg_SVv[isv]); 
07630    if (!SUMA_Engine (&list)) {
07631       SUMA_RegisterMessage (SUMAg_CF->MessageList, "Failed to open DrawROI", FuncName, SMT_Error, SMA_LogAndPopup);
07632    }  
07633    SUMA_RETURNe;
07634 }
07635 
07636 /*!
07637    \brief Undo an action on the stack
07638    
07639    - expects nothing
07640 */
07641 void SUMA_cb_DrawROI_Undo (Widget w, XtPointer data, XtPointer client_data)
07642 {
07643    static char FuncName[]={"SUMA_cb_DrawROI_Undo"};
07644    DList *list = NULL;
07645    DListElmt *tmp=NULL;
07646    SUMA_Boolean LocalHead = NOPE;
07647    
07648    SUMA_ENTRY;
07649    
07650    if (!SUMAg_CF->X->DrawROI->curDrawnROI) SUMA_RETURNe;
07651    
07652    if (LocalHead) fprintf(SUMA_STDERR,"%s: Calling SUMA_UndoAction...\n", FuncName);
07653    
07654    if (!SUMAg_CF->X->DrawROI->curDrawnROI->StackPos) {
07655       SUMA_SLP_Err("Nothing to Undo.");
07656       SUMA_RETURNe;
07657    }
07658    
07659    tmp = SUMA_UndoAction (SUMAg_CF->X->DrawROI->curDrawnROI->ActionStack, SUMAg_CF->X->DrawROI->curDrawnROI->StackPos);
07660    if (!tmp) {
07661       SUMA_S_Err("Failed to Undo.");
07662       SUMA_RETURNe;
07663    }else if (tmp == SUMAg_CF->X->DrawROI->curDrawnROI->StackPos) {
07664       /* reached bottom */
07665       SUMAg_CF->X->DrawROI->curDrawnROI->StackPos = NULL;
07666    }else {
07667       SUMAg_CF->X->DrawROI->curDrawnROI->StackPos = tmp;
07668    }
07669 
07670    if (dlist_size(SUMAg_CF->X->DrawROI->curDrawnROI->ROIstrokelist)) {
07671       SUMA_LH("Not empty ROIstrokelist");
07672    }else {
07673       SUMA_LH(" empty ROIstrokelist");
07674    }
07675    
07676    /* do the paint thing */
07677    /* Now update the Paint job on the ROI plane */
07678    if (!SUMA_Paint_SO_ROIplanes_w (SUMA_findSOp_inDOv(SUMAg_CF->X->DrawROI->curDrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv), SUMAg_DOv, SUMAg_N_DOv)) {
07679       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
07680       SUMA_RETURNe;
07681    } 
07682 
07683    /* place a call to redisplay */
07684    if (!list) list = SUMA_CreateList ();
07685    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_Suma, NULL);
07686    if (!SUMA_Engine (&list)) {
07687       SUMA_SL_Err("Failed calling SUMA_Engine.");
07688    }
07689    
07690    
07691    SUMA_RETURNe;
07692 }
07693 
07694 void SUMA_cb_DrawROI_Redo (Widget w, XtPointer data, XtPointer client_data)
07695 {
07696    static char FuncName[]={"SUMA_cb_DrawROI_Redo"};
07697    DList *list = NULL;
07698    DListElmt *tmp=NULL;
07699    SUMA_Boolean LocalHead = NOPE;
07700    
07701    
07702    SUMA_ENTRY;
07703    
07704    if (!SUMAg_CF->X->DrawROI->curDrawnROI) SUMA_RETURNe;
07705    
07706    if (LocalHead) fprintf(SUMA_STDERR,"%s: Calling SUMA_RedoAction...\n", FuncName);
07707    
07708    if (SUMAg_CF->X->DrawROI->curDrawnROI->StackPos == dlist_tail(SUMAg_CF->X->DrawROI->curDrawnROI->ActionStack)) {
07709       SUMA_SLP_Err("Nothing to Redo.");
07710       SUMA_RETURNe;
07711    }
07712    
07713    tmp = SUMA_RedoAction (SUMAg_CF->X->DrawROI->curDrawnROI->ActionStack, SUMAg_CF->X->DrawROI->curDrawnROI->StackPos);
07714    if (!tmp) {
07715       SUMA_S_Err("Failed to Redo.");
07716       SUMA_RETURNe;
07717    }else {
07718       SUMAg_CF->X->DrawROI->curDrawnROI->StackPos = tmp;
07719    }
07720    
07721 
07722    /* do the paint thing */
07723    /* Now update the Paint job on the ROI plane */
07724    if (!SUMA_Paint_SO_ROIplanes_w (SUMA_findSOp_inDOv(SUMAg_CF->X->DrawROI->curDrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv), SUMAg_DOv, SUMAg_N_DOv)) {
07725       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
07726       SUMA_RETURNe;
07727    } 
07728 
07729    /* place a call to redisplay */
07730    if (!list) list = SUMA_CreateList ();
07731    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_Suma, NULL);
07732    if (!SUMA_Engine (&list)) {
07733       SUMA_SL_Err("Failed calling SUMA_Engine.");
07734    }
07735    
07736    SUMA_RETURNe;
07737 }
07738 
07739 void SUMA_cb_DrawROI_Join (Widget w, XtPointer data, XtPointer client_data)
07740 {
07741    static char FuncName[]={"SUMA_cb_DrawROI_Join"};
07742    SUMA_Boolean LocalHead = NOPE;
07743    int HeadNode=-1, TailNode=-1;
07744    float ThirdNode_v[3];
07745    SUMA_DRAWN_ROI *DrawnROI=NULL;
07746    SUMA_SurfaceObject *SO=NULL;
07747    SUMA_ROI_DATUM *ROIstroke = NULL;
07748    SUMA_ROI_ACTION_STRUCT *ROIA;
07749    DListElmt *tmpStackPos=NULL;
07750    DList *list=NULL;
07751    
07752    SUMA_ENTRY;
07753    
07754    DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
07755    
07756    if (!DrawnROI) {
07757       SUMA_SLP_Err ("NO ROI to close.");
07758       SUMA_RETURNe;
07759    }
07760    
07761    if (DrawnROI->DrawStatus == SUMA_ROI_Finished) {
07762       SUMA_SLP_Err ("Cannot edit Finished ROI.");
07763       SUMA_RETURNe;
07764    }
07765    
07766    if (DrawnROI->Type != SUMA_ROI_OpenPath) {
07767       SUMA_SLP_Err ("You can only close an open path.");
07768       SUMA_RETURNe; 
07769    }
07770    
07771    SUMA_DRAWN_ROI_HEAD_NODE(DrawnROI,HeadNode);
07772    SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI,TailNode);
07773    
07774    /* get the third node, assuming it is along the normal of the TailNode */
07775    SO = SUMA_findSOp_inDOv(DrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv); 
07776    ThirdNode_v[0] = SO->NodeList[3*TailNode] + 20 *SO->NodeNormList[3*TailNode];
07777    ThirdNode_v[1] = SO->NodeList[3*TailNode+1] + 20 *SO->NodeNormList[3*TailNode+1];
07778    ThirdNode_v[2] = SO->NodeList[3*TailNode+2] + 20 *SO->NodeNormList[3*TailNode+2];
07779    
07780    /* No do the intersection */
07781    ROIstroke = SUMA_Surf_Plane_Intersect_ROI (SO, TailNode, HeadNode, ThirdNode_v);
07782    
07783    if (!ROIstroke) {
07784       SUMA_SLP_Err ("Failed to close path.\nTry closing with mouse.");
07785       SUMA_RETURNe;
07786    }
07787    
07788    /* what is the last node of ROIstroke ? 
07789    It is possible that the returned ROIstroke 
07790    was not a successful closure (a partial success), investigate*/
07791    if (LocalHead) fprintf(SUMA_STDERR, "%s: Last node of ROIstroke is %d\n", FuncName, ROIstroke->nPath[ROIstroke->N_n-1]); 
07792    if (ROIstroke->nPath[ROIstroke->N_n-1] != HeadNode) {
07793       /* Can't accept partials */
07794       SUMA_SLP_Err ("Failed to close path.\nTry closing with mouse.");
07795       SUMA_RETURNe;
07796    }
07797    
07798    /* looking good, add the thing */
07799    ROIstroke->action = SUMA_BSA_JoinEnds;
07800    ROIA = (SUMA_ROI_ACTION_STRUCT *) SUMA_malloc (sizeof(SUMA_ROI_ACTION_STRUCT)); /* this structure is freed in SUMA_DestroyROIActionData */
07801    ROIA->DrawnROI = DrawnROI;
07802    ROIA->ROId = ROIstroke;
07803    tmpStackPos = SUMA_PushActionStack (DrawnROI->ActionStack, DrawnROI->StackPos, SUMA_AddToTailJunctionROIDatum, (void *)ROIA, SUMA_DestroyROIActionData);
07804    if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
07805    else {
07806       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
07807       SUMA_RETURNe;
07808    }
07809    
07810    /* redisplay all others */
07811    if (!list) list = SUMA_CreateList ();
07812    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_RedisplayNow_AllVisible, SES_SumaWidget, NULL);
07813    SUMA_Engine (&list);
07814 
07815    SUMA_RETURNe;
07816 }
07817 
07818 void SUMA_cb_DrawROI_Finish (Widget w, XtPointer data, XtPointer client_data)
07819 {
07820    static char FuncName[]={"SUMA_cb_DrawROI_Finish"};
07821    SUMA_Boolean LocalHead = NOPE;
07822    SUMA_DRAWN_ROI *DrawnROI=NULL;
07823    SUMA_ROI_ACTION_STRUCT *ROIA;
07824    SUMA_SurfaceObject *SO = NULL;
07825    DListElmt *tmpStackPos=NULL;
07826    DList *list=NULL;
07827    
07828    SUMA_ENTRY;
07829    
07830    DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
07831    
07832    if (!DrawnROI) {
07833       SUMA_SLP_Err ("NO ROI to finish.");
07834       SUMA_RETURNe;
07835    }
07836    
07837    if (DrawnROI->DrawStatus == SUMA_ROI_Finished) {
07838       /* nothing to do */
07839       SUMA_RETURNe;
07840    }
07841    
07842    /* looking good, add the thing */
07843    ROIA = (SUMA_ROI_ACTION_STRUCT *) SUMA_malloc (sizeof(SUMA_ROI_ACTION_STRUCT)); /* this structure is freed in SUMA_DestroyROIActionData */
07844    ROIA->DrawnROI = DrawnROI;
07845    ROIA->ROId = NULL;
07846    tmpStackPos = SUMA_PushActionStack (DrawnROI->ActionStack, DrawnROI->StackPos, SUMA_FinishedROI, (void *)ROIA, SUMA_DestroyROIActionData);
07847    if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
07848    else {
07849       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
07850       SUMA_RETURNe;
07851    }
07852    
07853    SO = SUMA_findSOp_inDOv(DrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
07854    
07855    /* Now update the Paint job on the ROI plane */
07856    if (!SUMA_Paint_SO_ROIplanes_w (SO, SUMAg_DOv, SUMAg_N_DOv)) {
07857       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
07858       SUMA_RETURNe;
07859    }
07860    
07861    /* redisplay all others */
07862    if (!list) list = SUMA_CreateList ();
07863    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_SumaWidget, NULL);
07864    SUMA_Engine (&list);
07865 
07866    SUMA_RETURNe;
07867 }
07868 
07869 /*! 
07870    \brief Delete a drawn ROI 
07871    
07872 */
07873 void SUMA_cb_DrawROI_Delete(Widget wcall, XtPointer cd1, XtPointer cbs)
07874 {
07875    static char *PlaneName=NULL, FuncName[] = {"SUMA_cb_DrawROI_Delete"};
07876    XmPushButtonCallbackStruct * pbcbs = (XmPushButtonCallbackStruct *) cbs ;
07877    static int ErrCnt =0;
07878    DList *list=NULL;
07879    SUMA_SurfaceObject *SO=NULL;
07880    SUMA_Boolean LocalHead = NOPE;
07881    
07882    SUMA_ENTRY;
07883 
07884    if (!SUMAg_CF->X->DrawROI->curDrawnROI && wcall) { 
07885       /* remember, you'll always get the callback from the time out function
07886       the use of wcall in the condition above is to tell the difference between
07887       the timeout call and a delete request with a null curDrawnROI ...
07888       NULL curDrawnROI occurs normally such as when there are no ROI left */
07889       if (!ErrCnt) SUMA_SLP_Note ("No ROI to delete");
07890       wcall = NULL; /* use this to turn key back to lower case ahead */
07891       ErrCnt ++;
07892    }
07893    
07894    /* NULL widget --> reset button to lowercase */
07895    if( wcall == NULL ){
07896       if (LocalHead) fprintf (SUMA_STDERR, "%s: Resetting button.\n", FuncName); 
07897       if( SUMAg_CF->X->DrawROI->Delete_first == NOPE ){
07898          MCW_set_widget_label( SUMAg_CF->X->DrawROI->Delete_pb , "delete ROI" ) ;
07899          SUMAg_CF->X->DrawROI->Delete_first = YUP ;
07900       }
07901       SUMA_RETURNe ;
07902    }
07903    
07904    /* First press --> just change button label */
07905 
07906    if( SUMAg_CF->X->DrawROI->Delete_first ){
07907       MCW_set_widget_label( SUMAg_CF->X->DrawROI->Delete_pb  , "DELETE ROI" ) ;
07908       SUMAg_CF->X->DrawROI->Delete_first = NOPE ;
07909 
07910       /* if not re-pressed in 5 seconds, will reset to lowercase */
07911       if (LocalHead) fprintf (SUMA_STDERR, "%s: First Press, adding time out.\n", FuncName);
07912       (void) XtAppAddTimeOut(
07913                XtWidgetToApplicationContext(SUMAg_CF->X->DrawROI->Delete_pb) ,
07914                5000 , SUMA_delete_timeout_CB , NULL ) ;
07915 
07916        SUMA_RETURNe;
07917    }
07918    
07919    /* delete ROI */
07920    ErrCnt = 0;
07921    if (LocalHead) fprintf (SUMA_STDERR, "%s: Should be deleting ROI %s here ...\n", FuncName, SUMAg_CF->X->DrawROI->curDrawnROI->Label);
07922    
07923    /* preserve some info about ROI to be deleted */
07924    SO = SUMA_findSOp_inDOv(SUMAg_CF->X->DrawROI->curDrawnROI->Parent_idcode_str , SUMAg_DOv, SUMAg_N_DOv);
07925    PlaneName = SUMA_copy_string(SUMAg_CF->X->DrawROI->curDrawnROI->ColPlaneName);
07926    
07927    if (!SUMA_DeleteROI (SUMAg_CF->X->DrawROI->curDrawnROI)) {
07928       SUMA_SLP_Err("Failed to delete ROI");
07929       SUMA_RETURNe; 
07930    }
07931    
07932    /* If no other ROIs remain on the same plane as the deleted ROI, flush that plane's colors */
07933    SUMA_FlushPlaneNotInUse (PlaneName, SO, SUMAg_DOv, SUMAg_N_DOv);
07934    if (PlaneName) SUMA_free(PlaneName);
07935    
07936    /* Now update the Paint job on the ROI plane */
07937    if (!SUMA_Paint_SO_ROIplanes_w (
07938          SO, SUMAg_DOv, SUMAg_N_DOv)) {
07939       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
07940       SUMA_RETURNe;
07941    }
07942 
07943    /* redisplay */
07944    if (!list) list = SUMA_CreateList ();
07945    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_Suma, NULL); 
07946    if (!SUMA_Engine(&list)) SUMA_SLP_Err("Failed to redisplay.");
07947    
07948    /* reset the Delete button settings */
07949    MCW_set_widget_label( SUMAg_CF->X->DrawROI->Delete_pb , "delete ROI" ) ;   
07950    SUMA_RETURNe;
07951 }
07952 
07953 void SUMA_delete_timeout_CB( XtPointer client_data , XtIntervalId * id )
07954 {
07955    static char FuncName[] = {"SUMA_delete_timeout_CB"};
07956 
07957    SUMA_ENTRY;
07958 
07959    SUMA_cb_DrawROI_Delete(NULL, NULL, NULL);
07960 
07961    SUMA_RETURNe; 
07962 }
07963 
07964 /*!
07965    \brief saving the current ROI (stored in SUMAg_CF->X->DrawROI->curDrawnROI) to a niml format
07966 */
07967 void SUMA_cb_DrawROI_Save (Widget w, XtPointer data, XtPointer client_data)
07968 {
07969    static char FuncName[]={"SUMA_cb_DrawROI_Save"};
07970    SUMA_DRAWN_ROI *dROI=NULL;
07971    DList *list = NULL;
07972    SUMA_EngineData *ED = NULL;
07973    DListElmt *NextElm = NULL;
07974    SUMA_Boolean LocalHead = NOPE;
07975    
07976    SUMA_ENTRY;
07977    
07978    SUMA_LH("Called");
07979    
07980    dROI = SUMAg_CF->X->DrawROI->curDrawnROI;
07981    
07982    if (!dROI) {
07983       SUMA_LH("NULL ROI");
07984       SUMA_RETURNe;
07985    }
07986    
07987    if (!list) list = SUMA_CreateList();
07988    ED = SUMA_InitializeEngineListData (SE_SaveDrawnROIFileSelection);
07989    if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
07990                                           SEF_vp, NULL,
07991                                           SES_Suma, NULL, NOPE,
07992                                           SEI_Head, NULL))) {
07993       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
07994    }
07995    if (!SUMA_RegisterEngineListCommand (  list, ED,
07996                                           SEF_ip, (int *)w,
07997                                           SES_Suma, NULL, NOPE,
07998                                           SEI_In, NextElm)) {
07999       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
08000    }
08001    
08002    if (!SUMA_Engine (&list)) {
08003       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
08004    }
08005 
08006    SUMA_RETURNe;
08007 }
08008 
08009 void SUMA_cb_DrawROI_Load (Widget w, XtPointer data, XtPointer client_data)
08010 {
08011    static char FuncName[]={"SUMA_cb_DrawROI_Load"};
08012    DList *list = NULL;
08013    SUMA_EngineData *ED = NULL;
08014    DListElmt *NextElm = NULL;
08015    SUMA_Boolean LocalHead = NOPE;
08016    
08017    SUMA_ENTRY;
08018    
08019    if (!list) list = SUMA_CreateList();
08020    ED = SUMA_InitializeEngineListData (SE_OpenDrawnROIFileSelection);
08021    if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
08022                                           SEF_vp, NULL,
08023                                           SES_Suma, NULL, NOPE,
08024                                           SEI_Head, NULL))) {
08025       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
08026    }
08027    if (!SUMA_RegisterEngineListCommand (  list, ED,
08028                                           SEF_ip, (int *)w,
08029                                           SES_Suma, NULL, NOPE,
08030                                           SEI_In, NextElm)) {
08031       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
08032    }
08033    
08034    if (!SUMA_Engine (&list)) {
08035       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
08036    }
08037 
08038    SUMA_RETURNe;
08039 }
08040 
08041 void SUMA_DrawROI_NewLabel (void *data)
08042 {
08043    static char FuncName[]={"SUMA_DrawROI_NewLabel"};
08044    SUMA_DRAWN_ROI *DrawnROI=NULL;
08045    SUMA_ARROW_TEXT_FIELD * AF=NULL;
08046    void *n=NULL;
08047    static int ErrCnt=0;
08048    SUMA_Boolean Shaded = YUP;
08049    SUMA_Boolean LocalHead = NOPE;
08050    
08051    SUMA_ENTRY;
08052    
08053    AF = (SUMA_ARROW_TEXT_FIELD *)data;
08054    DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
08055    if (!DrawnROI) {
08056       SUMA_LH("Null DrawnROI");
08057       SUMA_RETURNe;
08058    }
08059    
08060    XtVaGetValues (AF->textfield, XmNvalue, &n, NULL);
08061    /* return if no change has been made */
08062    if (!strcmp((char *)n, DrawnROI->Label)) {
08063       SUMA_LH("No change");
08064       SUMA_LH((char *)n);
08065       SUMA_LH(DrawnROI->Label);
08066       SUMA_RETURNe;
08067    }
08068    
08069    if (DrawnROI->DrawStatus != SUMA_ROI_Finished) {
08070       SUMA_LH("unFinished");
08071       /* YOU DO NOT WANT TO FREE n because n is not a copy of the string in the widget! */
08072       if (DrawnROI->Label) {
08073          if (LocalHead) fprintf (SUMA_STDERR, "%s: Changing ROI label from %s to %s\n", FuncName, DrawnROI->Label, (char *)n);         
08074          DrawnROI->Label = (char *)SUMA_realloc(DrawnROI->Label, sizeof(char)*(strlen((char *)n)+1));
08075       }  else {
08076          if (LocalHead) fprintf (SUMA_STDERR, "%s: Setting ROI label to %s\n", FuncName, (char *)n);
08077          DrawnROI->Label = (char *)SUMA_malloc(sizeof(char) * (strlen((char *)n)+1));
08078       }
08079       DrawnROI->Label = strcpy(DrawnROI->Label, (char *)n);   
08080       ErrCnt = 0;
08081       
08082       /* check if list window is open and update it if need be */
08083       SUMA_IS_DRAW_ROI_SWITCH_ROI_SHADED(Shaded);
08084       if (!Shaded) {
08085          if (LocalHead) fprintf (SUMA_STDERR, "%s: updating switch ROI window ...\n", FuncName);
08086          SUMA_cb_DrawROI_SwitchROI(NULL, (XtPointer) SUMAg_CF->X->DrawROI->SwitchROIlst, NULL);
08087       }
08088    } else {
08089       SUMA_LH("Finished");
08090       if (!ErrCnt) SUMA_SLP_Err("ROI maked as finished.\nNew label cannot be applied.");
08091       ++ErrCnt;
08092       SUMA_SET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIlbl->textfield, DrawnROI->Label);
08093    }
08094    
08095    SUMA_RETURNe;
08096 }
08097 
08098 void SUMA_WidgetResize (Widget New, int width, int height)
08099 {
08100    static char FuncName[]={"SUMA_WidgetResize"};
08101    
08102    SUMA_ENTRY;
08103    
08104    XtVaSetValues (New,
08105       XmNwidth, width,
08106       XmNheight, height,
08107       NULL);
08108    SUMA_RETURNe;
08109 }
08110 /*!
08111    \brief Positions a new widget relative to a reference widget 
08112    SUMA_PositionWindowRelative ( New,  Ref,  Loc);
08113    
08114    \param New (Widget) the widget to place
08115    \param Ref (Widget) the widget relative to which New is placed (could pass NULL if positioning relative to pointer)
08116    \param Loc (SUMA_WINDOW_POSITION) the position of New relative to Ref
08117 */
08118 void SUMA_PositionWindowRelative (Widget New, Widget Ref, SUMA_WINDOW_POSITION Loc)
08119 {
08120    static char FuncName[]={"SUMA_PositionWindowRelative"};
08121    Position RefX, RefY, NewX, NewY, Dx=5;
08122    Dimension RefW, RefH, ScrW, ScrH, NewW, NewH;
08123    SUMA_Boolean LocalHead=NOPE;
08124    
08125    SUMA_ENTRY;
08126    
08127    if (!New) { SUMA_RETURNe; }
08128    
08129    ScrW = WidthOfScreen (XtScreen(New));
08130    ScrH = HeightOfScreen (XtScreen(New));
08131    
08132    SUMA_LH("Getting New Positions");
08133    XtVaGetValues (New,           /* get the positions of New */
08134          XmNwidth, &NewW,
08135          XmNheight, &NewH,
08136          XmNx, &NewX,
08137          XmNy, &NewY,
08138          NULL);
08139 
08140    if (Ref) { /* get the positions of Ref */
08141       SUMA_LH("Getting Ref Positions");
08142       XtVaGetValues (Ref,
08143          XmNwidth, &RefW,
08144          XmNheight, &RefH,
08145          XmNx, &RefX,
08146          XmNy, &RefY,
08147          NULL);
08148    } else {
08149       if (LocalHead) fprintf(SUMA_STDERR, "%s: NULL Ref.\n", FuncName);
08150       RefX = 10;
08151       RefY = 10;
08152       RefW = 0;
08153       RefH = 0;
08154    }
08155    
08156    switch (Loc) {
08157       case SWP_BOTTOM_RIGHT_CORNER:
08158          NewX = RefW + RefX;
08159          NewY = RefH + RefY;
08160          break; 
08161       case SWP_TOP_RIGHT:
08162          NewX = RefW + RefX + Dx;
08163          NewY = RefY;
08164          break;
08165       case SWP_TOP_LEFT:
08166          NewX = RefW + Dx;
08167          NewY = RefY;
08168          break;
08169       case SWP_POINTER:
08170          {
08171             Window root, child, wind;
08172             int root_x, root_y, win_x, win_y;
08173             unsigned int keys_buttons;
08174             SUMA_LH("Pointer Query 1");
08175             if (!XtIsRealized(New)) {
08176                SUMA_LH("Need new wind");
08177                if (!XtIsRealized(SUMAg_SVv[0].X->GLXAREA)) {
08178                   SUMA_SL_Err("Nothing to work with here!");
08179                   SUMA_RETURNe;
08180                }
08181                wind = XtWindow(SUMAg_SVv[0].X->GLXAREA);
08182             } else {
08183                wind = XtWindow(New);
08184             }
08185             XQueryPointer(XtDisplay(New), wind, &root, &child, &root_x, &root_y, &win_x, &win_y, &keys_buttons);
08186             NewX = root_x;
08187             NewY = root_y;
08188          }
08189          break;
08190       case SWP_POINTER_OFF:
08191          {
08192             Window root, child, wind;
08193             int root_x, root_y, win_x, win_y;
08194             unsigned int keys_buttons;
08195             SUMA_LH("Pointer Query 2");
08196             if (!XtIsRealized(New)) {
08197                SUMA_LH("Need new wind");
08198                if (!XtIsRealized(SUMAg_SVv[0].X->GLXAREA)) {
08199                   SUMA_SL_Err("Nothing to work with here!");
08200                   SUMA_RETURNe;
08201                }
08202                wind = XtWindow(SUMAg_SVv[0].X->GLXAREA);
08203             } else {
08204                wind = XtWindow(New);
08205             }
08206             XQueryPointer(XtDisplay(New), wind, &root, &child, &root_x, &root_y, &win_x, &win_y, &keys_buttons);
08207             NewX = root_x - (int)NewW/2;
08208             NewY = root_y - (int)NewH + Dx;
08209          }
08210          break;
08211             
08212       default:
08213          fprintf (SUMA_STDERR, "Error %s: Option not known.\n", FuncName);
08214          SUMA_RETURNe;
08215          break;
08216    }
08217 
08218    
08219    if (NewX >= ScrW || NewX < 0) NewX = 50;
08220    if (NewY >= ScrH || NewY < 0) NewY = 50;
08221    
08222    if (LocalHead) fprintf (SUMA_STDERR, "%s: Positioning window at %d %d\n", FuncName, NewX, NewY);
08223    XtVaSetValues (New,
08224       XmNx, NewX,
08225       XmNy, NewY,
08226       NULL);
08227       
08228    SUMA_RETURNe;
08229 }
08230 
08231 /*** Functions to follow taken from editor_dnd.c example code 
08232  * Written by Paula Ferguson.  
08233  * Copyright 1994, O'Reilly & Associates, Inc.
08234  * Permission to use, copy, and modify this program without
08235  * restriction is hereby granted, as long as this copyright
08236  * notice appears in each copy of the program source code.
08237  * This program is freely distributable without licensing fees and
08238  * is provided without guarantee or warrantee expressed or implied.
08239  * This program is -not- in the public domain.
08240  */
08241  
08242 /*!
08243    \brief function to allocate and initialize a prompt dialogue structure
08244    
08245    \param Mode (SUMA_PROMPT_MODE) type of action area buttons desired
08246    \param init_selection (char *) the original value to set the text_field to
08247    \param daddy (Widget) the parent widget of the dialog
08248    \param preserve (SUMA_Boolean) if YUP then do not destroy widget and structure after use
08249    \param Return_button (SUMA_PROMPT_BUTTONS) make return (enter) in the text field
08250       mimick button Return_button (usually SUMA_OK_BUTTON OR SUMA_APPLY_BUTTON)
08251    \param SelectCallback 
08252    \param SelectData
08253    \param CancelCallback
08254    \param CancelData
08255    \param HelpCallback
08256    \param HelpData
08257    \param oprmpt (SUMA_PROMPT_DIALOG_STRUCT *) the structure to reuse. 
08258                   Use in conjuction with preserve=YUP
08259                   
08260    \sa warnings in SUMA_CreateFileSelectionDialogStruct
08261 */
08262 SUMA_PROMPT_DIALOG_STRUCT *SUMA_CreatePromptDialogStruct (SUMA_PROMPT_MODE Mode, char *TextFieldLabel, 
08263                                                          char *init_selection, 
08264                                                          Widget daddy, SUMA_Boolean preserve,
08265                                                          SUMA_PROMPT_BUTTONS Return_button,
08266                                                          void(*SelectCallback)(char *selection, void *data), void *SelectData,
08267                                                          void(*CancelCallback)(void *data), void *CancelData,
08268                                                          void(*HelpCallback)(void *data), void *HelpData,
08269                                                          int(*VerifyFunction)(char *selection, void *data), void *VerifyData,
08270                                                          SUMA_PROMPT_DIALOG_STRUCT *oprmpt)
08271 {
08272    static char FuncName[]={"SUMA_CreatePromptDialogStruct"};
08273    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08274    SUMA_Boolean LocalHead = NOPE;
08275     
08276    SUMA_ENTRY;
08277    
08278    if (!oprmpt) {
08279       SUMA_LH ("New prompt structure");
08280       prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)SUMA_malloc(sizeof(SUMA_PROMPT_DIALOG_STRUCT));
08281       if (!prmpt) {
08282          SUMA_SLP_Crit("Failed to allocate for prmpt");
08283          SUMA_RETURN(prmpt);
08284       }
08285       prmpt->daddy = daddy;
08286       prmpt->dialog = NULL;
08287       prmpt->pane = NULL;
08288       prmpt->text_w = NULL;
08289       prmpt->Mode = Mode;
08290    } else {
08291       SUMA_LH("Refitting old prompt structure.");
08292       prmpt = oprmpt;
08293       if (!preserve) SUMA_SLP_Warn("You should not be reusing\na prmpt structure along with\nthe Preserve flag on.");
08294       if (Mode != prmpt->Mode) SUMA_SLP_Warn("You cannot be reusing\na prmpt structure and change its mode.");
08295       if (prmpt->selection) SUMA_free(prmpt->selection);
08296       if (prmpt->label) SUMA_free(prmpt->label);
08297    }   
08298    
08299    prmpt->SelectCallback = SelectCallback;
08300    prmpt->SelectData = SelectData;
08301    prmpt->CancelCallback = CancelCallback;
08302    prmpt->CancelData = CancelData;
08303    prmpt->HelpCallback = HelpCallback;
08304    prmpt->HelpData = HelpData;
08305    prmpt->default_button = Return_button;
08306    prmpt->VerifyFunction = VerifyFunction;
08307    prmpt->VerifyData = VerifyData;
08308    
08309    if (init_selection) {
08310       prmpt->selection = (char *)SUMA_calloc(strlen(init_selection)+1, sizeof(char));
08311       prmpt->selection = strcpy(prmpt->selection, init_selection);
08312    }else {
08313       prmpt->selection = NULL;
08314    }
08315    if (TextFieldLabel) {
08316       prmpt->label = (char *)SUMA_calloc(strlen(TextFieldLabel)+1, sizeof(char));
08317       prmpt->label = strcpy(prmpt->label, TextFieldLabel);
08318    }else {
08319       prmpt->label = NULL;
08320    }
08321    prmpt->preserve = preserve;
08322    
08323    SUMA_RETURN(prmpt);
08324 }
08325 
08326 /*!
08327    \brief function to open a prompt 
08328 */
08329 SUMA_PROMPT_DIALOG_STRUCT *SUMA_CreatePromptDialog(char *title_extension, SUMA_PROMPT_DIALOG_STRUCT *prmpt)
08330 {
08331    static char FuncName[]={"SUMA_CreatePromptDialog"};
08332    Widget rc;
08333    XmString string;
08334    SUMA_Boolean LocalHead = NOPE;
08335 
08336    SUMA_ENTRY;
08337 
08338    if (!prmpt->dialog) {
08339       SUMA_LH ("Creating new prompt dialog.");
08340       /* The DialogShell is the Shell for this dialog.  Set it up so
08341       * that the "Close" button in the window manager's system menu
08342       * destroys the shell (it only unmaps it by default).
08343       */
08344       prmpt->dialog= XtVaCreatePopupShell ("dialog",
08345         xmDialogShellWidgetClass, prmpt->daddy,
08346         XmNtitle,  title_extension,     /* give arbitrary title in wm */
08347         XmNdeleteResponse, XmDO_NOTHING,  /* Unmap is the default and it is the best, 
08348                                              by I can't get an unmap callback for
08349                                              the stupid dialog shell. 
08350                                           */
08351         NULL);
08352       
08353       /* handle the close button from window manager */
08354       XmAddWMProtocolCallback(/* make "Close" window menu work */
08355          prmpt->dialog,
08356          XmInternAtom( XtDisplay(prmpt->dialog) , "WM_DELETE_WINDOW" , False ) ,
08357          SUMA_PromptUnmap_cb, (XtPointer) prmpt) ;
08358       
08359       
08360       /* Create the paned window as a child of the dialog.  This will
08361       * contain the control area and the action area
08362       * (created by CreateActionArea() using the action_items above).
08363       */
08364       prmpt->pane = XtVaCreateWidget ("pane", xmPanedWindowWidgetClass, prmpt->dialog,
08365         XmNsashWidth,  1,
08366         XmNsashHeight, 1,
08367         NULL);
08368 
08369       /* create the control area which contains a
08370       * Label gadget and a TextField widget.
08371       */
08372       rc = XtVaCreateWidget ("control_area", xmRowColumnWidgetClass, prmpt->pane, NULL);
08373       string = XmStringCreateLocalized (prmpt->label);
08374       XtVaCreateManagedWidget ("label", xmLabelWidgetClass, rc,
08375         XmNlabelString,    string,
08376         NULL);
08377       XmStringFree (string);
08378 
08379       prmpt->text_w = XtVaCreateManagedWidget ("text-field",
08380         xmTextFieldWidgetClass, rc, 
08381         NULL);
08382       
08383       if (prmpt->selection) {
08384          XtVaSetValues(prmpt->text_w, 
08385             XmNvalue, prmpt->selection,
08386             NULL);
08387       }
08388 
08389       /* add a callback for the return in the text-field widget */
08390       XtAddCallback (prmpt->text_w, XmNactivateCallback, SUMA_PromptActivate_cb, (XtPointer)prmpt);
08391       
08392       /* RowColumn is full -- now manage */
08393       XtManageChild (rc);
08394       
08395       
08396       /* Now create the action area */
08397       if (!SUMA_CreatePromptActionArea (prmpt)){
08398          SUMA_SLP_Crit("Failed to create action area.");
08399          SUMA_RETURN(NULL);
08400       }
08401       
08402       
08403        XtManageChild (prmpt->actionarea);
08404        XtManageChild (prmpt->pane);
08405        XtPopup (prmpt->dialog, XtGrabNone);
08406    }else {
08407       SUMA_LH ("bringing back old prompt dialog.");
08408       XtManageChild (prmpt->dialog);
08409       /* make sure that dialog is raised to top of window stack */
08410       /* 
08411          For some reason, the next line fails after opening the prompt more
08412          than twice!
08413          
08414          XMapRaised (XtDisplay (prmpt->dialog), XtWindow (XtParent (prmpt->dialog)));
08415          
08416          For some other reason, the following line works although it should be done by default
08417          when a widget is managed. ZSS May 14 03*/
08418       XtMapWidget (prmpt->dialog);
08419    }
08420    
08421    SUMA_RETURN(prmpt);
08422 }
08423 
08424 /*!
08425    \brief function to create the action area of the prompt 
08426 */
08427 #define TIGHTNESS 20
08428 const char * SUMA_PromptButtonLabel(SUMA_PROMPT_BUTTONS code)
08429 {
08430    static char FuncName[]={"SUMA_CommandString"};
08431    
08432    SUMA_ENTRY;
08433    
08434    switch (code) {
08435       case SUMA_OK_BUTTON:
08436          SUMA_RETURN("OK");
08437       case SUMA_CLEAR_BUTTON:
08438          SUMA_RETURN("Clear");
08439       case SUMA_CANCEL_BUTTON:
08440          SUMA_RETURN("Cancel");
08441       case SUMA_HELP_BUTTON:
08442          SUMA_RETURN("Help");
08443       case SUMA_APPLY_BUTTON:
08444          SUMA_RETURN("Apply");
08445       default:
08446          SUMA_RETURN("BAD BAD BAD.");
08447    }
08448    SUMA_RETURN("This cannot be.");
08449 }
08450 
08451 SUMA_Boolean SUMA_CreatePromptActionArea (SUMA_PROMPT_DIALOG_STRUCT *prmpt)
08452 {
08453    static char FuncName[]={"SUMA_CreatePromptActionArea"};
08454    int i, num_actions;
08455    Widget widget=NULL;
08456    SUMA_Boolean DoButt[SUMA_N_PROMPT_BUTTONS];
08457    SUMA_Boolean LocalHead = NOPE;
08458    
08459    SUMA_ENTRY;
08460 
08461    SUMA_LH ("Called");
08462    /* initialize DoButt */
08463    for (i=0; i < SUMA_N_PROMPT_BUTTONS; ++i) DoButt[i]=NOPE;
08464    
08465    /* Now set the flags for building the action area */
08466    num_actions = 0;
08467    switch (prmpt->Mode) {
08468       case SUMA_OK:
08469          DoButt[SUMA_OK_BUTTON] = YUP;
08470          num_actions = 1;
08471          break;
08472       case SUMA_OK_HELP:
08473          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_HELP_BUTTON] = YUP;
08474          num_actions = 2;
08475          break;
08476       case SUMA_OK_CANCEL:
08477          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = YUP;
08478          num_actions = 2;
08479          break;
08480       case SUMA_OK_CANCEL_HELP:
08481          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = 
08482          DoButt[SUMA_HELP_BUTTON] = YUP;
08483          num_actions = 3;
08484          break;               
08485       case SUMA_OK_CLEAR_CANCEL:
08486          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = 
08487          DoButt[SUMA_CLEAR_BUTTON] = YUP;
08488          num_actions = 3;
08489          break;
08490       case SUMA_OK_CLEAR_CANCEL_HELP:
08491          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = 
08492          DoButt[SUMA_CLEAR_BUTTON] = DoButt[SUMA_HELP_BUTTON] = YUP;
08493          num_actions = 4;
08494          break;
08495       case SUMA_OK_APPLY_CANCEL:
08496          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = 
08497          DoButt[SUMA_APPLY_BUTTON] = YUP;
08498          num_actions = 3;
08499          break;
08500       case SUMA_OK_APPLY_CANCEL_HELP:
08501          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = 
08502          DoButt[SUMA_APPLY_BUTTON] = DoButt[SUMA_HELP_BUTTON] = YUP;
08503          num_actions = 4;
08504          break;
08505       case SUMA_OK_APPLY_CLEAR_CANCEL:
08506          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = 
08507          DoButt[SUMA_APPLY_BUTTON] = DoButt[SUMA_CLEAR_BUTTON] = YUP;
08508          num_actions = 4;
08509          break;
08510       case SUMA_OK_APPLY_CLEAR_CANCEL_HELP:
08511          DoButt[SUMA_OK_BUTTON] = DoButt[SUMA_CANCEL_BUTTON] = 
08512          DoButt[SUMA_APPLY_BUTTON] = DoButt[SUMA_CLEAR_BUTTON] = 
08513          DoButt[SUMA_HELP_BUTTON] = YUP;
08514          num_actions = 5;
08515          break;
08516       default:
08517          SUMA_SL_Err("Bad prompt mode.");
08518          SUMA_RETURN(NOPE);
08519          break;
08520    }
08521 
08522    prmpt->actionarea = XtVaCreateWidget ("action_area", xmFormWidgetClass, prmpt->pane,
08523         XmNfractionBase, TIGHTNESS*num_actions - 1,
08524         XmNleftOffset,   10,
08525         XmNrightOffset,  10,
08526         NULL);
08527         
08528    /* create the buttons */
08529    for (i=0; i< SUMA_N_PROMPT_BUTTONS; ++i) {
08530       if (DoButt[i]) {
08531          widget = XtVaCreateManagedWidget (SUMA_PromptButtonLabel(i),
08532             xmPushButtonWidgetClass, prmpt->actionarea,
08533             XmNleftAttachment,       i? XmATTACH_POSITION : XmATTACH_FORM,
08534             XmNleftPosition,         TIGHTNESS*i,
08535             XmNtopAttachment,        XmATTACH_FORM,
08536             XmNbottomAttachment,     XmATTACH_FORM,
08537             XmNrightAttachment,
08538                 i != num_actions - 1 ? XmATTACH_POSITION : XmATTACH_FORM,
08539             XmNrightPosition,        TIGHTNESS * i + (TIGHTNESS - 1),
08540             XmNshowAsDefault,        i == 0, 
08541             XmNdefaultButtonShadowThickness, 1, 
08542             NULL);      
08543       }
08544       if (i == prmpt->default_button) {
08545          /* Set the action_area's default button  Also, set the
08546           * pane window constraint for max and min heights so this
08547           * particular pane in the PanedWindow is not resizable.
08548           */
08549          Dimension height, h;
08550          XtVaGetValues (prmpt->actionarea, XmNmarginHeight, &h, NULL);
08551          XtVaGetValues (widget, XmNheight, &height, NULL);
08552          height += 2 * h;
08553          XtVaSetValues (prmpt->actionarea,
08554              XmNdefaultButton, widget,
08555              XmNpaneMaximum,   height,
08556              XmNpaneMinimum,   height,
08557              NULL);
08558       }
08559 
08560       /* Now set the callbacks */
08561       switch (i) {
08562          case SUMA_OK_BUTTON:
08563             XtAddCallback (widget, XmNactivateCallback, SUMA_PromptOk_cb, (XtPointer)prmpt);
08564             break;
08565          case SUMA_CLEAR_BUTTON:
08566             XtAddCallback (widget, XmNactivateCallback, SUMA_PromptClear_cb, (XtPointer)prmpt);
08567             break;
08568          case SUMA_CANCEL_BUTTON:
08569             XtAddCallback (widget, XmNactivateCallback, SUMA_PromptCancel_cb, (XtPointer)prmpt);
08570             break;
08571          case SUMA_APPLY_BUTTON:
08572             XtAddCallback (widget, XmNactivateCallback, SUMA_PromptApply_cb, (XtPointer)prmpt);
08573             break;
08574          case SUMA_HELP_BUTTON:
08575             XtAddCallback (widget, XmNactivateCallback, SUMA_PromptHelp_cb, (XtPointer)prmpt);
08576             break;
08577          default:
08578             SUMA_SL_Err("Bad action area button label");
08579             break;
08580       }   
08581    }
08582    
08583    SUMA_RETURN(YUP);
08584 }
08585 
08586 /*!
08587    \brief Called when prompt dialog is being unmapped.
08588    This happens when users enter a selection, hit cancel or hit the kill button on the window 
08589 
08590    -expects a SUMA_PROMPT_DIALOG_STRUCT *in data
08591 
08592 */
08593 void SUMA_PromptUnmap_cb (Widget w, XtPointer data, XtPointer calldata)
08594 {
08595    static char FuncName[]={"SUMA_PromptUnmap_cb"};
08596    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08597    SUMA_Boolean LocalHead = NOPE;
08598       
08599    SUMA_ENTRY;
08600    
08601    SUMA_LH("Called");
08602    
08603    prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)data;
08604    
08605    /* if preservation is not required, kill the widget and free dlg */
08606    if (!prmpt->preserve) {
08607       if (prmpt->dialog) {
08608          SUMA_LH("Destroying prompt");
08609          XtDestroyWidget(prmpt->dialog); 
08610       }else {
08611          SUMA_SL_Warn("prmpt->dialog is null.\nThis should not be.");
08612       }
08613       
08614       /* now free the structure */
08615       SUMA_FreePromptDialogStruct(prmpt);
08616       
08617    }else {
08618       SUMA_LH("Preserving prompt");
08619       XtUnmapWidget (prmpt->dialog); 
08620    }   
08621    
08622    SUMA_RETURNe;
08623 }
08624 
08625 /*!
08626    \brief Call from Activate button in prompt dialog
08627    
08628    -expects a SUMA_PROMPT_DIALOG_STRUCT *in data
08629 */
08630 void SUMA_PromptActivate_cb (Widget w, XtPointer data, XtPointer calldata)
08631 {
08632    static char FuncName[]={"SUMA_PromptActivate_cb"};
08633    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) calldata;
08634    Widget dflt;
08635    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08636    SUMA_Boolean LocalHead = NOPE;
08637       
08638    SUMA_ENTRY;
08639    
08640    SUMA_LH("Called");
08641    
08642    prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)data;
08643    
08644    /* get the "default button" from the action area... */
08645     XtVaGetValues (prmpt->actionarea, XmNdefaultButton, &dflt, NULL);
08646     if (dflt) /* sanity check -- this better work */
08647         /* make the default button think it got pushed using
08648          * XtCallActionProc().  This function causes the button
08649          * to appear to be activated as if the user pressed it.
08650          */
08651         XtCallActionProc (dflt, "ArmAndActivate", cbs->event, NULL, 0);
08652    
08653    
08654    SUMA_RETURNe;
08655 }
08656 
08657 /*!
08658    \brief Call from Ok button in prompt dialog
08659    
08660    -expects a SUMA_PROMPT_DIALOG_STRUCT *in data
08661 */
08662 void SUMA_PromptOk_cb (Widget w, XtPointer data, XtPointer calldata)
08663 {
08664    static char FuncName[]={"SUMA_PromptOk_cb"};
08665    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08666    SUMA_Boolean LocalHead = NOPE;
08667       
08668    SUMA_ENTRY;
08669    
08670    SUMA_LH("Called");
08671 
08672    prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)data;
08673    
08674    /* apply first */
08675    SUMA_PromptApply_cb (w, data, calldata);
08676 
08677    /* close window */
08678    SUMA_PromptUnmap_cb (w, data, calldata);
08679    
08680    SUMA_RETURNe;
08681 }
08682 
08683 /*!
08684    \brief Call from Clear button in prompt dialog
08685    
08686    -expects a SUMA_PROMPT_DIALOG_STRUCT *in data
08687 */
08688 void SUMA_PromptClear_cb (Widget w, XtPointer data, XtPointer calldata)
08689 {
08690    static char FuncName[]={"SUMA_PromptClear_cb"};
08691    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08692    SUMA_Boolean LocalHead = NOPE;
08693       
08694    SUMA_ENTRY;
08695    
08696    SUMA_LH("Called");
08697    
08698    prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)data;
08699   
08700    XmTextFieldSetString (prmpt->text_w, "");
08701    
08702    SUMA_RETURNe;
08703 }
08704 
08705 /*!
08706    \brief Call from Apply button in prompt dialog
08707    
08708    -expects a SUMA_PROMPT_DIALOG_STRUCT *in data
08709 */
08710 void SUMA_PromptApply_cb (Widget w, XtPointer data, XtPointer calldata)
08711 {
08712    static char FuncName[]={"SUMA_PromptApply_cb"};
08713    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08714    char *text=NULL;
08715    SUMA_Boolean LocalHead = NOPE;
08716       
08717    SUMA_ENTRY;
08718    
08719    SUMA_LH("Called");
08720    
08721    prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)data;
08722    
08723    text = XmTextFieldGetString (prmpt->text_w);
08724    
08725    if (prmpt->selection) SUMA_free(prmpt->selection);
08726    if (text[0]) { 
08727       prmpt->selection = (char *)SUMA_calloc(strlen(text)+1,sizeof(char));
08728       prmpt->selection = strcpy(prmpt->selection, text);
08729    }else {
08730       prmpt->selection = NULL;
08731    }
08732    XtFree (text);
08733    
08734    if (LocalHead) fprintf (SUMA_STDERR, "%s: Read %s\n", FuncName, prmpt->selection);
08735 
08736    /* verify the input */
08737    if (prmpt->VerifyFunction) {
08738       if (!prmpt->VerifyFunction(prmpt->selection, prmpt->VerifyData)) {
08739          SUMA_SLP_Err("Gibberish! try again.\nSyntax error or wrong\nnumber/type of arguments.");
08740          SUMA_RETURNe;
08741       }
08742    }
08743    
08744    /* do your selectcallback */
08745    if (prmpt->SelectCallback) {
08746       prmpt->SelectCallback (prmpt->selection, prmpt->SelectData);
08747    }
08748    
08749    
08750    SUMA_RETURNe;
08751 }
08752 
08753 /*!
08754    \brief Call from Cancel button in prompt dialog
08755    
08756    -expects a SUMA_PROMPT_DIALOG_STRUCT *in data
08757 */
08758 void SUMA_PromptCancel_cb (Widget w, XtPointer data, XtPointer calldata)
08759 {
08760    static char FuncName[]={"SUMA_PromptCancel_cb"};
08761    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08762    SUMA_Boolean LocalHead = NOPE;
08763       
08764    SUMA_ENTRY;
08765    
08766    SUMA_LH("Called");
08767    
08768    prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)data;
08769    
08770    /* do your cancelcallback */
08771    if (prmpt->CancelCallback) {
08772       prmpt->CancelCallback (prmpt->CancelData);
08773    }
08774    
08775    /* close window */
08776    SUMA_PromptUnmap_cb (w, data, calldata);
08777 
08778    SUMA_RETURNe;
08779 }
08780 
08781 /*!
08782    \brief Call from Help button in prompt dialog
08783    
08784    -expects a SUMA_PROMPT_DIALOG_STRUCT *in data
08785 */
08786 void SUMA_PromptHelp_cb (Widget w, XtPointer data, XtPointer calldata)
08787 {
08788    static char FuncName[]={"SUMA_PromptHelp_cb"};
08789    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL;
08790    SUMA_Boolean LocalHead = NOPE;
08791       
08792    SUMA_ENTRY;
08793    
08794    SUMA_LH("Called");
08795    
08796    prmpt = (SUMA_PROMPT_DIALOG_STRUCT *)data;
08797    
08798    /* do your helpcallback */
08799    if (prmpt->HelpCallback) {
08800       prmpt->HelpCallback (prmpt->HelpData);
08801    }
08802    
08803    SUMA_RETURNe;
08804 }
08805 
08806 /*!
08807    \brief frees prompt dialog structure. 
08808    It does not destroy the widget for the dialog, that should be done
08809    before this function is called.
08810    
08811 */
08812 void SUMA_FreePromptDialogStruct(SUMA_PROMPT_DIALOG_STRUCT *prmpt)
08813 {
08814    static char FuncName[]={"SUMA_FreePromptDialogStruct"};
08815    SUMA_Boolean LocalHead = NOPE;
08816    
08817    SUMA_ENTRY;
08818    SUMA_LH("Called");
08819    
08820    if (!prmpt) SUMA_RETURNe;
08821    
08822    /* now free structure */
08823    if (prmpt->selection) SUMA_free(prmpt->selection);
08824    if (prmpt->label) SUMA_free(prmpt->label); 
08825    SUMA_free(prmpt);
08826    
08827    SUMA_RETURNe;
08828 }
08829 
08830 /*!
08831    \brief function to allocate and initialize a file selection dialogue structure
08832    
08833    \param parent (Widget) parent widget of dialog
08834    \param Mode (SUMA_FILE_SELECT_MODE) : SUMA_OPEN_FILE, SUMA_SAVE_FILE
08835    \param preserve (SUMA_Boolean) YUP: keep dialog widget and structure after closing.
08836                                     see notes in structure's definition for more help.
08837    \param SelectCallback(char *filename, void *data) (void*): Function to call when selection is made
08838    \param SelectData (void *) data to pass SelectCallback
08839    \param CancelCallback(void *data) (void*): Function to call when cancel is pressed
08840    \param CancelData (void *) data to pass CancelCallback
08841    \param FilePattern (char *) pattern to use as initial file filter.
08842             FilePattern is copied so you should handle freeing it if necessary.
08843             If FilePattern = NULL then the one that was used last is preserved.
08844    \param odlg (SUMA_SELECTION_DIALOG_STRUCT *) if not null, then instead of 
08845             creating a new structure, the function will update the fields in 
08846             odlg. This is useful if you want to reuse a dialog's widget (preserve = YUP)
08847             but with different callbacks and calldata.
08848             NOTE: parent cannot be changed if you are updating odlg.
08849             NOTE: DO NOT USE preserve = YUP along with non-NULL odlg. It does not make sense
08850             and I can't easily make this fool proof.
08851    \return dlg_strct (SUMA_SELECTION_DIALOG_STRUCT *) an allocated and initialized dialogue struct
08852                or an updated odlg if specified. 
08853     
08854    -You might have to add a trap for the kill button, if possible, else you need to trap for the kill with
08855    a callback to set the widget to null.
08856    
08857    See SUMA_DestroyTextShell
08858 */
08859 SUMA_SELECTION_DIALOG_STRUCT *SUMA_CreateFileSelectionDialogStruct (Widget daddy, SUMA_FILE_SELECT_MODE Mode, SUMA_Boolean preserve,
08860                                                                   void (*SelectCallback)(char *filename, void *data), void *SelectData,
08861                                                                   void (*CancelCallback)(void *data), void *CancelData,
08862                                                                   char *FilePattern,
08863                                                                   SUMA_SELECTION_DIALOG_STRUCT *odlg)
08864 {
08865    static char FuncName[]={"SUMA_CreateFileSelectionDialogStruct"};
08866    SUMA_SELECTION_DIALOG_STRUCT * dlg = NULL;
08867    SUMA_Boolean LocalHead = NOPE;
08868    
08869    SUMA_ENTRY;
08870    
08871    if (!odlg) { /* new structure */
08872       SUMA_LH("A new structure ");    
08873       dlg = (SUMA_SELECTION_DIALOG_STRUCT *)SUMA_malloc(sizeof(SUMA_SELECTION_DIALOG_STRUCT));
08874       if (!dlg) {
08875          fprintf (SUMA_STDERR, "Error %s: Failed to allocate for TextShell.\n", FuncName);
08876          SUMA_RETURN (NULL);
08877       }
08878       dlg->dlg_w = NULL;
08879       dlg->FilePattern = NULL;
08880    }else {
08881       SUMA_LH("Refitting old one. ");
08882       if (!preserve) 
08883          SUMA_SLP_Warn("You should not be reusing\na dlg structure along with\nthe Preserve flag on.");
08884       dlg = odlg;
08885       if (dlg->filename) {
08886          SUMA_LH("Freeing dlg->filename");
08887          SUMA_free(dlg->filename);
08888       }
08889    }
08890    
08891    dlg->daddy = daddy; 
08892    dlg->filename = NULL;
08893    dlg->Mode = Mode;
08894    dlg->SelectCallback = SelectCallback;
08895    dlg->SelectData = SelectData;
08896    dlg->CancelCallback = CancelCallback;
08897    dlg->CancelData = CancelData;
08898    dlg->preserve = preserve;
08899    
08900    if (FilePattern) {
08901       /* new one specified, destroy the old one */
08902       if (dlg->FilePattern) {
08903          SUMA_LH("Freeing dlg->FilePattern");
08904          SUMA_free(dlg->FilePattern);
08905       }   
08906       dlg->FilePattern = SUMA_copy_string (FilePattern);
08907    }
08908    
08909    SUMA_RETURN(dlg);
08910 }
08911 
08912 /*!
08913    \brief, opens a file selection dialogue
08914    
08915    \param title (char *) title of window
08916    \param dlg (SUMA_SELECTION_DIALOG_STRUCT **) pointer to structure created and initialized by SUMA_CreateFileSelectionDialogStruct
08917 */                                                            
08918 SUMA_SELECTION_DIALOG_STRUCT *SUMA_CreateFileSelectionDialog (char *title_extension, SUMA_SELECTION_DIALOG_STRUCT **dlgp)
08919 {
08920    static char FuncName[]={"SUMA_CreateFileSelectionDialog"};
08921    SUMA_Boolean LocalHead = NOPE;
08922    SUMA_SELECTION_DIALOG_STRUCT *dlg = NULL;
08923    XmString button, title, pattern;
08924 
08925    SUMA_ENTRY;
08926    
08927    dlg = *dlgp;   
08928    if (!dlg->dlg_w) {/* need to create it for the first time */
08929       SUMA_LH ("Creating new file selection window.");
08930       dlg->dlg_w = XmCreateFileSelectionDialog (dlg->daddy, "Files", NULL, 0);
08931       
08932       XtVaSetValues (dlg->dlg_w,
08933          XmNdeleteResponse, XmUNMAP,  /* system menu "Close" action */
08934         NULL);
08935         
08936       /* you can't cancel the kill button's effect, the way you do for toplevel shells. 
08937       But it does appear that the kill button is just unmanaging the widget, which is fine.
08938       see my modified action_area.c file
08939       */
08940       
08941    } else { 
08942       SUMA_LH ("Updating");
08943       /* update and raise dialogue, that is done next, for the moment, remove pre-existing callbacks*/
08944       XtRemoveAllCallbacks (dlg->dlg_w, XmNcancelCallback);
08945       XtRemoveAllCallbacks (dlg->dlg_w, XmNokCallback);
08946       XtRemoveAllCallbacks (dlg->dlg_w, XmNunmapCallback);
08947    }
08948       
08949       if (dlg->FilePattern) {
08950          pattern = XmStringCreateLocalized (dlg->FilePattern);
08951          XtVaSetValues (dlg->dlg_w,
08952             XmNpattern, pattern,
08953             NULL);
08954          XmStringFree (pattern);
08955       }
08956       
08957       XtAddCallback (dlg->dlg_w, XmNcancelCallback, SUMA_FileSelection_popdown_cb, (XtPointer)dlg);
08958       XtAddCallback (dlg->dlg_w, XmNokCallback, SUMA_FileSelection_file_select_cb, (XtPointer)dlg);
08959       XtAddCallback (dlg->dlg_w, XmNunmapCallback, SUMA_FileSelection_Unmap_cb, (XtPointer)dlgp);
08960 
08961       if (dlg->Mode == SUMA_FILE_OPEN) {
08962          button = XmStringCreateLocalized ("Open");
08963          title = XmStringCreateLocalized (title_extension);
08964       } 
08965       else { /* dlg->Mode == SUMA_FILE_SAVE */
08966         button = XmStringCreateLocalized ("Save");
08967         title = XmStringCreateLocalized (title_extension);
08968       }
08969       XtVaSetValues (dlg->dlg_w,
08970         XmNokLabelString, button,
08971         XmNdialogTitle,   title,
08972         NULL);
08973       
08974       XmStringFree (button);
08975       XmStringFree (title);
08976       
08977       XtManageChild (dlg->dlg_w);
08978       
08979       /* make sure that dialog is raised to top of window stack */
08980       XMapRaised (XtDisplay (dlg->dlg_w), XtWindow (XtParent (dlg->dlg_w)));      
08981    
08982    SUMA_RETURN(dlg);
08983 }
08984 /*!
08985  \brief sample callback routine for "Cancel" button in FileSelectionDialogs 
08986  SUMA_SELECTION_DIALOG_STRUCT *
08987 */
08988 void SUMA_FileSelection_popdown_cb (Widget w, XtPointer client_data, XtPointer call_data)
08989 {
08990    static char FuncName[]={"SUMA_FileSelection_popdown_cb"};
08991    SUMA_SELECTION_DIALOG_STRUCT *dlg;
08992    SUMA_Boolean LocalHead = NOPE;
08993 
08994    SUMA_ENTRY;
08995    
08996    SUMA_LH("Called");
08997    
08998    dlg = (SUMA_SELECTION_DIALOG_STRUCT *)client_data;
08999    
09000 
09001    /* do the callback for the cancel */
09002    if (dlg->CancelCallback) {
09003       dlg->CancelCallback(dlg->CancelData);
09004    }
09005    
09006    XtUnmanageChild (dlg->dlg_w);
09007    
09008    SUMA_RETURNe;
09009 }
09010 /*!
09011  \brief sample callback routine for killing window in FileSelectionDialogs.
09012  That happens when users hit the X on the dialog
09013  This function destroys the widget and frees the structure if no preservation is needed
09014  
09015  -expect SUMA_SELECTION_DIALOG_STRUCT ** in client_data
09016 */
09017 void SUMA_FileSelection_Unmap_cb (Widget w, XtPointer client_data, XtPointer call_data)
09018 {
09019    static char FuncName[]={"SUMA_FileSelection_Unmap_cb"};
09020    SUMA_SELECTION_DIALOG_STRUCT *dlg;
09021    SUMA_SELECTION_DIALOG_STRUCT **dlgp;
09022    SUMA_Boolean LocalHead = NOPE;
09023 
09024    SUMA_ENTRY;
09025    
09026    SUMA_LH("Called");
09027    
09028    dlgp = (SUMA_SELECTION_DIALOG_STRUCT **)client_data;
09029    dlg = *dlgp;
09030    
09031    /* if preservation is not required, kill the widget and free dlg */
09032    if (!dlg->preserve) {
09033       if (dlg->dlg_w) {
09034          SUMA_LH("Destroying dlg");
09035          XtDestroyWidget(dlg->dlg_w); 
09036       }else {
09037          SUMA_SL_Warn("dlg_w is null.\nThis should not be.");
09038       }
09039       
09040       /* now free the structure */
09041       SUMA_FreeFileSelectionDialogStruct(dlg);
09042       *dlgp = NULL;
09043       
09044    }
09045    
09046    SUMA_RETURNe;
09047 }
09048 
09049 /*!
09050    \brief Free the structure for creating a file selection dialog
09051    
09052 */
09053 void SUMA_FreeFileSelectionDialogStruct(SUMA_SELECTION_DIALOG_STRUCT *dlg)
09054 {
09055    static char FuncName[]={"SUMA_FreeFileSelectionDialogStruct"};
09056    SUMA_Boolean LocalHead = NOPE;
09057    
09058    SUMA_ENTRY;
09059    SUMA_LH("Called");
09060    
09061    
09062    if (!dlg) SUMA_RETURNe;
09063    
09064    /* now free structure */
09065    if (dlg->filename) SUMA_free(dlg->filename);
09066    if (dlg->FilePattern) SUMA_free(dlg->FilePattern);
09067    SUMA_free(dlg);
09068    
09069    SUMA_RETURNe;
09070 }
09071 
09072 /*! 
09073 callback routine for "OK" button in FileSelectionDialogs 
09074 */
09075 void SUMA_FileSelection_file_select_cb(Widget dialog, XtPointer client_data, XtPointer call_data)
09076 {
09077    static char FuncName[]={"SUMA_FileSelection_file_select_cb"};
09078    char buf[256], *filename;
09079    struct stat statb;
09080    FILE *fp=NULL;
09081    SUMA_SELECTION_DIALOG_STRUCT *dlg;
09082    XmFileSelectionBoxCallbackStruct *cbs =
09083      (XmFileSelectionBoxCallbackStruct *) call_data;
09084    SUMA_Boolean LocalHead = NOPE;
09085 
09086    SUMA_ENTRY;
09087 
09088    SUMA_LH("Called");
09089    
09090    dlg = (SUMA_SELECTION_DIALOG_STRUCT *)client_data;
09091 
09092    /* clear old filename */
09093    if (dlg->filename) {
09094       SUMA_free(dlg->filename); 
09095       dlg->filename = NULL;
09096    }
09097 
09098    if (!XmStringGetLtoR (cbs->value, XmFONTLIST_DEFAULT_TAG, &filename))
09099       SUMA_RETURNe; /* must have been an internal error */
09100 
09101    if (filename[0] == '\0') {
09102       XtFree (filename);
09103       XBell (XtDisplay (dlg->daddy), 50);
09104       SUMA_RETURNe; /* nothing typed */
09105    }
09106 
09107    if (dlg->Mode == SUMA_FILE_SAVE) {
09108       /* here you could do some tests on the file given the
09109       options that would be specified in dlg */
09110       /* Do not carry out tests here as filename might change once proper extensions are added */
09111       #if 0
09112       if (!(fp = fopen (filename, "w"))) {
09113          perror (filename);
09114          sprintf (buf, "Can't save to %s.", filename);
09115          SUMA_SLP_Err(buf);
09116          XtFree(filename);
09117          SUMA_RETURNe;
09118       }
09119       #endif
09120       
09121    } 
09122    else { /* reason == FILE_OPEN */
09123      /* here you could do some tests on the file given the
09124      options that would be specified in dlg */
09125      /* make sure the file is a regular text file and open it */
09126      if (stat (filename, &statb) == -1 ||
09127              (statb.st_mode & S_IFMT) != S_IFREG ||
09128              !(fp = fopen (filename, "r"))) {
09129          perror (filename);
09130          sprintf (buf, "Can't read %s.", filename);
09131          SUMA_SLP_Err(buf);
09132          XtFree(filename);
09133          SUMA_RETURNe;
09134      }
09135    }
09136 
09137    /* store the filename */
09138    if (filename) {
09139       dlg->filename = (char *)SUMA_calloc(strlen(filename)+1, sizeof(char));
09140       dlg->filename = strcpy(dlg->filename, filename);
09141    }
09142 
09143    /* free all allocated space. */
09144    XtFree (filename);
09145    if (fp) fclose (fp);
09146 
09147    /* Now do the SelectCallback */
09148    if (dlg->SelectCallback) {
09149       dlg->SelectCallback(dlg->filename, dlg->SelectData);
09150    } 
09151 
09152    XtUnmanageChild (dlg->dlg_w); /* this function will call the unmap callback which will 
09153                                     do the destruction if dialog is not to be preserved */
09154 
09155    SUMA_RETURNe;
09156 }
09157 
09158 /* This function is for hiding the color plane frame */
09159 void  SUMA_cb_UnmanageWidget(Widget w, XtPointer data, XtPointer client_data)
09160 {
09161    static char FuncName[]={"SUMA_cb_UnmanageWidget"};
09162    static int ncall=1;
09163    SUMA_SurfaceObject *SO = NULL;
09164    void **curSOp;
09165    int xx, yy;
09166    
09167    SUMA_ENTRY;
09168    
09169    curSOp = (void **)data;
09170    SO = (SUMA_SurfaceObject *)(*curSOp);
09171    
09172    if (ncall > 0) {
09173       if (XtIsManaged(SO->SurfCont->ColPlane_fr)) XtUnmanageChild(SO->SurfCont->ColPlane_fr);
09174       /* if nothing else remains in the parent of ColPlane, then unmanage its parent (rc_right) too. 
09175        *** Parent of that frame is now rc_left    May 25 04*/
09176       /*XtUnmanageChild(XtParent(SO->SurfCont->ColPlane_fr)); May 25 04*/
09177       if (XtIsManaged(SO->SurfCont->DsetMap_fr)) {
09178          XtUnmanageChild(SO->SurfCont->DsetMap_fr);
09179          XtUnmanageChild(XtParent(SO->SurfCont->DsetMap_fr));
09180       }
09181    } else {
09182       /* XtManageChild(XtParent(SO->SurfCont->ColPlane_fr)); May 25 04*/
09183       if (strcmp(SO->SurfCont->curColPlane->cmapname, "explicit") != 0) { /* not an RGB dset */
09184          if (!XtIsManaged(SO->SurfCont->DsetMap_fr)) {
09185             XtManageChild(XtParent(SO->SurfCont->DsetMap_fr));
09186             XtManageChild((Widget)SO->SurfCont->DsetMap_fr);
09187          }
09188       }
09189       XtManageChild((Widget)SO->SurfCont->ColPlane_fr);
09190       XMapRaised (XtDisplay(SO->SurfCont->ColPlane_fr), XtWindow(SO->SurfCont->TopLevelShell));
09191    }
09192    
09193 
09194    ncall *= -1;
09195    SUMA_RETURNe;
09196 }
09197 
09198 
09199 /*!
09200    Load colorplane
09201    
09202    expects SO in data and a calling widget in w 
09203 */
09204 void SUMA_cb_ColPlane_Load(Widget w, XtPointer data, XtPointer client_data)
09205 {
09206    static char FuncName[]={"SUMA_cb_ColPlane_Load"};
09207    SUMA_LIST_WIDGET *LW=NULL;
09208    SUMA_SurfaceObject *SO=NULL;
09209    DList *list = NULL;
09210    SUMA_EngineData *ED = NULL;
09211    DListElmt *NextElm = NULL;
09212    SUMA_Boolean LocalHead = NOPE;
09213     
09214    SUMA_ENTRY;
09215    
09216    SUMA_LH("Called");
09217    
09218    SO = (SUMA_SurfaceObject *)data;
09219    
09220    if (!list) list = SUMA_CreateList();
09221    ED = SUMA_InitializeEngineListData (SE_OpenColFileSelection);
09222    if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
09223                                           SEF_vp, (void *)data,
09224                                           SES_Suma, NULL, NOPE,
09225                                           SEI_Head, NULL))) {
09226       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
09227    }
09228    if (!SUMA_RegisterEngineListCommand (  list, ED,
09229                                           SEF_ip, (int *)w,
09230                                           SES_Suma, NULL, NOPE,
09231                                           SEI_In, NextElm)) {
09232       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
09233    }
09234    
09235    if (!SUMA_Engine (&list)) {
09236       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
09237    }
09238    
09239    SUMA_RETURNe;
09240 }
09241 
09242 /*!
09243    Load Dset
09244    
09245    expects SO in data and a calling widget in w 
09246 */
09247 void SUMA_cb_Dset_Load(Widget w, XtPointer data, XtPointer client_data)
09248 {
09249    static char FuncName[]={"SUMA_cb_Dset_Load"};
09250    SUMA_LIST_WIDGET *LW=NULL;
09251    SUMA_SurfaceObject *SO=NULL;
09252    DList *list = NULL;
09253    SUMA_EngineData *ED = NULL;
09254    DListElmt *NextElm = NULL;
09255    SUMA_Boolean LocalHead = NOPE;
09256     
09257    SUMA_ENTRY;
09258    
09259    SUMA_LH("Called");
09260    
09261    SO = (SUMA_SurfaceObject *)data;
09262    
09263    if (!list) list = SUMA_CreateList();
09264    ED = SUMA_InitializeEngineListData (SE_OpenDsetFileSelection);
09265    if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
09266                                           SEF_vp, (void *)data,
09267                                           SES_Suma, NULL, NOPE,
09268                                           SEI_Head, NULL))) {
09269       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
09270    }
09271    if (!SUMA_RegisterEngineListCommand (  list, ED,
09272                                           SEF_ip, (int *)w,
09273                                           SES_Suma, NULL, NOPE,
09274                                           SEI_In, NextElm)) {
09275       fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
09276    }
09277    
09278    if (!SUMA_Engine (&list)) {
09279       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
09280    }
09281    
09282    SUMA_RETURNe;
09283 }
09284 
09285 /*!
09286    Delete colorplane
09287    
09288    expects SO in data 
09289 */
09290 void SUMA_cb_ColPlane_Delete(Widget w, XtPointer data, XtPointer client_data)
09291 {
09292    static char FuncName[]={"SUMA_cb_ColPlane_Delete"};
09293    SUMA_LIST_WIDGET *LW=NULL;
09294    SUMA_SurfaceObject *SO=NULL;
09295    SUMA_Boolean LocalHead = NOPE;
09296       
09297    SUMA_ENTRY;
09298    
09299    SUMA_LH("Called");
09300    SUMA_RETURNe;
09301    
09302    #if 0
09303    SO = (SUMA_SurfaceObject *)data;
09304    
09305    LW is not set yet ...
09306    
09307    /*close the list widget if open */
09308    if (!LW->isShaded) {
09309       if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing switch Color plane window ...\n", FuncName);
09310       SUMA_cb_CloseSwitchColPlane( w,  (XtPointer)SO->SurfCont->SwitchDsetlst,  client_data);
09311    }  
09312    #endif       
09313    SUMA_RETURNe;
09314 }
09315 
09316 /*!
09317    \brief create a forced answer dialog for replacing files
09318    \return SUMA_YES SUMA_NO SUMA_YES_ALL or SUMA_NO_ALL
09319    
09320 */
09321 int SUMA_AskUser_File_replace(Widget parent, char *question, int default_ans)
09322 {
09323     static char FuncName[]={"SUMA_AskUser_File_replace"};
09324     static Widget dialog; /* static to avoid multiple creation */
09325     Widget YesWid, NoWid, HelpWid;
09326     XmString text, yes, no;
09327     static int answer;
09328 
09329    SUMA_ENTRY;
09330 
09331    if (!dialog) {
09332      dialog = XmCreateQuestionDialog (parent, "dialog", NULL, 0);
09333      XtVaSetValues (dialog,
09334          XmNdialogStyle,        XmDIALOG_FULL_APPLICATION_MODAL,
09335          NULL);
09336      XtSetSensitive (
09337          XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON),
09338          False);
09339      XtAddCallback (dialog, XmNokCallback, SUMA_response, &answer);
09340      XtAddCallback (dialog, XmNcancelCallback, SUMA_response, &answer);
09341     /* Now add a special extra cute little button */
09342     {
09343        XmString NewButt;
09344        Widget NewButt_button = NULL;
09345       
09346        NewButt= XmStringCreateLocalized ("Yes All");
09347        NewButt_button = XtVaCreateManagedWidget("Yes All", 
09348          xmPushButtonWidgetClass, dialog,
09349          XmNlabelString, NewButt,
09350          NULL);
09351        XtVaSetValues(NewButt_button, XmNuserData, SUMA_YES_ALL, NULL);
09352        XtAddCallback (NewButt_button, XmNactivateCallback, SUMA_response, &answer);
09353        XmStringFree (NewButt);
09354        
09355 
09356        NewButt= XmStringCreateLocalized ("No");
09357        NewButt_button = XtVaCreateManagedWidget("No", 
09358          xmPushButtonWidgetClass, dialog,
09359          XmNlabelString, NewButt,
09360          NULL);
09361        XtVaSetValues(NewButt_button, XmNuserData, SUMA_NO, NULL);
09362        XtAddCallback (NewButt_button, XmNactivateCallback, SUMA_response, &answer);
09363        XmStringFree (NewButt);
09364           
09365     }
09366 
09367     }
09368    answer = SUMA_NO_ANSWER;
09369    text = XmStringCreateLocalized (question);
09370    yes = XmStringCreateLocalized ("Yes");
09371    no = XmStringCreateLocalized ("No All");
09372    XtVaSetValues (dialog,
09373      XmNmessageString,      text,
09374      XmNokLabelString,      yes,
09375      XmNcancelLabelString,  no,
09376      XmNdefaultButtonType,  default_ans == SUMA_YES ?
09377          XmDIALOG_OK_BUTTON : XmDIALOG_CANCEL_BUTTON,
09378      NULL);
09379    XmStringFree (text);
09380    XmStringFree (yes);
09381    XmStringFree (no);
09382 
09383    /* set the values of the standrard buttons */
09384    YesWid = XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON);
09385    XtVaSetValues(YesWid, XmNuserData, SUMA_YES, NULL);
09386    NoWid = XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON);
09387    XtVaSetValues(NoWid, XmNuserData, SUMA_NO_ALL, NULL);
09388    HelpWid = XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
09389    XtVaSetValues(HelpWid, XmNuserData, SUMA_HELP, NULL);
09390 
09391    /* unmanage the Help button because I am not using it here */
09392    XtUnmanageChild(HelpWid);
09393    
09394    XtManageChild (dialog);
09395    XtPopup (XtParent (dialog), XtGrabNone);
09396 
09397    while (answer == SUMA_NO_ANSWER)
09398      XtAppProcessEvent (SUMAg_CF->X->App, XtIMAll);
09399 
09400    XtPopdown (XtParent (dialog));
09401    /* make sure the dialog goes away before returning. Sync with server
09402    * and update the display.
09403    */
09404    XSync (XtDisplay (dialog), 0);
09405    XmUpdateDisplay (parent);
09406 
09407    SUMA_RETURN(answer);
09408 }
09409 
09410 
09411 /*!
09412    \brief create a forced answer dialog YES/NO 
09413    
09414    set pos to SWP_DONT_CARE (recommended) if you don't want to specify where
09415    the prompt goes
09416    \return SUMA_YES SUMA_NO 
09417 */
09418 int SUMA_ForceUser_YesNo(Widget parent, char *question, int default_ans, SUMA_WINDOW_POSITION pos)
09419 {
09420     static char FuncName[]={"SUMA_ForceUser_YesNo"};
09421     static Widget dialog; /* static to avoid multiple creation */
09422     Widget YesWid, NoWid, HelpWid;
09423     XmString text, yes, no;
09424     static int answer;
09425 
09426    SUMA_ENTRY;
09427 
09428    if (!dialog) {
09429      dialog = XmCreateQuestionDialog (parent, "dialog", NULL, 0);
09430      XtVaSetValues (dialog,
09431          XmNdialogStyle,        XmDIALOG_FULL_APPLICATION_MODAL,
09432          NULL);
09433      XtSetSensitive (
09434          XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON),
09435          False);
09436      XtAddCallback (dialog, XmNokCallback, SUMA_response, &answer);
09437      XtAddCallback (dialog, XmNcancelCallback, SUMA_response, &answer);
09438 
09439     }
09440    answer = SUMA_NO_ANSWER;
09441    text = XmStringCreateLocalized (question);
09442    yes = XmStringCreateLocalized ("Yes");
09443    no = XmStringCreateLocalized ("No");
09444    XtVaSetValues (dialog,
09445      XmNmessageString,      text,
09446      XmNokLabelString,      yes,
09447      XmNcancelLabelString,  no,
09448      XmNdefaultButtonType,  default_ans == SUMA_YES ?
09449          XmDIALOG_OK_BUTTON : XmDIALOG_CANCEL_BUTTON,
09450      NULL);
09451    XmStringFree (text);
09452    XmStringFree (yes);
09453    XmStringFree (no);
09454 
09455    /* set the values of the standard buttons */
09456    YesWid = XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON);
09457    XtVaSetValues(YesWid, XmNuserData, SUMA_YES, NULL);
09458    NoWid = XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON);
09459    XtVaSetValues(NoWid, XmNuserData, SUMA_NO_ALL, NULL);
09460    HelpWid = XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
09461    XtVaSetValues(HelpWid, XmNuserData, SUMA_HELP, NULL);
09462 
09463    /* unmanage the buttons I am not using it here */
09464    XtUnmanageChild(HelpWid);
09465    
09466    
09467    XtManageChild (dialog);
09468    XtPopup (XtParent (dialog), XtGrabNone);
09469    
09470    if (pos != SWP_DONT_CARE) SUMA_PositionWindowRelative(dialog, parent, pos);
09471    
09472    while (answer == SUMA_NO_ANSWER)
09473      XtAppProcessEvent (SUMAg_CF->X->App, XtIMAll);
09474 
09475    XtPopdown (XtParent (dialog));
09476    /* make sure the dialog goes away before returning. Sync with server
09477    * and update the display.
09478    */
09479    XSync (XtDisplay (dialog), 0);
09480    XmUpdateDisplay (parent);
09481 
09482    SUMA_RETURN(answer);
09483 }
09484 
09485  
09486 /*
09487  * AskUser() -- a generalized routine that asks the user a question
09488  * and returns a response.  Parameters are: the question, the labels
09489  * for the "Yes" and "No" buttons, and the default selection to use.
09490  */
09491 int AskUser(Widget parent, char *question, char *ans1, char *ans2, int default_ans)
09492 {
09493     static Widget dialog; /* static to avoid multiple creation */
09494     XmString text, yes, no;
09495     static int answer;
09496 
09497     if (!dialog) {
09498         dialog = XmCreateQuestionDialog (parent, "dialog", NULL, 0);
09499         XtVaSetValues (dialog,
09500             XmNdialogStyle,        XmDIALOG_FULL_APPLICATION_MODAL,
09501             NULL);
09502         XtSetSensitive (
09503             XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON),
09504             False);
09505         XtAddCallback (dialog, XmNokCallback, SUMA_response, &answer);
09506         XtAddCallback (dialog, XmNcancelCallback, SUMA_response, &answer);
09507        /* Now add a special extra cute little button */
09508        {
09509           /* To do here:
09510           - Make all other buttons use UserData for uniformity
09511           - use SUMA_NO, SUMA_YES etc....
09512           - deal with recreation issues (you'll have to keep track of which new buttons are used, their new labels and whether they are to appear or not.)
09513             You'll probably want different kinds of static dialog widgets for the various types you envision using ....
09514           */
09515           XmString All = XmStringCreateLocalized ("All");
09516           Widget All_button = NULL;
09517 
09518           All_button = XtVaCreateManagedWidget("All", 
09519             xmPushButtonWidgetClass, dialog,
09520             XmNlabelString, All,
09521             NULL);
09522           XtVaSetValues(All_button, XmNuserData, SUMA_YES_ALL, NULL);
09523           XtAddCallback (All_button, XmNactivateCallback, SUMA_response, &answer);
09524           XmStringFree (All);   
09525        }
09526 
09527     }
09528     answer = SUMA_NO_ANSWER;
09529     text = XmStringCreateLocalized (question);
09530     yes = XmStringCreateLocalized (ans1);
09531     no = XmStringCreateLocalized (ans2);
09532     XtVaSetValues (dialog,
09533         XmNmessageString,      text,
09534         XmNokLabelString,      yes,
09535         XmNcancelLabelString,  no,
09536         XmNdefaultButtonType,  default_ans == SUMA_YES ?
09537             XmDIALOG_OK_BUTTON : XmDIALOG_CANCEL_BUTTON,
09538         NULL);
09539     XmStringFree (text);
09540     XmStringFree (yes);
09541     XmStringFree (no);
09542         
09543     XtManageChild (dialog);
09544     XtPopup (XtParent (dialog), XtGrabNone);
09545 
09546     while (answer == SUMA_NO_ANSWER)
09547         XtAppProcessEvent (SUMAg_CF->X->App, XtIMAll);
09548 
09549     XtPopdown (XtParent (dialog));
09550     /* make sure the dialog goes away before returning. Sync with server
09551      * and update the display.
09552      */
09553     XSync (XtDisplay (dialog), 0);
09554     XmUpdateDisplay (parent);
09555 
09556     return answer;
09557 }
09558 
09559 /*!
09560    \brief sets the answer value to a question dialog created by functions 
09561    like SUMA_AskUser.... 
09562    -Based largely on example in Motif Programming Manual chapters 5 and 7
09563    
09564    - For the three standard dialog buttons: 
09565    XmDIALOG_OK_BUTTON, XmDIALOG_CANCEL_BUTTON and XmDIALOG_HELP_BUTTON,
09566    the widget appears to be the dialog widget
09567    - For the other buttons (XmCR_ACTIVATE) the widget appears to be the
09568    button itself.
09569  */
09570 void SUMA_response(Widget widget, XtPointer client_data, XtPointer call_data)
09571 {
09572    static char FuncName[]={"SUMA_response"};
09573    int *answer = (int *) client_data;
09574    int ud;
09575    Widget YesWid, NoWid, HelpWid;
09576    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data;
09577    SUMA_Boolean LocalHead = NOPE;
09578    
09579    SUMA_ENTRY;
09580    
09581    switch (cbs->reason) {
09582    case XmCR_OK:
09583       YesWid = XmMessageBoxGetChild(widget, XmDIALOG_OK_BUTTON);
09584       XtVaGetValues(YesWid, XmNuserData, &ud, NULL);       
09585       *answer = ud;
09586       break;
09587    case XmCR_CANCEL:
09588       NoWid = XmMessageBoxGetChild(widget, XmDIALOG_CANCEL_BUTTON);
09589       XtVaGetValues(NoWid, XmNuserData, &ud, NULL);      
09590       *answer = ud;
09591       break;
09592    case XmCR_HELP:
09593       HelpWid = XmMessageBoxGetChild(widget, XmDIALOG_HELP_BUTTON);
09594       XtVaGetValues(HelpWid, XmNuserData, &ud, NULL);      
09595       *answer = ud;
09596       break;
09597    case XmCR_ACTIVATE:
09598       XtVaGetValues(widget, XmNuserData, &ud, NULL); 
09599       *answer = ud;
09600       break;
09601    default:
09602       *answer = -1;
09603       break;
09604    }
09605    
09606    if (LocalHead) fprintf (SUMA_STDERR,"%s: Answer %d\n", FuncName, *answer); 
09607    SUMA_RETURNe;        
09608 }
09609 /*!
09610    \brief spits out stats about available visuals 
09611    
09612    - copied from program glxvisuals.c by Mark Kilgard
09613    
09614    \sa SUMA_ShowVisual
09615 */
09616 void SUMA_ShowAllVisuals (void) 
09617 {
09618    static char FuncName[]={"SUMA_ShowAllVisuals"};
09619    Display *dpy;
09620    XVisualInfo match, *visualList, *vi, *visualToTry;
09621    int errorBase, eventBase, major, minor, found, glxcapable;
09622    Widget TopLevel;
09623    XtAppContext App;
09624    char *vargv[1]={ "[A] SUMA" };
09625    int cargc = 1;
09626 
09627 
09628    
09629    SUMA_ENTRY;
09630 
09631    dpy = XOpenDisplay(NULL);
09632    if (!dpy) {
09633       fprintf(SUMA_STDERR, "Error %s: Could not connect to %s.\n", FuncName, XDisplayName(NULL));
09634       SUMA_RETURNe;
09635    }
09636    if (glXQueryExtension(dpy, &errorBase, &eventBase) == False) {
09637       fprintf(SUMA_STDERR, "Error %s: OpenGL not supported by X server.\n" ,FuncName);
09638       SUMA_RETURNe;
09639    }
09640 
09641    glXQueryVersion(dpy, &major, &minor);
09642    fprintf(SUMA_STDERR, "display: %s\n", XDisplayName(NULL));
09643    fprintf(SUMA_STDERR, "using GLX version: %d.%d\n\n", major, minor);
09644 
09645    match.screen = DefaultScreen(dpy);
09646    visualList = XGetVisualInfo(dpy, VisualScreenMask, &match, &found);
09647    
09648    visualToTry = NULL;
09649    for(vi = visualList; found > 0; found--, vi++) {
09650       if (vi == visualList) glxcapable = SUMA_ShowVisual(dpy, vi, YUP);
09651       else glxcapable = SUMA_ShowVisual(dpy, vi, NOPE);
09652       
09653       if (glxcapable) visualToTry = vi;
09654    }
09655 
09656    if (visualToTry) {
09657       GLXContext context;
09658       Window window;
09659       Colormap colormap;
09660       XSetWindowAttributes swa;
09661 
09662       context = glXCreateContext(dpy, visualToTry, 0, GL_TRUE);
09663       colormap = XCreateColormap(dpy,
09664       RootWindow(dpy, visualToTry->screen),
09665       visualToTry->visual, AllocNone);
09666       swa.colormap = colormap;
09667       swa.border_pixel = 0;
09668       window = XCreateWindow(dpy, RootWindow(dpy, visualToTry->screen), 0, 0, 100, 100,
09669       0, visualToTry->depth, InputOutput, visualToTry->visual,
09670       CWBorderPixel | CWColormap, &swa);
09671       glXMakeCurrent(dpy, window, context);
09672       fprintf(SUMA_STDERR, "\n");
09673       fprintf(SUMA_STDERR, "OpenGL vendor string: %s\n", glGetString(GL_VENDOR));
09674       fprintf(SUMA_STDERR, "OpenGL renderer string: %s\n", glGetString(GL_RENDERER));
09675       fprintf(SUMA_STDERR, "OpenGL version string: %s\n", glGetString(GL_VERSION));
09676       if (glXIsDirect(dpy, context))
09677          fprintf(SUMA_STDERR, "direct rendering: supported\n");
09678    } else fprintf(SUMA_STDERR, "No GLX-capable visuals!\n");
09679    
09680    XFree(visualList);
09681 
09682    /* which visual will be chosen by SUMA ? (based on Step 3 in SUMA_X_SurfaceViewer_Create) */
09683    TopLevel = XtAppInitialize(&App, "SUMA", NULL, 0, &cargc, vargv,
09684                               SUMA_get_fallbackResources(), NULL, 0);
09685    dpy = XtDisplay(TopLevel);
09686 
09687    vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf);
09688    if (vi == NULL) {
09689       fprintf(stdout, "trying lame single buffer visual\n");
09690       XtAppWarning(App, "trying lame single buffer visual");
09691       vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf);
09692     if (vi == NULL) {
09693       XtAppError(App, "no good visual");
09694       }
09695    }
09696    fprintf (SUMA_STDERR,"************************************\n"); 
09697    fprintf (SUMA_STDERR,"%s: Visual chosen by SUMA:\n", FuncName);
09698    SUMA_ShowVisual(dpy, vi, YUP);
09699    if (vi->class != TrueColor) {
09700       fprintf (SUMA_STDERR,"%s: Visual is not TrueColor.\n", FuncName); 
09701       fprintf (SUMA_STDERR," SUMA NO LIKE.\n");
09702    }
09703    XtDestroyWidget(TopLevel);
09704    
09705    SUMA_RETURNe;
09706 }
09707 
09708 /*!
09709    \brief Show the properties of a visual.
09710    \sa OpenGL Programming for the X Window System by Mark J. Kilgard
09711              pp. 75..81
09712 */
09713 int SUMA_ShowVisual (Display *dpy, XVisualInfo *vi, SUMA_Boolean ShowHead)
09714 {
09715    static char FuncName[]={"SUMA_ShowVisual"};
09716    int glxCapable, bufferSize, level, renderType, doubleBuffer, stereo,
09717       auxBuffers, redSize, greenSize, blueSize, alphaSize, depthSize,
09718       stencilSize, acRedSize, acGreenSize, acBlueSize, acAlphaSize;
09719 
09720    SUMA_ENTRY;
09721    
09722    if (ShowHead) {
09723       fprintf(SUMA_STDERR, "\n");
09724       fprintf(SUMA_STDERR, "   visual     bf lv rg d st  r  g  b a   ax dp st accum buffs\n");
09725       fprintf(SUMA_STDERR, " id dep cl    sz l  ci b ro sz sz sz sz  bf th cl  r  g  b  a\n");
09726       fprintf(SUMA_STDERR, "-------------------------------------------------------------\n");
09727    }
09728    
09729    glXGetConfig(dpy, vi, GLX_USE_GL, &glxCapable);
09730    if (glxCapable) {
09731       fprintf(SUMA_STDERR, "0x%x %2d %s",(unsigned int)vi->visualid, vi->depth, SUMA_ClassOf(vi->class));
09732       glXGetConfig(dpy, vi, GLX_BUFFER_SIZE, &bufferSize);
09733       glXGetConfig(dpy, vi, GLX_LEVEL, &level);
09734       glXGetConfig(dpy, vi, GLX_RGBA, &renderType);
09735       glXGetConfig(dpy, vi, GLX_DOUBLEBUFFER, &doubleBuffer);
09736       glXGetConfig(dpy, vi, GLX_STEREO, &stereo);
09737       glXGetConfig(dpy, vi, GLX_AUX_BUFFERS, &auxBuffers);
09738       glXGetConfig(dpy, vi, GLX_RED_SIZE, &redSize);
09739       glXGetConfig(dpy, vi, GLX_GREEN_SIZE, &greenSize);
09740       glXGetConfig(dpy, vi, GLX_BLUE_SIZE, &blueSize);
09741       glXGetConfig(dpy, vi, GLX_ALPHA_SIZE, &alphaSize);
09742       glXGetConfig(dpy, vi, GLX_DEPTH_SIZE, &depthSize);
09743       glXGetConfig(dpy, vi, GLX_STENCIL_SIZE, &stencilSize);
09744       glXGetConfig(dpy, vi, GLX_ACCUM_RED_SIZE, &acRedSize);
09745       glXGetConfig(dpy, vi, GLX_ACCUM_GREEN_SIZE, &acGreenSize);
09746       glXGetConfig(dpy, vi, GLX_ACCUM_BLUE_SIZE, &acBlueSize);
09747       glXGetConfig(dpy, vi, GLX_ACCUM_ALPHA_SIZE, &acAlphaSize);
09748       fprintf(SUMA_STDERR, "    %2s %2s %1s  %1s  %1s ",
09749         SUMA_Format(bufferSize, 2), SUMA_Format(level, 2),
09750         renderType ? "r" : "c",
09751          doubleBuffer ? "y" : ".", 
09752          stereo ? "y" : ".");
09753       fprintf(SUMA_STDERR, "%2s %2s %2s %2s ",
09754          SUMA_Format(redSize, 2), SUMA_Format(greenSize, 2),
09755          SUMA_Format(blueSize, 2), SUMA_Format(alphaSize, 2));
09756       fprintf(SUMA_STDERR, "%2s %2s %2s %2s %2s %2s %2s",
09757         SUMA_Format(auxBuffers, 2), SUMA_Format(depthSize, 2), SUMA_Format(stencilSize, 2),
09758         SUMA_Format(acRedSize, 2), SUMA_Format(acGreenSize, 2),
09759         SUMA_Format(acBlueSize, 2), SUMA_Format(acAlphaSize, 2));
09760       fprintf(SUMA_STDERR, "\n");
09761    }
09762    
09763    SUMA_RETURN(glxCapable); 
09764 } 
09765 
09766 char * SUMA_ClassOf(int c)
09767 {
09768    static char FuncName[]={"SUMA_ClassOf"};
09769   
09770    SUMA_ENTRY;
09771 
09772    switch (c) {
09773       case StaticGray:   SUMA_RETURN("sg");
09774       case GrayScale:    SUMA_RETURN("gs");
09775       case StaticColor:  SUMA_RETURN("sc");
09776       case PseudoColor:  SUMA_RETURN("pc");
09777       case TrueColor:    SUMA_RETURN("tc");
09778       case DirectColor:  SUMA_RETURN("dc");
09779       default:           SUMA_RETURN("??");
09780    }
09781 }
09782 
09783 char * SUMA_Format(int n, int w)
09784 {
09785    static char FuncName[]={"SUMA_Format"};
09786    static char buffer[256];
09787    static int bufptr;
09788    char *buf;
09789 
09790    SUMA_ENTRY;
09791 
09792    if (bufptr >= sizeof(buffer) - w)
09793       bufptr = 0;
09794    
09795    buf = buffer + bufptr;
09796    
09797    if (n == 0)
09798       sprintf(buf, "%*s", w, ".");
09799    else
09800       sprintf(buf, "%*d", w, n);
09801    
09802    bufptr += w + 1;
09803 
09804    SUMA_RETURN(buf);
09805 }
09806 
09807 
09808 /*
09809 void  (Widget w, XtPointer data, XtPointer client_data)
09810 {
09811    static char FuncName[]={""};
09812    
09813    SUMA_ENTRY;
09814    
09815    SUMA_RETURNe;
09816 }
09817 
09818 */
 

Powered by Plone

This site conforms to the following standards: