1 #define DEBUG_1
2 #ifdef DEBUG_1
3    #define DEBUG_2
4    #define DEBUG_3
5 #endif
6 
7 /* Need to figure out what to do with talking to multiple sockets (MATLAB and AFNI, for example).
8    So far, it looks like:
9    *- toggling should be separate. Maybe use Y key for matlab
10       Not sure if SUMA_Engine talk toggling targets need to be separate
11       for the various stream. Me thinks that should not be the case.
12    *- Talk_mode should be a part of the SUMAg_CF structure and should be set
13       for each stream. You'll also need to make sure relevant NI_write calls
14       abide by the settings. You should remove reliance on NI_TALK_MODE
15       and the current env used to control it.
16    *- Everytime one deals with SUMA_AFNI_STREAM_INDEX, one should have
17       a case for    SUMA_TO_MATLAB_STREAM_INDEX . However, one does not
18       want to call SE_SendColorMapToAfni twice, once for AFNI and another
19       time for matlab. You want to send, not generate, the nel in question twice. */
20 /* Header FILES */
21 
22 #include "SUMA_suma.h"
23 
24 extern int selenium_close(void) ;
25 
26 static FILE *sumaout = NULL;             /* no default output stream */
27 static int SUMA_drive_set_outstream(char *outfile);
28 static FILE *SUMA_drive_get_outstream(void);
29 
30 /* Make suma call itself with DriveSuma command in scom */
SUMA_MakeMeDo(char * scom,int method)31 SUMA_Boolean SUMA_MakeMeDo (char *scom, int method)
32 {
33    static char FuncName[]={"SUMA_MakeMeDo"};
34    SUMA_Boolean res = NOPE;
35    int i, exflag, margc;
36    char **margv=NULL;
37    SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt = NULL;
38    SUMA_Boolean LocalHead = NOPE;
39 
40    SUMA_ENTRY;
41 
42    if (!scom) SUMA_RETURN(YUP);
43 
44    SUMA_LH("Talking to self");
45    /* The shortcut, proper way (below, method = 0) needs fixing.
46       SUMA does not seem to get command it sends itself. Check later */
47    if (method==1) {
48       char *ssys=(char *)SUMA_calloc(strlen(scom)+100, sizeof(char));
49       SUMA_LH("Clumsy system call");
50       sprintf(ssys,"\\DriveSuma %s &", scom);
51       if (system(ssys)) {
52          SUMA_S_Err("Failed to execute %s ssys\n", ssys);
53          SUMA_ifree(ssys);
54          SUMA_RETURN(NOPE);
55       }
56       SUMA_RETURN(YUP);
57    }
58 
59    margv = SUMA_com2argv(scom, &margc);
60 
61    if (!(Opt = SUMA_DriveSuma_ParseInput (margv, margc, NULL))) {
62       goto CLEANOUT;
63    }
64 
65    for (i=0; i<Opt->N_com; ++i) {
66       if (LocalHead) {
67          SUMA_LH("Have the following commands");
68          fprintf(SUMA_STDERR,"Command %d: %s\n", i, Opt->com[i]);
69       }
70       if (!(exflag = SUMA_ProcessCommand(Opt->com[i], NULL, Opt->s))) {
71          SUMA_S_Errv("Failed in processing command\n%s\n", Opt->com[i]);
72          goto CLEANOUT;
73       }
74       if (exflag == -1) { /*gone daddy gone */
75          SUMA_S_Note("There's no more reason to exist.\n"
76                      "Farewell dear friends.\n");
77          goto CLEANOUT;
78       }
79    }
80 
81    res = YUP;
82 
83    CLEANOUT:
84    if (Opt) Opt = SUMA_Free_Generic_Prog_Options_Struct(Opt);
85    margv = SUMA_free_com_argv(margv, &margc);
86 
87    SUMA_RETURN(res);
88 }
89 
90 
91 
92 /*!
93    \brief This is the function that runs the viewers.
94    success = SUMA_Engine (listp);
95 
96    \param listp (DList **) pointer to doubly linked list pointer containing Engine commands
97 
98    \return success (YUP/NOPE)
99 
100    - *listp is destroyed just before SUMA_Engine returns and *listp is set to null
101    - To add a new command:
102    include it SUMA_define.h in SUMA_ENGINE_CODE's typedef
103    include it in SUMA_ParseCommands.c, SUMA_CommandCode, SUMA_CommandString functions
104    - OLD Format: SUMA_Boolean SUMA_Engine (char *Command, SUMA_EngineData *EngineData, SUMA_SurfaceViewer *sv)
105 
106 */
107 
SUMA_Engine(DList ** listp)108 SUMA_Boolean SUMA_Engine (DList **listp)
109 {
110    static char FuncName[]={"SUMA_Engine"};
111    char tmpstr[128], sfield[100], sdestination[100];
112    const char *NextCom;
113    int NextComCode, ii, i, id, ND, ip, NP, itmp=-1;
114    SUMA_SurfaceObject *SO = NULL;
115    SUMA_ALL_DO *ado = NULL;
116    SUMA_X_SurfCont *SurfCont=NULL;
117    SUMA_OVERLAYS *curColPlane=NULL;
118    float delta_t, ftmp = -1.0;
119    struct  timeval tt;
120    int it, Wait_tot, nn=0, N_SOlist,
121             SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], iv200[200];
122    float ft, **fm, fv15[15];
123    double dv15[15];
124    XtPointer elvis=NULL;
125    NI_element *nel;
126    char *cbuf=NULL;
127    SUMA_Boolean Found;
128    SUMA_SurfaceViewer *svi;
129    SUMA_SurfaceViewer *sv = NULL;
130    static char Command[]={"OBSOLETE-since:Thu Jan 23 16:55:03 EST 2003"};
131    SUMA_EngineData *EngineData=NULL, *ED = NULL;
132       /* EngineData is what get passed from a list element,
133          ED is what gets added to the list inside SUMA_Engine */
134    DListElmt *NextElem_CANT_TOUCH_THIS, *LocElm=NULL;
135    DList *list= NULL;
136    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell = NULL, *LogShell=NULL;
137    SUMA_PARSED_NAME *fn = NULL;
138    static int NI_TALK_MODE = -1;      /* Choose from:
139                                              NI_TEXT_MODE or NI_BINARY_MODE
140                                              Note cross-hair communication
141                                              is now always in NI_TEXT_MODE,
142                                              verify that AFNI handles either well
143                                              THIS handling here is TEMPORARY */
144    SUMA_Boolean LocalHead = NOPE;
145 
146 
147    SUMA_ENTRY;
148 
149    if (NI_TALK_MODE < 0) {
150       if (AFNI_yesenv("SUMA_NI_TEXT_TALK_MODE")) {
151          SUMA_S_Note("Talking in text mode");
152          NI_TALK_MODE = NI_TEXT_MODE;
153       } else NI_TALK_MODE = NI_BINARY_MODE;
154    }
155 
156    list = *listp;    /* listp is now passed instead of list so that I can
157                         set list to NULL from within this function */
158 
159    if (!list) {
160       fprintf (SUMA_STDERR, "Error %s: Nothing to do.\n", FuncName);
161       SUMA_RETURN (NOPE);
162    }
163 
164    SUMA_LH("Cycling through %d list elements", list->size);
165    while (list->size) {/* cycle through NextComs */
166       SUMA_LH("Fetching next element\n");
167      /* get the next command from the head of the list */
168       NextElem_CANT_TOUCH_THIS = dlist_head(list);
169       EngineData = (SUMA_EngineData *)NextElem_CANT_TOUCH_THIS->data;
170 
171       /* decide on what Srcp might be. Currently only sv is passed
172          when the source is Suma*/
173       sv = NULL;
174       switch (EngineData->Src) {
175          case SES_Suma:
176          case SES_SumaFromAfni:
177          case SES_SumaWidget:
178          case SES_SumaFromAny:
179             sv = (SUMA_SurfaceViewer *)EngineData->Srcp;
180          case SES_Afni:
181             break;
182          default:
183             break;
184       }
185 
186       NextComCode = EngineData->CommandCode;
187       if (!NextComCode) {
188          fprintf (stderr, "%s Error: Bad next element code\n", FuncName);
189          SUMA_RETURN (NOPE);
190       }
191       NextCom = SUMA_CommandString (NextComCode);
192       SUMA_LH("->%s<-\t", NextCom);
193       switch (NextComCode) {/* switch NextComCode */
194          case SE_SendColorMapToAfni:
195             /* expects in i the code of one of SUMA's standard colormaps */
196             {
197                SUMA_COLOR_MAP *cmap;
198                NI_element *nel=NULL;
199                int i;
200                char sbuf[50], *stmp=NULL;
201 
202                if (EngineData->i_Dest != NextComCode ) {
203                   fprintf (
204                      SUMA_STDERR,
205                      "Error %s: Data not destined correctly for %s (%d).\n", \
206                    FuncName, NextCom, NextComCode);
207                   break;
208                }
209 
210                /* get the CMAP */
211                if (!(cmap = SUMA_FindCodedColMap(EngineData->i))) {
212                   SUMA_SLP_Err("Failed to get colormap");
213                   break;
214                }
215 
216                if (cmap->N_M[0] > 256) {
217                   SUMA_SLP_Err(  "Cannot send more\n"
218                                  "than 256 colors to\n"
219                                  "AFNI.");
220                   cmap = NULL;
221                   break;
222                }
223 
224                /* send AFNI the color map */
225                nel = NI_new_data_element("ni_do", 0);
226                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
227                stmp = SUMA_append_string("DEFINE_COLORSCALE ", cmap->Name);
228                /* SEND COLORMAP In REVERSE ORDER TO AFNI,
229                C'est la vie */
230                for (i=cmap->N_M[0]-1; i >= 0; --i) {
231                   sprintf(sbuf,"rgbi:%f/%f/%f",
232                            cmap->M[i][0], cmap->M[i][1], cmap->M[i][2]);
233                   stmp = SUMA_append_replace_string(stmp, sbuf, " ", 1);
234                }
235                SUMA_LH("%s",stmp);
236                NI_set_attribute ( nel, "ni_object", stmp);
237 
238                /* SUMA_ShowNel((void*)nel); */
239 
240                if (NI_write_element(   SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] ,
241                                        nel, NI_TALK_MODE ) < 0) {
242                   SUMA_SLP_Err("Failed to send CMAP to afni");
243                   NI_free_element(nel) ; nel = NULL;
244                   if (stmp) SUMA_free(stmp); stmp = NULL;
245                   cmap = NULL;
246                   break;
247                }
248 
249                NI_free_element(nel) ; nel = NULL;
250                if (stmp) SUMA_free(stmp); stmp = NULL;
251 
252                /* Now set the colormap in AFNI */
253                nel = NI_new_data_element("ni_do", 0);
254                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
255                stmp = SUMA_append_string("SET_PBAR_ALL ", "A.+99");
256                sprintf(sbuf, " 1 %s", cmap->Name);
257                stmp = SUMA_append_replace_string(stmp, sbuf, "", 1);
258                NI_set_attribute ( nel, "ni_object", stmp);
259 
260                /* SUMA_ShowNel((void*)nel); */
261 
262                if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] ,
263                                      nel, NI_TALK_MODE ) < 0) {
264                   SUMA_SLP_Err("Failed to send CMAP to afni");
265                   NI_free_element(nel) ; nel = NULL;
266                   if (stmp) SUMA_free(stmp); stmp = NULL;
267                   cmap = NULL;
268                   break;
269                }
270 
271                NI_free_element(nel) ; nel = NULL;
272                if (stmp) SUMA_free(stmp); stmp = NULL;
273 
274                /* set the autorange off */
275                nel = NI_new_data_element("ni_do", 0);
276                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
277                NI_set_attribute ( nel, "ni_object", "SET_FUNC_AUTORANGE A.-");
278                if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] ,
279                                      nel, NI_TALK_MODE ) < 0) {
280                   SUMA_SLP_Err("Failed to send CMAP to afni");
281                   NI_free_element(nel) ; nel = NULL;
282                   cmap = NULL;
283                   break;
284                }
285 
286                NI_free_element(nel) ; nel = NULL;
287 
288                /* set the range of the colorbar */
289                nel = NI_new_data_element("ni_do", 0);
290                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
291                sprintf(sbuf," %d", cmap->N_M[0]);
292                stmp = SUMA_append_string("SET_FUNC_RANGE A.", sbuf);
293                NI_set_attribute ( nel, "ni_object", stmp);
294                if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] ,
295                                      nel, NI_TALK_MODE ) < 0) {
296                   SUMA_SLP_Err("Failed to send CMAP to afni");
297                   NI_free_element(nel) ; nel = NULL;
298                   if (stmp) SUMA_free(stmp); stmp = NULL;
299                   cmap = NULL;
300                   break;
301                }
302                NI_free_element(nel) ; nel = NULL;
303                if (stmp) SUMA_free(stmp); stmp = NULL;
304 
305                cmap = NULL;
306             }
307             break;
308          case SE_OpenDrawnROIFileSelection:
309             /* opens the open ROI file selection window.
310             Expects sv in vp, NULL is OK, and a position
311             reference widget typecast to ip, the latter can also be null.*/
312             {
313                char sbuf[128];
314                if (  EngineData->vp_Dest != NextComCode ||
315                      EngineData->ip_Dest != NextComCode ) {
316                   fprintf (SUMA_STDERR,
317                            "Error %s: "
318                            "Data not destined correctly for %s (%d).\n",
319                            FuncName, NextCom, NextComCode);
320                   break;
321                }
322                /* open the ROI file */
323                if (!sv) sv = SUMA_LAST_VIEWER;
324                /* wildcard selection
325                  for a surface, just use the one in focus
326                  But it is only to select the wildcard
327                  SO assignment to an ROI is done in the ROI
328                  reading function*/
329                SO = SUMA_SV_Focus_SO(sv);
330                if (SO && !SUMA_WildcardChoice(2, SO, sbuf)) {
331                   sprintf(sbuf, "*.roi");
332                } else sprintf(sbuf, "*.roi");
333                if (!EngineData->vp) EngineData->vp = sv;
334                if (!EngineData->ip) {
335                   SUMAg_CF->X->FileSelectDlg =
336                      SUMA_CreateFileSelectionDialogStruct (
337                         sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
338                         SUMA_OpenDrawnROI, (void *)EngineData->vp,
339                         NULL, NULL,
340                         sbuf,
341                         SUMAg_CF->X->FileSelectDlg);
342                } else {
343                   SUMAg_CF->X->FileSelectDlg =
344                      SUMA_CreateFileSelectionDialogStruct (
345                         (Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
346                         SUMA_OpenDrawnROI, (void *)EngineData->vp,
347                         NULL, NULL,
348                         sbuf,
349                         SUMAg_CF->X->FileSelectDlg);
350                }
351                if (SO && SO->Side == SUMA_RIGHT) {
352                   sprintf(sbuf,"Select RH ROI File to Open");
353                } else if (SO && SO->Side == SUMA_LEFT) {
354                   sprintf(sbuf,"Select LH ROI File to Open");
355                } else sprintf(sbuf,"Select ROI File to Open");
356                SUMAg_CF->X->FileSelectDlg =
357                   SUMA_CreateFileSelectionDialog ( sbuf,
358                                                    &SUMAg_CF->X->FileSelectDlg);
359             }
360             break;
361 
362          case SE_OpenXformOrtFileFileSelection:
363             /* opens the open ort file selection window.
364             Expects SUMA_XFORM in vp (to be used later and a position
365             reference widget typecast to ip, the latter can be null.*/
366             if (  EngineData->vp_Dest != NextComCode ||
367                   EngineData->ip_Dest != NextComCode ) {
368                fprintf (SUMA_STDERR,
369                         "Error %s: Data not destined correctly for %s (%d).\n",
370                         FuncName, NextCom, NextComCode);
371                break;
372             }
373             if (!EngineData->ip) {
374                SUMAg_CF->X->FileSelectDlg =
375                   SUMA_CreateFileSelectionDialogStruct (
376                      sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
377                      SUMA_OpenXformOrtFile, (void *)EngineData->vp,
378                      NULL, NULL,
379                      "*.1D",
380                      SUMAg_CF->X->FileSelectDlg);
381             } else {
382                SUMAg_CF->X->FileSelectDlg =
383                   SUMA_CreateFileSelectionDialogStruct (
384                      (Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
385                      SUMA_OpenXformOrtFile, (void *)EngineData->vp,
386                      NULL, NULL,
387                      "*.1D",
388                      SUMAg_CF->X->FileSelectDlg);
389             }
390             SUMAg_CF->X->FileSelectDlg =
391                SUMA_CreateFileSelectionDialog ( "Select Ort File to Open",
392                                                 &SUMAg_CF->X->FileSelectDlg);
393             break;
394 
395          case SE_SaveDrawnROIFileSelection:
396             /* opens the save roi  file selection window.
397             Expects NULL in vp (to be used later and a position reference
398             widget typecast to ip, the latter can be null.*/
399             if (  EngineData->vp_Dest != NextComCode ||
400                   EngineData->ip_Dest != NextComCode ) {
401                fprintf (SUMA_STDERR,
402                         "Error %s: Data not destined correctly for %s (%d).\n",
403                         FuncName, NextCom, NextComCode);
404                break;
405             }
406 
407             /* save ROI to file */
408             if (!sv) sv = &(SUMAg_SVv[0]);
409             if (!EngineData->ip) {
410                SUMAg_CF->X->FileSelectDlg =
411                   SUMA_CreateFileSelectionDialogStruct ( sv->X->TOPLEVEL,
412                                                    SUMA_FILE_SAVE, YUP,
413                                                    SUMA_SaveDrawnROI,
414                                                    (void *)EngineData->vp,
415                                                    NULL, NULL,
416                                                    "*.roi",
417                                                    SUMAg_CF->X->FileSelectDlg);
418             } else {
419                SUMAg_CF->X->FileSelectDlg =
420                   SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip,
421                                                    SUMA_FILE_SAVE, YUP,
422                                                    SUMA_SaveDrawnROI,
423                                                    (void *)EngineData->vp,
424                                                    NULL, NULL,
425                                                    "*.roi",
426                                                    SUMAg_CF->X->FileSelectDlg);
427             }
428 
429             SUMAg_CF->X->FileSelectDlg =
430                SUMA_CreateFileSelectionDialog ( "Select ROI Filename",
431                                                 &SUMAg_CF->X->FileSelectDlg);
432 
433             break;
434          case SE_SaveXformOptsFileSelection:
435             /* opens the save Xform Opts  file selection window.
436             Expects SUMA_XFORM* in vp  and a position reference
437             widget typecast to ip, the latter can be null.*/
438             if (  EngineData->vp_Dest != NextComCode ||
439                   EngineData->ip_Dest != NextComCode ) {
440                fprintf (SUMA_STDERR,
441                         "Error %s: Data not destined correctly for %s (%d).\n",
442                         FuncName, NextCom, NextComCode);
443                break;
444             }
445 
446             /* save Xform opts to file */
447             if (!sv) sv = &(SUMAg_SVv[0]);
448             if (!EngineData->ip) {
449                SUMAg_CF->X->FileSelectDlg =
450                   SUMA_CreateFileSelectionDialogStruct ( sv->X->TOPLEVEL,
451                                                    SUMA_FILE_SAVE, YUP,
452                                                    SUMA_SaveXformOpts,
453                                                    (void *)EngineData->vp,
454                                                    NULL, NULL,
455                                                    "*.xfopts",
456                                                    SUMAg_CF->X->FileSelectDlg);
457             } else {
458                SUMAg_CF->X->FileSelectDlg =
459                   SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip,
460                                                    SUMA_FILE_SAVE, YUP,
461                                                    SUMA_SaveXformOpts,
462                                                    (void *)EngineData->vp,
463                                                    NULL, NULL,
464                                                    "*.xfopts",
465                                                    SUMAg_CF->X->FileSelectDlg);
466             }
467 
468             SUMAg_CF->X->FileSelectDlg =
469                SUMA_CreateFileSelectionDialog ( "Select Opts Filename",
470                                                 &SUMAg_CF->X->FileSelectDlg);
471 
472             break;
473 
474          case SE_SaveSOFileSelection:
475             /* saves a surface and its node colors to ascii files */
476             /* expects SO in vp and a position reference widget typecast
477                to ip, the latter can be null.*/
478             if (EngineData->vp_Dest != NextComCode ||
479                   EngineData->ip_Dest != NextComCode ) {
480                fprintf (SUMA_STDERR,
481                         "Error %s: Data not destined correctly for %s (%d).\n",
482                         FuncName, NextCom, NextComCode);
483                break;
484             }
485             if (!sv) sv = &(SUMAg_SVv[0]);
486 
487             {
488                SUMA_SAVESO_STRUCT *SaveSO_data = NULL;
489 
490                SaveSO_data = (SUMA_SAVESO_STRUCT *)
491                               SUMA_calloc(1,sizeof(SUMA_SAVESO_STRUCT));
492                               /* DO NOT FREE THIS POINTER,
493                                  It is freed by the function
494                                  SUMA_SaveSOascii */
495                SaveSO_data->SO = (SUMA_SurfaceObject *)EngineData->vp;
496                SaveSO_data->sv = sv;
497 
498                if (!EngineData->ip) {
499                   SUMAg_CF->X->FileSelectDlg =
500                      SUMA_CreateFileSelectionDialogStruct (
501                         sv->X->TOPLEVEL, SUMA_FILE_SAVE, YUP,
502                         SUMA_SaveSOascii, (void *)SaveSO_data,
503                         NULL, NULL,
504                         "*.1D.xyz",
505                         SUMAg_CF->X->FileSelectDlg);
506                } else {
507                   SUMAg_CF->X->FileSelectDlg =
508                      SUMA_CreateFileSelectionDialogStruct (
509                         (Widget) EngineData->ip, SUMA_FILE_SAVE, YUP,
510                         SUMA_SaveSOascii, (void *)SaveSO_data,
511                         NULL, NULL, "*.1D.xyz",                                                           SUMAg_CF->X->FileSelectDlg);
512                }
513 
514                SUMAg_CF->X->FileSelectDlg =
515                   SUMA_CreateFileSelectionDialog (
516                      "Select SO file prefix.", &SUMAg_CF->X->FileSelectDlg);
517             }
518             break;
519 
520          case SE_LoadSegDO:
521             if (EngineData->ip_Dest != NextComCode ) {
522                fprintf (SUMA_STDERR,
523                         "Error %s: Data not destined correctly for %s (%d).\n",
524                         FuncName, NextCom, NextComCode);
525                break;
526             }
527             if (!sv) sv = &(SUMAg_SVv[0]);
528             if (!EngineData->ip) {
529                SUMAg_CF->X->FileSelectDlg =
530                   SUMA_CreateFileSelectionDialogStruct (
531                      sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
532                      SUMA_LoadSegDO, (void *)sv,
533                      NULL, NULL,
534                      "*.*",
535                      SUMAg_CF->X->FileSelectDlg);
536             } else {
537                SUMAg_CF->X->FileSelectDlg =
538                   SUMA_CreateFileSelectionDialogStruct (
539                      (Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
540                      SUMA_LoadSegDO, (void *)sv,
541                      NULL, NULL,
542                      "*.*",
543                      SUMAg_CF->X->FileSelectDlg);
544             }
545             SUMAg_CF->X->FileSelectDlg =
546                SUMA_CreateFileSelectionDialog (
547                   "Select Displayable Objects File",
548                   &SUMAg_CF->X->FileSelectDlg);
549             break;
550 
551          case SE_LoadViewFileSelection:
552             /* opens the view file selection window.
553             Expects a position  reference widget typecast to ip,
554             the latter can be null.*/
555 
556             if (EngineData->ip_Dest != NextComCode ) {
557                fprintf (SUMA_STDERR,
558                         "Error %s: Data not destined correctly for %s (%d).\n",
559                         FuncName, NextCom, NextComCode);
560                break;
561             }
562             if (!sv) sv = &(SUMAg_SVv[0]);
563             if (!EngineData->ip) {
564                SUMAg_CF->X->FileSelectDlg =
565                   SUMA_CreateFileSelectionDialogStruct (
566                      sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
567                      SUMA_LoadVisualState, (void *)sv,
568                      NULL, NULL,
569                      "*.vvs",
570                      SUMAg_CF->X->FileSelectDlg);
571             } else {
572                SUMAg_CF->X->FileSelectDlg =
573                   SUMA_CreateFileSelectionDialogStruct (
574                      (Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
575                      SUMA_LoadVisualState, (void *)sv,
576                      NULL, NULL,
577                      "*.vvs",
578                      SUMAg_CF->X->FileSelectDlg);
579             }
580             SUMAg_CF->X->FileSelectDlg =
581                SUMA_CreateFileSelectionDialog (
582                   "Select Viewer Settings File", &SUMAg_CF->X->FileSelectDlg);
583             break;
584 
585          case SE_SaveViewFileSelection:
586             /* opens the view file selection window.
587             Expects a position  reference widget typecast to ip,
588             the latter can be null.*/
589 
590             if (EngineData->ip_Dest != NextComCode ) {
591                fprintf (SUMA_STDERR,
592                         "Error %s: Data not destined correctly for %s (%d).\n",
593                         FuncName, NextCom, NextComCode);
594                break;
595             }
596             if (!sv) sv = &(SUMAg_SVv[0]);
597             if (!EngineData->ip) {
598                SUMAg_CF->X->FileSelectDlg =
599                   SUMA_CreateFileSelectionDialogStruct (
600                        sv->X->TOPLEVEL, SUMA_FILE_SAVE, YUP,
601                        SUMA_SaveVisualState, (void *)sv,
602                        NULL, NULL,
603                        "*.vvs",
604                        SUMAg_CF->X->FileSelectDlg);
605             } else {
606                SUMAg_CF->X->FileSelectDlg =
607                   SUMA_CreateFileSelectionDialogStruct (
608                        (Widget) EngineData->ip, SUMA_FILE_SAVE, YUP,
609                        SUMA_SaveVisualState, (void *)sv,
610                        NULL, NULL,
611                        "*.vvs",
612                        SUMAg_CF->X->FileSelectDlg);
613             }
614             SUMAg_CF->X->FileSelectDlg =
615                SUMA_CreateFileSelectionDialog ("Select Viewer Settings File",
616                                                 &SUMAg_CF->X->FileSelectDlg);
617             break;
618 
619          case SE_OpenSurfCont:
620             /* opens the surface controller
621             Expects SO in vp */
622             if (EngineData->vp_Dest != NextComCode ) {
623                fprintf (SUMA_STDERR,
624                         "Error %s: Data not destined correctly for %s (%d).\n",
625                         FuncName, NextCom, NextComCode);
626                break;
627             }
628             if (!sv) sv = &(SUMAg_SVv[0]);
629             ado = (SUMA_ALL_DO *)EngineData->vp;
630             if (!SUMA_viewSurfaceCont(NULL, ado, sv)) {
631                SUMA_S_Err("Failed open surfcont");
632                break;
633             }
634             break;
635 
636          case SE_OneOnly:
637             if (EngineData->vp_Dest != NextComCode ) {
638                fprintf (SUMA_STDERR,
639                   "Error %s: Data not destined correctly for %s (%d).\n",
640                   FuncName, NextCom, NextComCode);
641                break;
642             }
643             if (!sv) sv = &(SUMAg_SVv[0]);
644             ado = (SUMA_ALL_DO *)EngineData->vp;
645             if (!SUMA_ColPlaneShowOneFore_Set (ado, YUP,
646                                  EngineData->Src == SES_SumaWidget)) {
647                SUMA_S_Err("Failed to set one only");
648                break;
649             }
650             break;
651 
652          case SE_OpenDsetFileSelection:
653              {
654                char sbuf[128];
655                /* opens the dataset file selection window.
656                   Expects SO in vp and a position reference
657                   widget typecast to ip, the latter can be null.*/
658 
659                if (  EngineData->vp_Dest != NextComCode ||
660                      EngineData->ip_Dest != NextComCode ) {
661                   fprintf (SUMA_STDERR,
662                      "Error %s: Data not destined correctly for %s (%d).\n",
663                      FuncName, NextCom, NextComCode);
664                   break;
665                }
666 
667                /* wildcard selection */
668                SO = (SUMA_SurfaceObject *)EngineData->vp;
669                if (!SUMA_WildcardChoice(1, SO, sbuf)) {
670                   sprintf(sbuf, "*.dset");
671                }
672 
673                /*Load data from file */
674                if (!sv) sv = &(SUMAg_SVv[0]);
675                if (!EngineData->ip) {
676                   SUMAg_CF->X->FileSelectDlg =
677                      SUMA_CreateFileSelectionDialogStruct (
678                         sv->X->TOPLEVEL,
679                         SUMA_FILE_OPEN, YUP,
680                         SUMA_LoadDsetOntoSO,
681                         (void *)EngineData->vp,
682                         NULL, NULL,
683                         sbuf,
684                         SUMAg_CF->X->FileSelectDlg);
685                } else {
686                   SUMAg_CF->X->FileSelectDlg =
687                      SUMA_CreateFileSelectionDialogStruct (
688                         (Widget) EngineData->ip,
689                         SUMA_FILE_OPEN, YUP,
690                         SUMA_LoadDsetOntoSO,
691                         (void *)EngineData->vp,
692                         NULL, NULL,
693                         sbuf,
694                         SUMAg_CF->X->FileSelectDlg);
695                }
696                if (SO && SO->Side == SUMA_RIGHT) {
697                   sprintf(sbuf,"Select RH Dset File");
698                } else if (SO && SO->Side == SUMA_LEFT) {
699                   sprintf(sbuf,"Select LH Dset File");
700                } else sprintf(sbuf,"Select Dset File");
701 
702                SUMAg_CF->X->FileSelectDlg =
703                   SUMA_CreateFileSelectionDialog (
704                      sbuf,
705                      &SUMAg_CF->X->FileSelectDlg);
706             }
707             break;
708 
709          case SE_OpenDsetFile:
710             /* opens the dataset file, Expects SO in vp and a name in cp*/
711             if (  EngineData->vp_Dest != NextComCode ||
712                   EngineData->cp_Dest != NextComCode ) {
713                fprintf (SUMA_STDERR,
714                         "Error %s: Data not destined correctly for %s (%d).\n",
715                         FuncName, NextCom, NextComCode);
716                break;
717             }
718             SUMA_LoadDsetOntoSO(EngineData->cp, EngineData->vp);
719             break;
720 
721          case SE_SaveMaskFileSelection:
722              {
723                char sbuf[128];
724                /* save the mask file selection window.
725                   Expects NULL in vp for now. Kept vp here
726                   in case I need it in the future.
727                   Also needs a position reference
728                   widget typecast to ip, the latter can be null.*/
729 
730                if (  EngineData->vp_Dest != NextComCode ||
731                      EngineData->ip_Dest != NextComCode ) {
732                   fprintf (SUMA_STDERR,
733                      "Error %s: Data not destined correctly for %s (%d).\n",
734                      FuncName, NextCom, NextComCode);
735                   break;
736                }
737 
738                /* wildcard selection */
739                sprintf(sbuf, "*.*.mo");
740 
741                /*Load data from file */
742                if (!sv) sv = &(SUMAg_SVv[0]);
743                if (!EngineData->ip) {
744                   SUMAg_CF->X->FileSelectDlg =
745                      SUMA_CreateFileSelectionDialogStruct (
746                         sv->X->TOPLEVEL,
747                         SUMA_FILE_SAVE, YUP,
748                         SUMA_SaveMultiMasks,
749                         (void *)EngineData->vp,
750                         NULL, NULL,
751                         sbuf,
752                         SUMAg_CF->X->FileSelectDlg);
753                } else {
754                   SUMAg_CF->X->FileSelectDlg =
755                      SUMA_CreateFileSelectionDialogStruct (
756                         (Widget) EngineData->ip,
757                         SUMA_FILE_SAVE, YUP,
758                         SUMA_SaveMultiMasks,
759                         (void *)EngineData->vp,
760                         NULL, NULL,
761                         sbuf,
762                         SUMAg_CF->X->FileSelectDlg);
763                }
764 
765                sprintf(sbuf,"Enter Masks Filename");
766                SUMAg_CF->X->FileSelectDlg =
767                   SUMA_CreateFileSelectionDialog (
768                      sbuf,
769                      &SUMAg_CF->X->FileSelectDlg);
770             }
771             break;
772 
773          case SE_OpenMaskFileSelection:
774              {
775                char sbuf[128];
776                /* opens the mask file selection window.
777                   Expects NULL in vp for now. Kept vp here
778                   in case I need it in the future.
779                   Also needs a position reference
780                   widget typecast to ip, the latter can be null.*/
781 
782                if (  EngineData->vp_Dest != NextComCode ||
783                      EngineData->ip_Dest != NextComCode ) {
784                   fprintf (SUMA_STDERR,
785                      "Error %s: Data not destined correctly for %s (%d).\n",
786                      FuncName, NextCom, NextComCode);
787                   break;
788                }
789 
790                /* wildcard selection */
791                sprintf(sbuf, "*.*.mo");
792 
793                /*Load data from file */
794                if (!sv) sv = &(SUMAg_SVv[0]);
795                if (!EngineData->ip) {
796                   SUMAg_CF->X->FileSelectDlg =
797                      SUMA_CreateFileSelectionDialogStruct (
798                         sv->X->TOPLEVEL,
799                         SUMA_FILE_OPEN, YUP,
800                         SUMA_LoadMultiMasks,
801                         (void *)EngineData->vp,
802                         NULL, NULL,
803                         sbuf,
804                         SUMAg_CF->X->FileSelectDlg);
805                } else {
806                   SUMAg_CF->X->FileSelectDlg =
807                      SUMA_CreateFileSelectionDialogStruct (
808                         (Widget) EngineData->ip,
809                         SUMA_FILE_OPEN, YUP,
810                         SUMA_LoadMultiMasks,
811                         (void *)EngineData->vp,
812                         NULL, NULL,
813                         sbuf,
814                         SUMAg_CF->X->FileSelectDlg);
815                }
816 
817                sprintf(sbuf,"Select Masks File");
818                SUMAg_CF->X->FileSelectDlg =
819                   SUMA_CreateFileSelectionDialog (
820                      sbuf,
821                      &SUMAg_CF->X->FileSelectDlg);
822             }
823             break;
824 
825          case SE_OpenMaskFile:
826             /* opens the dataset file, Expects nothing in vp and a name in cp*/
827             if (  EngineData->vp_Dest != NextComCode ||
828                   EngineData->cp_Dest != NextComCode ) {
829                fprintf (SUMA_STDERR,
830                         "Error %s: Data not destined correctly for %s (%d).\n",
831                         FuncName, NextCom, NextComCode);
832                break;
833             }
834             SUMA_LoadMultiMasks(EngineData->cp, EngineData->vp);
835             break;
836 
837          case SE_OpenColFile:
838             /* opens the color file, Expects SO in vp and a name in cp*/
839             if (  EngineData->vp_Dest != NextComCode ||
840                   EngineData->cp_Dest != NextComCode ) {
841                fprintf (SUMA_STDERR,
842                         "Error %s: Data not destined correctly for %s (%d).\n",
843                         FuncName, NextCom, NextComCode);
844                break;
845             }
846             SUMA_LoadColorPlaneFile(EngineData->cp, EngineData->vp);
847             break;
848 
849          case SE_OpenCmapFileSelection:
850             /* opens the Cmap file selection window.
851             Expects ADO in vp and a position reference widget
852             typecast to ip, the latter can be null.*/
853 
854             if (  EngineData->vp_Dest != NextComCode ||
855                   EngineData->ip_Dest != NextComCode ) {
856                fprintf (SUMA_STDERR,
857                         "Error %s: Data not destined correctly for %s (%d).\n",
858                         FuncName, NextCom, NextComCode);
859                break;
860             }
861 
862             /*Load colors from file */
863             if (!sv) sv = &(SUMAg_SVv[0]);
864             if (!EngineData->ip) {
865                SUMAg_CF->X->FileSelectDlg =
866                   SUMA_CreateFileSelectionDialogStruct (
867                      sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
868                      SUMA_LoadCmapFile, (void *)EngineData->vp,
869                      NULL, NULL,
870                      "*.cmap",
871                      SUMAg_CF->X->FileSelectDlg);
872             } else {
873                SUMAg_CF->X->FileSelectDlg =
874                   SUMA_CreateFileSelectionDialogStruct (
875                      (Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
876                      SUMA_LoadCmapFile, (void *)EngineData->vp,
877                      NULL, NULL,
878                      "*.cmap",
879                      SUMAg_CF->X->FileSelectDlg);
880             }
881 
882             SUMAg_CF->X->FileSelectDlg =
883                SUMA_CreateFileSelectionDialog (
884                   "Select Cmap File", &SUMAg_CF->X->FileSelectDlg);
885 
886             break;
887          case SE_OpenColFileSelection:
888             /* opens the color file selection window.
889             Expects SO in vp and a position reference widget typecast to ip,
890             the latter can be null.*/
891 
892             if (EngineData->vp_Dest != NextComCode ||
893                   EngineData->ip_Dest != NextComCode ) {
894                fprintf (SUMA_STDERR,
895                         "Error %s: Data not destined correctly for %s (%d).\n",
896                         FuncName, NextCom, NextComCode);
897                break;
898             }
899 
900             /*Load colors from file */
901             if (!sv) sv = &(SUMAg_SVv[0]);
902             if (!EngineData->ip) {
903                SUMAg_CF->X->FileSelectDlg =
904                   SUMA_CreateFileSelectionDialogStruct (
905                      sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
906                      SUMA_LoadColorPlaneFile, (void *)EngineData->vp,
907                      NULL, NULL,
908                      "*.col",
909                      SUMAg_CF->X->FileSelectDlg);
910             } else {
911                SUMAg_CF->X->FileSelectDlg =
912                   SUMA_CreateFileSelectionDialogStruct (
913                      (Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
914                      SUMA_LoadColorPlaneFile, (void *)EngineData->vp,
915                      NULL, NULL,
916                      "*.col",
917                      SUMAg_CF->X->FileSelectDlg);
918             }
919 
920             SUMAg_CF->X->FileSelectDlg =
921                SUMA_CreateFileSelectionDialog (
922                   "Select Node Color File", &SUMAg_CF->X->FileSelectDlg);
923 
924             break;
925 
926 
927          case SE_OpenDrawROI:
928             /* opens the DrawROI window, expects a surface viewer
929                pointer in EngineData->Srcp*/
930             {
931                SUMA_DRAWN_ROI *DrawnROI=NULL;
932 
933                if (!sv) {
934                   fprintf (SUMA_STDERR, "Error %s: Null sv.\n", FuncName);
935                   SUMA_RETURN(NOPE);
936                }
937 
938                /* determine if there are ROIs being drawn on surfaces
939                   displayed here */
940                DrawnROI = NULL;
941                /* start with the Focus_SO */
942                if ((SO = SUMA_SV_Focus_SO(sv))) {
943                   DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv,
944                                                        SUMAg_N_DOv);
945                }
946                if (!DrawnROI) { /* none found on focus surface, check
947                                  other surfaces in this viewer */
948                   N_SOlist = SUMA_RegisteredSOs(sv, SUMAg_DOv, SOlist);
949                   if (N_SOlist) {
950                      it = 0;
951                      do {
952                         DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv,
953                                                              SUMAg_N_DOv);
954                         ++it;
955                      } while (!DrawnROI && it < N_SOlist);
956                   }
957                }
958 
959                /* call function to create ROI window */
960                if (!SUMA_OpenDrawROIWindow (DrawnROI)) {
961                   SUMA_RegisterMessage (SUMAg_CF->MessageList,
962                                         "Failed to open Draw ROI window",
963                                         FuncName,
964                                         SMT_Error, SMA_LogAndPopup);
965 
966                }
967                break;
968 
969             }
970          case SE_SetRenderMode:
971             { /* sets the rendering mode of a surface,
972                expects SO in vp and rendering mode in i*/
973                SO = (SUMA_SurfaceObject *)EngineData->vp;
974                SUMA_SET_SO_POLYMODE(SO,EngineData->i);
975             }
976             break;
977 
978          case SE_SetTransMode:
979             { /* sets the transparency value of a surface,
980                expects SO in vp and TransMode in i*/
981                SO = (SUMA_SurfaceObject *)EngineData->vp;
982                SUMA_Set_ADO_TransMode((SUMA_ALL_DO *)SO,EngineData->i, 0, 0);
983             }
984             break;
985 
986          case SE_SetATransMode:
987             { /* sets the transparency value of a surface,
988                expects SO in vp and TransMode in i*/
989                ado = (SUMA_ALL_DO *)EngineData->vp;
990                SUMA_Set_ADO_TransMode(ado,EngineData->i, 0, 0);
991             }
992             break;
993 
994          case SE_SetDsetViewMode:
995             { /* sets the viewing mode of a dset,
996                expects ADO in vp and rendering mode in i*/
997                SUMA_COLOR_MAP *cmp=NULL;
998                static int nwarn=0, nwarn2=0;
999 
1000                ado = (SUMA_ALL_DO *)EngineData->vp;
1001                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1002                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1003                   SUMA_S_Err("No cur plane");
1004                   break;
1005                }
1006                it = SUMA_ABS(curColPlane->ShowMode);
1007                if (EngineData->i == SW_SurfCont_DsetViewXXX) {
1008                   curColPlane->ShowMode =
1009                      -SUMA_ABS(curColPlane->ShowMode);
1010                } else {
1011                   curColPlane->ShowMode =  EngineData->i ;
1012                }
1013                if (strcmp(curColPlane->cmapname,"explicit")) {
1014                   /* Can we do contours? */
1015                   cmp = SUMA_FindNamedColMap(
1016                                  curColPlane->cmapname);
1017                   if (!cmp) { SUMA_S_Err("Unexpected null colormap"); break;}
1018                   if (SUMA_NeedsLinearizing(cmp)) {
1019                      if (EngineData->i == SW_SurfCont_DsetViewCon   ||
1020                          EngineData->i == SW_SurfCont_DsetViewCaC ) {
1021                         if (!nwarn) {
1022                            SUMA_SLP_Note("Cannot do contouring with colormaps\n"
1023                                          "that panes of unequal sizes.\n"
1024                                          "Contouring turned off.\n"
1025                                          "Notice shown once per session.");
1026                            ++nwarn;
1027                         }
1028                         curColPlane->ShowMode = it; /* get back */
1029                         SUMA_Set_Menu_Widget( SurfCont->DsetViewModeMenu,
1030                            SUMA_ShowMode2ShowModeMenuItem(it));
1031                         /* kill current contours, if any */
1032                         SUMA_KillOverlayContours(curColPlane);
1033                      }
1034                   }
1035                   /* if new mode require contours, better regenerate them */
1036                   if ( (it != SW_SurfCont_DsetViewCon &&
1037                         it != SW_SurfCont_DsetViewCaC ) &&
1038                        (curColPlane->ShowMode ==
1039                                  SW_SurfCont_DsetViewCon   ||
1040                         curColPlane->ShowMode ==
1041                                  SW_SurfCont_DsetViewCaC) ) {
1042                      if (!SUMA_ColorizePlane(curColPlane)) {
1043                         SUMA_S_Err( "Police at the station - "
1044                                     "and they don't look friendly.");
1045                      }
1046                   }
1047                } else {
1048                   SUMA_LH("lam");
1049                   /* explicit colormap no need for all the complications above*/
1050                      if (EngineData->i == SW_SurfCont_DsetViewCon   ||
1051                          EngineData->i == SW_SurfCont_DsetViewCaC ) {
1052                         if (!nwarn2) {
1053                            SUMA_SLP_Note("Cannot do contouring with explicitly\n"
1054                                          "colored datasets. \n"
1055                                          "Notice shown once per session.");
1056                            ++nwarn2;
1057                         }
1058                         curColPlane->ShowMode = it; /* get back */
1059                         SUMA_Set_Menu_Widget( SurfCont->DsetViewModeMenu,
1060                            SUMA_ShowMode2ShowModeMenuItem(it));
1061                         /* kill current contours, if any . There should be none
1062                            here but there is no harm */
1063                         SUMA_KillOverlayContours(curColPlane);
1064                      }
1065                }
1066                if (!SUMA_Remixedisplay (ado)) {
1067                   SUMA_S_Err("Dunno what happened here");
1068                }
1069             }
1070             break;
1071 
1072          case SE_SetDsetFont:
1073             { /* sets the Font for nodes of a (graph) dset,
1074                expects ADO in vp and rendering mode in i*/
1075                ado = (SUMA_ALL_DO *)EngineData->vp;
1076                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1077                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1078                   SUMA_S_Err("No cur plane");
1079                   break;
1080                }
1081 
1082                if (EngineData->i == SW_SurfCont_DsetFontXXX) {
1083                   curColPlane->Font =
1084                      -SUMA_ABS(curColPlane->Font);
1085                } else {
1086                   curColPlane->Font = EngineData->i;
1087                }
1088                SUMA_ADO_Flush_Pick_Buffer(ado, sv);
1089                if (!SUMA_Remixedisplay (ado)) {
1090                   SUMA_S_Err("Dunno what happened here");
1091                }
1092             }
1093             break;
1094 
1095          case SE_SetDsetThrough:
1096             { /* sets the sphere radius for nodes of a (graph) dset,
1097                expects ADO in vp and rendering mode in i*/
1098                ado = (SUMA_ALL_DO *)EngineData->vp;
1099                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1100                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1101                   SUMA_S_Err("No cur plane");
1102                   break;
1103                }
1104 
1105                if (EngineData->i == SW_SurfCont_DsetThroughXXX) {
1106                   curColPlane->Through =
1107                      -SUMA_ABS(curColPlane->Through);
1108                } else {
1109                   curColPlane->Through = EngineData->i;
1110                }
1111                SUMA_ADO_Flush_Pick_Buffer(ado, sv);
1112                if (!SUMA_Remixedisplay (ado)) {
1113                   SUMA_S_Err("Dunno what happened here");
1114                }
1115             }
1116             break;
1117 
1118          case SE_SetDsetNodeRad:
1119             { /* sets the sphere radius for nodes of a (graph) dset,
1120                expects ADO in vp and rendering mode in i*/
1121                ado = (SUMA_ALL_DO *)EngineData->vp;
1122                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1123                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1124                   SUMA_S_Err("No cur plane");
1125                   break;
1126                }
1127 
1128                if (EngineData->i == SW_SurfCont_DsetNodeRadXXX) {
1129                   curColPlane->NodeRad =
1130                      -SUMA_ABS(curColPlane->NodeRad);
1131                } else {
1132                   curColPlane->NodeRad = EngineData->i;
1133                }
1134                SUMA_ADO_Flush_Pick_Buffer(ado, sv);
1135                if (!SUMA_Remixedisplay (ado)) {
1136                   SUMA_S_Err("Dunno what happened here");
1137                }
1138             }
1139             break;
1140 
1141          case SE_SetDsetEdgeThick:
1142             { /* sets the thickness of a (graph's) edges,
1143                expects ADO in vp and rendering mode in i*/
1144                ado = (SUMA_ALL_DO *)EngineData->vp;
1145                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1146                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1147                   SUMA_S_Err("No cur plane");
1148                   break;
1149                }
1150 
1151                curColPlane->EdgeThick = EngineData->i;
1152                SUMA_ADO_Flush_Pick_Buffer(ado, sv);
1153                if (!SUMA_Remixedisplay (ado)) {
1154                   SUMA_S_Err("Dunno what happened here");
1155                }
1156             }
1157             break;
1158 
1159          case SE_SetDsetEdgeStip:
1160             { /* sets the stippling of a (graph's) edges,
1161                expects ADO in vp and rendering mode in i*/
1162                ado = (SUMA_ALL_DO *)EngineData->vp;
1163                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1164                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1165                   SUMA_S_Err("No cur plane");
1166                   break;
1167                }
1168 
1169                if (EngineData->i == SW_SurfCont_DsetEdgeStipXXX) {
1170                   curColPlane->EdgeStip =
1171                      -SUMA_ABS(curColPlane->EdgeStip);
1172                } else {
1173                   curColPlane->EdgeStip = EngineData->i;
1174                }
1175 
1176                if (!SUMA_Remixedisplay (ado)) {
1177                   SUMA_S_Err("Dunno what happened here");
1178                }
1179             }
1180             break;
1181 
1182          case SE_SetTractStyle:
1183             { /* sets the stippling of a (graph's) edges,
1184                expects ADO in vp and rendering mode in i*/
1185                ado = (SUMA_ALL_DO *)EngineData->vp;
1186                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1187                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1188                   SUMA_S_Err("No cur plane");
1189                   break;
1190                }
1191 
1192                if (EngineData->i == SW_SurfCont_TractStyleSOLID) {
1193                   curColPlane->EdgeStip =
1194                      -SUMA_ABS(curColPlane->EdgeStip);
1195                } else {
1196                   curColPlane->EdgeStip = EngineData->i;
1197                }
1198 
1199                if (!SUMA_Remixedisplay (ado)) {
1200                   SUMA_S_Err("Dunno what happened here");
1201                }
1202             }
1203             break;
1204 
1205          case SE_SetDsetAlphaVal:
1206             { /* sets the stippling of a (graph's) edges,
1207                expects ADO in vp and rendering mode in i*/
1208                ado = (SUMA_ALL_DO *)EngineData->vp;
1209                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1210                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1211                   SUMA_S_Err("No cur plane");
1212                   break;
1213                }
1214 
1215                SUMA_LH("Setting AlphaVal = %d", EngineData->i);
1216                if (curColPlane->AlphaVal != EngineData->i) {
1217                   curColPlane->AlphaVal = EngineData->i;
1218                   /* This requires recoloring because the alpha values may
1219                      depend on the data */
1220                   if (!SUMA_ColorizePlane (curColPlane)) {
1221                      SUMA_SLP_Err("Failed to colorize plane.\n");
1222                      SUMA_RETURN(0);
1223                   }
1224 
1225                   if (!SUMA_Remixedisplay (ado)) {
1226                      SUMA_S_Err("Dunno what happened here");
1227                   }
1228                }
1229             }
1230             break;
1231 
1232          case SE_SetDsetNodeCol:
1233             { /* sets the node coloring mode of a (graph) dset,
1234                expects ADO in vp and rendering mode in i*/
1235                ado = (SUMA_ALL_DO *)EngineData->vp;
1236                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1237                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1238                   SUMA_S_Err("No cur plane");
1239                   break;
1240                }
1241 
1242                curColPlane->NodeCol = EngineData->i;
1243                if (!SUMA_Remixedisplay (ado)) {
1244                   SUMA_S_Err("Dunno what happened here");
1245                }
1246             }
1247             break;
1248 
1249          case SE_SetDsetTxtShad:
1250             { /* sets the text shading for nodes of a (graph) dset,
1251                expects ADO in vp and rendering mode in i*/
1252                ado = (SUMA_ALL_DO *)EngineData->vp;
1253                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1254                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1255                   SUMA_S_Err("No cur plane");
1256                   break;
1257                }
1258 
1259                curColPlane->TxtShad = EngineData->i;
1260                if (!SUMA_Remixedisplay (ado)) {
1261                   SUMA_S_Err("Dunno what happened here");
1262                }
1263             }
1264             break;
1265 
1266          case SE_SetDsetGmatBord:
1267             { /* sets the border width of a (graph) dset matrix,
1268                expects ADO in vp and rendering mode in i*/
1269                ado = (SUMA_ALL_DO *)EngineData->vp;
1270                if (!(curColPlane = SUMA_ADO_CurColPlane(ado)) ||
1271                    !(SurfCont = SUMA_ADO_Cont(ado))) {
1272                   SUMA_S_Err("No cur plane");
1273                   break;
1274                }
1275 
1276                /* Get rid of matrix */
1277                curColPlane->BordFrac = EngineData->i;
1278                SUMA_GDSET_refresh_matrix_nido(SUMA_ADO_Dset(ado), 1);
1279                /* Update all viewers showing ado */
1280                SUMA_UpdateViewPoint_RegisteredADO(ado, 1);
1281                if (!SUMA_Remixedisplay (ado)) {
1282                   SUMA_S_Err("Dunno what happened here");
1283                }
1284             }
1285             break;
1286 
1287          case SE_SetTractMask:
1288             { /* sets the masking mode for tracts,
1289                expects ADO in vp and masking mode in i*/
1290                SUMA_TRACT_SAUX *TSaux;
1291                ado = (SUMA_ALL_DO *)EngineData->vp;
1292                if (!(TSaux = SUMA_ADO_TSaux(ado))) {
1293                   SUMA_S_Err("No valid pointers");
1294                   break;
1295                }
1296 
1297                TSaux->TractMask = EngineData->i;
1298 
1299                SUMA_ADO_Flush_Pick_Buffer(ado, sv);
1300                if (!SUMA_Remixedisplay (ado)) {
1301                   SUMA_S_Err("Dunno what happened here");
1302                }
1303             }
1304             break;
1305 
1306          case SE_UpdateLog:
1307             /* Updates the Log window if it is open */
1308             {
1309                if (SUMAg_CF->X->Log_TextShell) {
1310                   char *s = NULL;
1311                   s = SUMA_BuildMessageLog (SUMAg_CF->MessageList);
1312                   SUMAg_CF->X->Log_TextShell->CursorAtBottom = YUP;
1313                   (void) SUMA_CreateTextShell (s,
1314                               "Message Log", SUMAg_CF->X->Log_TextShell);
1315                   XRaiseWindow(SUMAg_CF->X->DPY_controller1,
1316                                  XtWindow(SUMAg_CF->X->Log_TextShell->toplevel));
1317                   if (s) SUMA_free(s);
1318                }
1319             }
1320             break;
1321 
1322          case SE_Log:
1323             /* opens log window, needs nothing for the moment*/
1324             {
1325                char *s = NULL;
1326                if (SUMAg_CF->X->Log_TextShell) { /* just raise it */
1327                   XRaiseWindow(  SUMAg_CF->X->DPY_controller1,
1328                                  XtWindow(SUMAg_CF->X->Log_TextShell->toplevel));
1329                   break;
1330                }else { /* create it */
1331                   s = SUMA_BuildMessageLog (SUMAg_CF->MessageList);
1332                   if (LocalHead)
1333                      fprintf (SUMA_STDERR,
1334                               "%s: Message string:\n%s\n", FuncName, s);
1335                   LogShell =  SUMA_CreateTextShellStruct (
1336                                   SUMA_Message_open, NULL, NULL,
1337                                   SUMA_Message_destroyed, NULL, NULL);
1338                   if (!LogShell) {
1339                      fprintf (SUMA_STDERR,
1340                             "Error %s: Failed in SUMA_CreateTextShellStruct.\n",
1341                             FuncName);
1342                      break;
1343                   }
1344                   SUMAg_CF->X->Log_TextShell =
1345                      SUMA_CreateTextShell(s, "SUMA log", LogShell);
1346                   SUMA_free(s);
1347                }
1348             }
1349             break;
1350 
1351          case SE_Help:
1352             /* opens help window, needs nothing for the moment*/
1353             {
1354                char *s = NULL;
1355                if (SUMAg_CF->X->Help_TextShell) { /* just raise it */
1356                      XRaiseWindow(SUMAg_CF->X->DPY_controller1,
1357                               XtWindow(SUMAg_CF->X->Help_TextShell->toplevel));
1358                } else {
1359                   SUMAg_CF->X->Help_TextShell =  SUMA_CreateTextShellStruct (
1360                                     SUMA_Help_open, NULL, NULL,
1361                                     SUMA_Help_destroyed, NULL,
1362                         "https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/"
1363                                     "SUMA/Viewer.html#mouse-keyboard");
1364                   if (!SUMAg_CF->X->Help_TextShell) {
1365                      fprintf (SUMA_STDERR,
1366                            "Error %s: Failed in SUMA_CreateTextShellStruct.\n",
1367                            FuncName);
1368                      break;
1369                   }
1370                }
1371 
1372                s = SUMA_help_message_Info(TXT);
1373                if (!s) {
1374                   fprintf (SUMA_STDERR,
1375                            "Error %s: Failed in SUMA_help_message_Info.\n",
1376                            FuncName);
1377                   break;
1378                }else {
1379                   SUMAg_CF->X->Help_TextShell =
1380                         SUMA_CreateTextShell(
1381                               s, "SUMA help", SUMAg_CF->X->Help_TextShell);
1382                   SUMA_free(s);
1383                }
1384             }
1385             break;
1386 
1387          case SE_Help_Xform: /* use same window as SUMA's help */
1388             /* opens help window, needs xform struct in vp */
1389             {
1390                SUMA_XFORM *xf=NULL;
1391                char *s = NULL;
1392                if (EngineData->vp_Dest != NextComCode) {
1393                   fprintf (SUMA_STDERR,
1394                            "Error %s: "
1395                            "Data not destined correctly for %s (%d).\n",
1396                      FuncName, NextCom, NextComCode);
1397                   break;
1398                }
1399                if (!(xf = (SUMA_XFORM *)EngineData->vp)) {
1400                   SUMA_S_Err("NULL input");
1401                   break;
1402                }
1403                if (SUMAg_CF->X->Help_TextShell) { /* just raise it */
1404                      XRaiseWindow(SUMAg_CF->X->DPY_controller1,
1405                               XtWindow(SUMAg_CF->X->Help_TextShell->toplevel));
1406                } else { /* make one */
1407                   SUMAg_CF->X->Help_TextShell =  SUMA_CreateTextShellStruct (
1408                                     SUMA_Help_open, NULL, NULL,
1409                                     SUMA_Help_destroyed, NULL, NULL);
1410                   if (!SUMAg_CF->X->Help_TextShell) {
1411                      fprintf (SUMA_STDERR,
1412                            "Error %s: Failed in SUMA_CreateTextShellStruct.\n",
1413                            FuncName);
1414                      break;
1415                   }
1416                }
1417 
1418                if (!strcmp(xf->name,"Dot")) {
1419                   s = SUMA_help_xform_dot_message_Info();
1420                } else {
1421                   s = SUMA_copy_string("aint no help for this xform honey");
1422                }
1423 
1424                if (!s) {
1425                   fprintf (SUMA_STDERR,
1426                         "Error %s: Failed somehow.\n",
1427                         FuncName);
1428                   break;
1429                }else {
1430                   SUMAg_CF->X->Help_TextShell =
1431                         SUMA_CreateTextShell(
1432                               s, "SUMA Xform help",
1433                               SUMAg_CF->X->Help_TextShell);
1434                   SUMA_free(s);
1435                }
1436             }
1437             break;
1438 
1439          case SE_Help_Cmap:
1440             /* opens Cmap help window, needs Cmap in vp*/
1441             {
1442                char *s = NULL;
1443                SUMA_COLOR_MAP *Cmp;
1444                if (EngineData->vp_Dest != NextComCode) {
1445                   fprintf (SUMA_STDERR,
1446                            "Error %s: "
1447                            "Data not destined correctly for %s (%d).\n",
1448                      FuncName, NextCom, NextComCode);
1449                   break;
1450                }
1451                Cmp = (SUMA_COLOR_MAP *)EngineData->vp;
1452                if (SUMAg_CF->X->Help_Cmap_TextShell) { /* just raise it */
1453                      XRaiseWindow(
1454                         SUMAg_CF->X->DPY_controller1,
1455                         XtWindow(SUMAg_CF->X->Help_Cmap_TextShell->toplevel));
1456                      break;
1457                }
1458 
1459                s = SUMA_help_Cmap_message_Info(Cmp, 0);
1460                if (!s) {
1461                   fprintf (SUMA_STDERR,
1462                            "Error %s: Failed in SUMA_help_Cmap_message_Info.\n",                            FuncName);
1463                   break;
1464                }else {
1465                   TextShell =
1466                      SUMA_CreateTextShellStruct (  SUMA_Help_Cmap_open,
1467                                                    NULL, NULL,
1468                                                    SUMA_Help_Cmap_destroyed,
1469                                                    NULL,
1470                               "https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/"
1471                               "SUMA/Viewer.html#colormap-keyboard-controls");
1472                   if (!TextShell) {
1473                      fprintf (SUMA_STDERR,
1474                               "Error %s: "
1475                               "Failed in SUMA_CreateTextShellStruct.\n",
1476                               FuncName);
1477                      break;
1478                   }
1479                   SUMAg_CF->X->Help_Cmap_TextShell =
1480                      SUMA_CreateTextShell(s, "SUMA Colormap help", TextShell);
1481                   SUMA_free(s);
1482                }
1483             }
1484             break;
1485          case SE_Help_Plot:
1486             /* opens Plot help window, needs nothing in vp*/
1487             {
1488                char *s = NULL;
1489 
1490                if (SUMAg_CF->X->Help_Plot_TextShell) { /* just raise it */
1491                      XRaiseWindow(
1492                         SUMAg_CF->X->DPY_controller1,
1493                         XtWindow(SUMAg_CF->X->Help_Plot_TextShell->toplevel));
1494                      break;
1495                }
1496 
1497                s = SUMA_help_Plot_message_Info();
1498                if (!s) {
1499                   fprintf (SUMA_STDERR,
1500                            "Error %s: Failed in SUMA_help_Plot_message_Info.\n",                            FuncName);
1501                   break;
1502                }else {
1503                   TextShell =
1504                      SUMA_CreateTextShellStruct (  SUMA_Help_Plot_open,
1505                                                    NULL, NULL,
1506                                                    SUMA_Help_Plot_destroyed,
1507                                                    NULL, NULL);
1508                   if (!TextShell) {
1509                      fprintf (SUMA_STDERR,
1510                               "Error %s: "
1511                               "Failed in SUMA_CreateTextShellStruct.\n",
1512                               FuncName);
1513                      break;
1514                   }
1515                   SUMAg_CF->X->Help_Plot_TextShell =
1516                      SUMA_CreateTextShell(s, "SUMA Plot help", TextShell);
1517                   SUMA_free(s);
1518                }
1519             }
1520             break;
1521 
1522          case SE_Whereami:
1523             /* opens wheremi text window,
1524                Expects SO in vp, and a string for the whereami data
1525                In the future, it should expect a list of whereami
1526                data and it should build the report on its own.
1527                Each whereami datum should contain atlas info, space, coordinate,
1528                label, etc. */
1529             {
1530                char *s = NULL;
1531 
1532                if (EngineData->vp_Dest != NextComCode ||
1533                    EngineData->s_Dest != NextComCode) {
1534                   fprintf (SUMA_STDERR,
1535                           "Error %s: Data not destined correctly for %s (%d).\n",
1536                            FuncName, NextCom, NextComCode);
1537                   break;
1538                }
1539                if (!sv) sv = &(SUMAg_SVv[0]);
1540                if (!(SO = (SUMA_SurfaceObject *)EngineData->vp)) break;
1541                if (!(s = (char*)EngineData->s)) break;
1542 
1543                if (!SUMAg_CF->X->Whereami_TextShell) {
1544                   if (!(SUMAg_CF->X->Whereami_TextShell =
1545                            SUMA_CreateTextShellStruct (  SUMA_Whereami_open,
1546                                                    NULL, NULL,
1547                                                    SUMA_Whereami_destroyed,
1548                                                    NULL, NULL))) {
1549                      SUMA_S_Err("Failed to create TextShellStruct.");
1550                      break;
1551                   }
1552                }
1553 
1554                if (SUMAg_CF->X->Whereami_TextShell) { /* update */
1555                      SUMAg_CF->X->Whereami_TextShell->CursorAtBottom = YUP;
1556                      (void) SUMA_CreateTextShell (s,
1557                               "Where Thou Layeth",
1558                               SUMAg_CF->X->Whereami_TextShell);
1559                      XRaiseWindow(
1560                         SUMAg_CF->X->DPY_controller1,
1561                         XtWindow(SUMAg_CF->X->Whereami_TextShell->toplevel));
1562 
1563                }
1564             }
1565             break;
1566          case SE_Load_Group:
1567             /* Does not need a sv
1568                expects  a pointer to .spec filename in cp,
1569                         if cp is NULL then it will look for a spec structure
1570                         pointer in ip (sorry, ran out of places...)
1571                         it will also determine if surfaces in a spec structure
1572                         pointer have already been loaded from f (really, ran out
1573                         of places...) a VolumeParent name in vp,
1574                         the indices of the viewers to register the surfaces with
1575                         in iv15.
1576                         and the number of viewers specified in iv15 in i.
1577                         Surfaces are registered with all i viewers in iv15*/
1578 
1579             if (  EngineData->cp_Dest != NextComCode ||
1580                   EngineData->vp_Dest != NextComCode
1581                || EngineData->iv15_Dest != NextComCode ||
1582                   EngineData->i_Dest != NextComCode
1583                || EngineData->ip_Dest != NextComCode ||
1584                   EngineData->f_Dest != NextComCode) {
1585                fprintf (SUMA_STDERR,
1586                         "Error %s: Data not destined correctly for %s (%d).\n"
1587                         "%d %d %d %d %d %d\n",
1588                         FuncName, NextCom, NextComCode, EngineData->cp_Dest,
1589                         EngineData->vp_Dest,
1590                         EngineData->iv15_Dest, EngineData->i_Dest ,
1591                         EngineData->ip_Dest, EngineData->f_Dest);
1592                break;
1593             }
1594             {
1595      		      SUMA_SurfSpecFile Spec;
1596                char *VolParName = NULL, *specfilename = NULL;
1597 
1598                VolParName = (char *)EngineData->vp;
1599                specfilename = EngineData->cp;
1600                if (specfilename) {
1601                   /* Load The spec file */
1602 		            if (LocalHead)
1603                      fprintf (SUMA_STDERR,
1604                               "%s: Reading Spec File %s...\n",
1605                               FuncName, specfilename);
1606                   if (!SUMA_AllocSpecFields(&Spec)) {
1607                      SUMA_S_Err("Failed to initialize spec fields.");
1608                      exit(1);
1609                   }
1610                   if (!SUMA_Read_SpecFile (specfilename, &Spec)) {
1611 			            fprintf( SUMA_STDERR,
1612                               "Error %s: Error in SUMA_Read_SpecFile.\n",
1613                               FuncName);
1614 			            exit(1);
1615 		            }
1616                } else {
1617                   if (!EngineData->ip) {
1618                      fprintf( SUMA_STDERR,
1619                               "Error %s: Nothing in ip, nothing to do !\n",
1620                               FuncName);
1621                      exit(1);
1622                   }
1623                   Spec = *((SUMA_SurfSpecFile *)EngineData->ip);
1624                }
1625 
1626                /* make sure only one group was read in */
1627 		         if (Spec.N_Groups != 1) {
1628 			         if (Spec.N_Groups > 1) {
1629                      fprintf( SUMA_STDERR,
1630                            "Error %s: "
1631                            "One and only one group of surfaces is allowed "
1632                            "at the moment (%d found).\n",
1633                            FuncName, Spec.N_Groups);
1634 			            exit(1);
1635                   }
1636                   /* We hope some DOs are visible, proceed */
1637 		         } else {
1638 		            if (!EngineData->f) {
1639                      /* load one by one surfs specified in the specs file */
1640 		               if (LocalHead)
1641                         fprintf (SUMA_STDERR,
1642                                  "%s: Loading Surfaces in Spec File ...\n",
1643                                  FuncName);
1644 		               if (!SUMA_LoadSpec_eng (&Spec, SUMAg_DOv, &SUMAg_N_DOv,
1645                                              VolParName, 0, SUMAg_CF->DsetList)){
1646 			               SUMA_LH("Failed in SUMA_LoadSpec.");
1647 			               exit(1);
1648 		               }
1649                   }
1650 
1651 
1652                   /* register the new group with SUMA */
1653                   if (!SUMA_RegisterSpecGroup(SUMAg_CF, &Spec)) {
1654                      SUMA_SL_Err("Failed to register group");
1655                      break;
1656                   }
1657 
1658                }
1659 	            /* Register surfaces in Spec file or other DOs with the
1660                      surface viewer and perform setups */
1661                for (ii = 0; ii < EngineData->i; ++ii) {
1662 	               SUMA_LHv("%s: Registering surfaces with surface viewer "
1663                            "%d/%d ...\n", FuncName, ii, EngineData->i);
1664                   if (!SUMA_SetupSVforDOs (&Spec, SUMAg_DOv, SUMAg_N_DOv,
1665                                        &(SUMAg_SVv[EngineData->iv15[ii]]), 0)) {
1666 			            fprintf (SUMA_STDERR,
1667                               "Error %s: "
1668                               "Failed in SUMA_SetupSVforDOs function.\n",
1669                               FuncName);
1670 			            exit(1);
1671 		            }
1672 	            }
1673 
1674                if (LocalHead)
1675                   fprintf (SUMA_STDERR,
1676                            "%s: Adding call to Home and Redisplay \n", FuncName);
1677                /* add a call to Home and a redisplay */
1678                if (!list) {
1679                   fprintf (SUMA_STDERR,
1680                            "Error %s: Should not be inside "
1681                            "SUMA_Engine: ZSS Feb 02 05.\n", FuncName);
1682                   /* list = SUMA_CreateList();*/
1683                   break;
1684                }else {
1685                   SUMA_LH("Appending to list ");
1686                }
1687                ED = SUMA_InitializeEngineListData (SE_Home_AllVisible);
1688                if (!SUMA_RegisterEngineListCommand (  list, ED,
1689                                                       SEF_Empty, NULL,
1690                                                       SES_Afni, NULL, NOPE,
1691                                                       SEI_Tail, NULL )) {
1692                   fprintf( SUMA_STDERR,
1693                            "Error %s: Failed to register command\n", FuncName);
1694                   break;
1695                }
1696                ED = SUMA_InitializeEngineListData (SE_Redisplay_AllVisible);
1697                if (!SUMA_RegisterEngineListCommand (  list, ED,
1698                                                       SEF_Empty, NULL,
1699                                                       SES_Afni, NULL, NOPE,
1700                                                       SEI_Tail, NULL )) {
1701                   fprintf( SUMA_STDERR,
1702                            "Error %s: Failed to register command\n", FuncName);
1703                   break;
1704                }
1705 
1706                if (specfilename) {
1707                   /* locally created spec, free contents */
1708                   if (!SUMA_FreeSpecFields(&Spec)) {
1709                      SUMA_S_Err("Failed to free spec fields");
1710                      break;
1711                   }
1712 
1713                }
1714 
1715 
1716             }
1717             if (LocalHead)
1718                fprintf (SUMA_STDERR, "%s: Done in SE_Load_Spec.\n", FuncName);
1719             break;
1720 
1721          case SE_SetClip:
1722             {
1723                int iplane = -1, Delete = 0;
1724                /* expects a clipping plane name in EngineData->s,
1725                   equation in fv15 and type in i*/
1726                if (EngineData->fv15_Dest != NextComCode ||
1727                   EngineData->s_Dest != NextComCode  ||
1728                   EngineData->i_Dest != NextComCode ) {
1729                   SUMA_S_Errv("Data not destined correctly for %s (%d).\n"
1730                               , NextCom, NextComCode);
1731                   break;
1732                }
1733 
1734                /* find plane in question */
1735                iplane = -1;
1736                for (ii=0; ii<SUMAg_CF->N_ClipPlanes; ++ii) {
1737                   if (  strcmp(SUMAg_CF->ClipPlanesLabels[ii],
1738                                EngineData->s) == 0
1739                      && SUMAg_CF->ClipPlaneType[ii] ==
1740                         (SUMA_CLIP_PLANE_TYPES)EngineData->i) {
1741                      iplane = ii; break;
1742                   }
1743                }
1744 
1745                // Added by PDL to prevent extra clip plane being partially generated
1746                //   when user maniulates default plane when first enetering clipping plane
1747                //   mode or using the zero key
1748                 if (strlen(EngineData->s)<1) iplane = 0;
1749 
1750                /* stick equation where it belongs */
1751                if (EngineData->fv15[0] == 0.0 && EngineData->fv15[1] == 0.0 &&
1752                    EngineData->fv15[2] == 0.0 && EngineData->fv15[3] == 0.0) {
1753                   Delete = 1; /* no more clipping */
1754                } else {
1755                   Delete = 0; /* a plane to add, modify */
1756                }
1757 
1758                /* what to do? */
1759                if (Delete && iplane >=0) {
1760                   /* delete */
1761                   SUMAg_CF->ClipPlaneType[iplane] = SUMA_NO_CLIP_PLANE_TYPE;
1762                   SUMAg_CF->ClipPlanesLabels[iplane][0]='\0';
1763                   SUMAg_CF->ClipPlanes[4*iplane] =
1764                      SUMAg_CF->ClipPlanes[4*iplane+1] =
1765                      SUMAg_CF->ClipPlanes[4*iplane+2] =
1766                      SUMAg_CF->ClipPlanes[4*iplane+3]= 0.0;
1767                   --SUMAg_CF->N_ClipPlanes;
1768                   glDisable(SUMA_index_to_clip_plane(iplane));
1769                } else if (Delete) {
1770                   /* delete what ? */
1771                   SUMA_SL_Warn("No plane to delete");
1772                   break;
1773                } else if (!Delete && iplane < 0) {
1774                   /* add a new one */
1775                   if (SUMAg_CF->N_ClipPlanes == SUMA_MAX_N_CLIP_PLANES) {
1776                      SUMA_SLP_Err("No more clipping planes available.");
1777                      break;
1778                   }
1779                   SUMAg_CF->ClipPlaneType[SUMAg_CF->N_ClipPlanes] =
1780                                     (SUMA_CLIP_PLANE_TYPES)EngineData->i;
1781                   snprintf(SUMAg_CF->ClipPlanesLabels[SUMAg_CF->N_ClipPlanes],
1782                                           8*sizeof(char), "%s", EngineData->s);
1783                   SUMAg_CF->ClipPlanes[4*SUMAg_CF->N_ClipPlanes  ] =
1784                                                    (GLdouble)EngineData->fv15[0];
1785                   SUMAg_CF->ClipPlanes[4*SUMAg_CF->N_ClipPlanes+1] =
1786                                                    (GLdouble)EngineData->fv15[1];
1787                   SUMAg_CF->ClipPlanes[4*SUMAg_CF->N_ClipPlanes+2] =
1788                                                    (GLdouble)EngineData->fv15[2];
1789                   SUMAg_CF->ClipPlanes[4*SUMAg_CF->N_ClipPlanes+3] =
1790                                                    (GLdouble)EngineData->fv15[3];
1791                   ++SUMAg_CF->N_ClipPlanes;
1792                } else {
1793                   /* Replace an existing one */
1794                   SUMAg_CF->ClipPlaneType[iplane] =
1795                                           (SUMA_CLIP_PLANE_TYPES)EngineData->i;
1796                   snprintf(SUMAg_CF->ClipPlanesLabels[iplane],
1797                                           8*sizeof(char), "%s", EngineData->s);
1798                   SUMAg_CF->ClipPlanes[4*iplane  ] =
1799                                           (GLdouble)EngineData->fv15[0];
1800                   SUMAg_CF->ClipPlanes[4*iplane+1] =
1801                                           (GLdouble)EngineData->fv15[1];
1802                   SUMAg_CF->ClipPlanes[4*iplane+2] =
1803                                           (GLdouble)EngineData->fv15[2];
1804                   SUMAg_CF->ClipPlanes[4*iplane+3] =
1805                                           (GLdouble)EngineData->fv15[3];
1806                }
1807                ED = SUMA_InitializeEngineListData (SE_Redisplay_AllVisible);
1808                if (!SUMA_RegisterEngineListCommand (  list, ED,
1809                                                       SEF_Empty, NULL,
1810                                                       SES_Afni, NULL, NOPE,
1811                                                       SEI_Tail, NULL )) {
1812                   SUMA_S_Err("Failed to register command");
1813                   break;
1814                }
1815 
1816                /* Show the clip planes */
1817                SUMA_Show_Clip_Planes(SUMAg_CF, NULL);
1818             }
1819             break;
1820 
1821          case SE_SetLookAt:
1822             /* expects a center XYZ in EngineData->fv3[0 .. 2] */
1823             if (EngineData->fv3_Dest != NextComCode) {
1824                SUMA_S_Err("Data not destined correctly for %s (%d).\n",
1825                            NextCom, NextComCode);
1826                break;
1827             }
1828             /* calculate the transform required to bring the new look at
1829                location to the current one */
1830             {
1831                float ulook_old[3], ulook_new[3];
1832                int Step = 10, iStep;
1833                float fracUp, fracDown;
1834 
1835                ulook_old[0] = sv->GVS[sv->StdView].ViewFrom[0] -
1836                               sv->GVS[sv->StdView].ViewCenter[0];
1837                ulook_old[1] = sv->GVS[sv->StdView].ViewFrom[1] -
1838                               sv->GVS[sv->StdView].ViewCenter[1];
1839                ulook_old[2] = sv->GVS[sv->StdView].ViewFrom[2] -
1840                               sv->GVS[sv->StdView].ViewCenter[2];
1841                ulook_new[0] = ulook_new[1] = ulook_new[2] = 0.0;
1842                fm = (float **)SUMA_allocate2D(4,4,sizeof(float));
1843 
1844                for (iStep = Step; iStep >= 1; --iStep) {
1845                   fracUp = (float)(iStep)/(float)Step;
1846                   fracDown = (float)(Step - iStep)/(float)Step;
1847                   SUMA_LH("%d, fracUp %f, fracDown %f, fv3[%f %f %f]\n",
1848                           iStep, fracUp, fracDown, EngineData->fv3[0],
1849                                  EngineData->fv3[1], EngineData->fv3[2]);
1850                   ulook_new[0] = (EngineData->fv3[0] * fracUp +
1851                            sv->GVS[sv->StdView].ViewFrom[0] * fracDown)
1852                                  - sv->GVS[sv->StdView].ViewCenter[0];
1853                   ulook_new[1] = (EngineData->fv3[1] * fracUp +
1854                            sv->GVS[sv->StdView].ViewFrom[1] * fracDown)
1855                                  - sv->GVS[sv->StdView].ViewCenter[1];
1856                   ulook_new[2] = (EngineData->fv3[2] * fracUp +
1857                            sv->GVS[sv->StdView].ViewFrom[2] * fracDown)
1858                                  - sv->GVS[sv->StdView].ViewCenter[2];
1859                   if (fm == NULL) {
1860                      SUMA_S_Err("Failed to allocate fm.");
1861                      break;
1862                   }
1863                   if (!SUMA_FromToRotation (ulook_new, ulook_old, fm)) {
1864                      SUMA_S_Err("Failed in SUMA_FromToRotation.");
1865                      break;
1866                   }
1867 
1868                   /* add a SetRotMatrix to list*/
1869                   ED = SUMA_InitializeEngineListData (SE_SetRotMatrix);
1870                   ED->N_cols = 4;
1871                   ED->N_rows = 4;
1872                   if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
1873                                     SEF_fm, (void *)fm,
1874                                     EngineData->Src, EngineData->Srcp, NOPE,
1875                                     SEI_Head, NULL ))) {
1876                      SUMA_S_Err("Failed to register command");
1877                      break;
1878                   }
1879 
1880                   /* add a redisplay call */
1881                   ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
1882                   if (!SUMA_RegisterEngineListCommand (  list, ED,
1883                                     SEF_Empty, NULL,
1884                                     EngineData->Src, EngineData->Srcp, NOPE,
1885                                     SEI_After, LocElm )) {
1886                      SUMA_S_Err("Failed to register command");
1887                      break;
1888                   }
1889 
1890                }
1891                /* fm was copied into engine data, free it */
1892                SUMA_free2D((char **)fm, 4);
1893             }
1894             break;
1895 
1896          case SE_StartListening:
1897             /* expects nothing in EngineData */
1898             if (!SUMAg_CF->Listening) {
1899                SUMAg_CF->Listening = !SUMAg_CF->Listening;
1900                fprintf(SUMA_STDERR,"%s: Starting to listen ...\n", FuncName);
1901                /* Make sure special NIML rowtypes are defined before */
1902                get_NI_tract_type();
1903                /* start the listening WorkProcess */
1904                if (!SUMAg_CF->niml_work_on) {
1905                   SUMA_LH("registering SUMA_niml_workproc...");
1906                   SUMA_register_workproc(SUMA_niml_workproc, (XtPointer)sv);
1907                } else {
1908                   SUMA_LH("SUMA_niml_workproc Already on.");
1909                }
1910             } else {
1911                /* if already on, just close streams */
1912                /* closing the streams */
1913                SUMA_S_Text("Closing streams, but still listening ...");
1914                /* kill the streams */
1915                for (ii=0; ii< SUMA_MAX_STREAMS; ++ii) {
1916                   if (ii != SUMA_AFNI_STREAM_INDEX) {
1917                         /* leave AFNI connection separate */
1918                      NI_stream_close( SUMAg_CF->ns_v[ii] ) ;
1919                      SUMAg_CF->ns_v[ii] = NULL ;
1920                      SUMAg_CF->ns_flags_v[ii] = 0;
1921                      SUMAg_CF->TrackingId_v[ii] = 0;
1922                   }
1923                }
1924             }
1925             break;
1926 
1927          case SE_ToggleConnected:
1928             /* expects nothing in EngineData */
1929             if (!SUMA_CanTalkToAfni (SUMAg_DOv, SUMAg_N_DOv)) {
1930                fprintf(SUMA_STDOUT,
1931                         "%s: Cannot connect to AFNI.\n"
1932                         "\tNot one of the surfaces is mappable "
1933                         "and has a Surface Volume.\n"
1934                         "\tDid you use the -sv option when launching SUMA ?\n",
1935                         FuncName);
1936                break;
1937             }
1938 
1939             SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] =
1940                               !SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX];
1941             if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
1942                if (!SUMA_niml_call (SUMAg_CF, SUMA_AFNI_STREAM_INDEX, YUP)) {
1943                   /* conection flag is reset in SUMA_niml_call */
1944                   break;
1945                }
1946 
1947                /* start the listening WorkProcess */
1948                if (!SUMAg_CF->niml_work_on) {
1949                   SUMA_LH("registering SUMA_niml_workproc...");
1950                   SUMA_register_workproc(SUMA_niml_workproc, (XtPointer)sv);
1951                } else {
1952                   SUMA_LH("SUMA_niml_workproc Already on.");
1953                }
1954 
1955                /* register a call for sending the surface to afni (SetAfniSurf)*/
1956                if (LocalHead)
1957                   fprintf(SUMA_STDERR,"Notifying Afni of New surface...\n");
1958                ED = SUMA_InitializeEngineListData (SE_SetAfniSurf);
1959                SUMA_RegisterEngineListCommand (list, ED,
1960                                                 SEF_Empty, NULL,
1961                                                 SES_Suma, (void *)sv, NOPE,
1962                                                 SEI_Head, NULL);
1963                break;
1964             } else {
1965                fprintf(SUMA_STDOUT,"%s: Disconnecting from afni.\n", FuncName);
1966 
1967                if (!SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX]) {
1968                   /* It looks like the stream was closed, do the clean up */
1969                   SUMA_S_Warn("sv->ns is null, stream must have gotten closed.\n"
1970                               "Cleaning up ...\n");
1971                   ED = SUMA_InitializeEngineListData (SE_CloseStream4All);
1972                   ii = SUMA_AFNI_STREAM_INDEX;
1973                   SUMA_RegisterEngineListCommand (list, ED,
1974                                                 SEF_i, (void*)&ii,
1975                                                 SES_Suma, (void *)sv, NOPE,
1976                                                 SEI_Head, NULL);
1977 
1978                   break;
1979                }
1980 
1981 
1982                /* Close the stream if nobody else wants it.
1983                This is not a great condition, one should be able to leave the
1984                stream open
1985                even if no viewer, for the moment, does not want to talk to AFNI.
1986                Perhaps in the future. */
1987                if (SUMAg_N_SVv == 1) {
1988                   SUMA_S_Note("Nobody wants to talk to AFNI anymore\n"
1989                               "closing stream ...\n");
1990                   NI_stream_close(SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX]);
1991                   SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] = NULL;
1992                   SUMAg_CF->ns_flags_v[SUMA_AFNI_STREAM_INDEX] = 0;
1993                   SUMAg_CF->TrackingId_v[SUMA_AFNI_STREAM_INDEX] = 0;
1994                }
1995                break;
1996             }
1997 
1998          case SE_CloseStream4All:
1999             /* expects the stream index in i in EngineData */
2000             if (EngineData->i_Dest != NextComCode) {
2001                fprintf (SUMA_STDERR,
2002                         "Error %s: Data not destined correctly for %s (%d).\n",
2003                         FuncName, NextCom, NextComCode);
2004                break;
2005             }
2006             /* odds are communicating program died or closed stream,
2007                mark all surfaces as unsent */
2008             if (EngineData->i == SUMA_AFNI_STREAM_INDEX) {
2009                for (ii=0; ii<SUMAg_N_DOv; ++ii) {
2010                   if (SUMA_isSO(SUMAg_DOv[ii])) {
2011                      SO = (SUMA_SurfaceObject *)(SUMAg_DOv[ii].OP);
2012                      if (SO->SentToAfni) SO->SentToAfni = NOPE;
2013                   }
2014                }
2015             }
2016 
2017             /* same for parent fields */
2018             /* check first if stream in SUMAg_CF still good by any chance */
2019             nn = NI_stream_goodcheck(SUMAg_CF->ns_v[EngineData->i] , 1 ) ;
2020 
2021             if( nn >= 0 ){
2022                SUMA_S_Err("Stream still alive, this should not be. "
2023                           "Closing anyway.");
2024                NI_stream_close(SUMAg_CF->ns_v[EngineData->i]);
2025             }
2026 
2027             /* clean up and get out of here*/
2028             SUMAg_CF->ns_v[EngineData->i] = NULL;
2029             SUMAg_CF->ns_flags_v[EngineData->i] = 0;
2030             SUMAg_CF->TrackingId_v[EngineData->i] = 0;
2031             if (EngineData->i != SUMA_AFNI_STREAM_INDEX) {
2032                /* Connected for AFNI line handled elsewhere */
2033                SUMAg_CF->Connected_v[EngineData->i] = NOPE;
2034             }
2035             break;
2036 
2037          case SE_SetForceAfniSurf:
2038             /* expects nothing in EngineData */
2039             /* send to afni surfaces that can be sent even if they
2040                have been sent already */
2041             #if 0 /* pre Oct 26 */
2042             for (ii=0; ii<sv->N_DO; ++ii) {
2043                if (SUMA_isSO(SUMAg_DOv[sv->RegisteredDO[ii]])) {
2044                   SO = (SUMA_SurfaceObject *)
2045                            (SUMAg_DOv[sv->RegisteredDO[ii]].OP);
2046                   if (SO->SentToAfni) SO->SentToAfni = NOPE;
2047                }
2048             }
2049             #else
2050                /* send all geometrically correct surfaces */
2051                for (ii=0; ii<SUMAg_N_DOv; ++ii) {
2052                   if (SUMA_isSO(SUMAg_DOv[ii])) {
2053                      SO = (SUMA_SurfaceObject *)(SUMAg_DOv[ii].OP);
2054                      if (SO->AnatCorrect && SO->SentToAfni)
2055                         SO->SentToAfni = NOPE;
2056                   }
2057                }
2058             #endif
2059             /* proceed to SE_SetAfniSurf: */
2060             ED = SUMA_InitializeEngineListData (SE_SetAfniSurf);
2061             SUMA_RegisterEngineListCommand (list, ED,
2062                                             SEF_Empty, NULL,
2063                                             SES_Suma, (void *)sv, NOPE,
2064                                             SEI_Head, NULL);
2065             break;
2066 
2067          case SE_SetAfniMask:
2068             if (SUMAg_CF->Dev) { /* Send a mask surface to AFNI */
2069                int nels_sent=0;
2070                SUMA_ALL_DO *ado = NULL;
2071                SUMA_MaskDO *mdo = NULL;
2072                if ( EngineData->s_Dest != NextComCode ||
2073                     EngineData->fv3_Dest != NextComCode) {
2074                   fprintf (SUMA_STDERR,
2075                      "Error %s: Data not destined correctly for %s (%d).\n",
2076                      FuncName, NextCom, NextComCode);
2077                   break;
2078                }
2079                ado = SUMA_whichADOg(EngineData->s);
2080                if (!ado || ado->do_type != MASK_type) {
2081                   SUMA_S_Warn("Mask not found or ado of wrong type");
2082                   break;
2083                }
2084                mdo = (SUMA_MaskDO*)ado;
2085                if (!(SO = mdo->SO)) {
2086                   SUMA_S_Warn("No mask SO");
2087                   break;
2088                }
2089                SUMA_LH("Sending mask %s's surface, SO = %p...",
2090                            ADO_LABEL(ado), SO);
2091                if (!SO->SentToAfni) {
2092                   SUMA_LH("Sending the whole thing, SO = %p", SO);
2093                   nel = NI_new_data_element("SUMA_mask", 0);
2094                   NI_set_attribute(nel, "idcode", ADO_ID(ado));
2095                   NI_SET_FLOATv(nel, "init_cen", mdo->init_cen, 3);
2096                   NI_SET_FLOATv(nel, "new_cen", EngineData->fv3, 3);
2097                   if ((nn = NI_write_element(
2098                               SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2099                                              NI_TALK_MODE ))<0) {
2100                           SUMA_S_Err("NI_write_element failed\n");
2101                   }
2102                   if (LocalHead) SUMA_ShowNel(nel);
2103                   NI_free_element(nel);
2104                   nel = NULL;
2105                   ++nels_sent;
2106                   if (1) {
2107                      float delta[3] = {0, 0, 0};
2108                      delta[0] = mdo->init_cen[0] - EngineData->fv3[0];
2109                      delta[1] = mdo->init_cen[1] - EngineData->fv3[1];
2110                      delta[2] = mdo->init_cen[2] - EngineData->fv3[2];
2111                      nel = SUMA_makeNI_SurfIXYZ (SO);
2112                      /* Undo the offset in the surface coords ... */
2113                      SUMA_offset_NI_SurfIXYZ(nel, delta);
2114                      /* label this object as being the surface of a mask */
2115                      if (!nel) {
2116                         fprintf(SUMA_STDERR,
2117                                  "Error %s: SUMA_makeNI_SurfIXYZ failed\n",
2118                                  FuncName);
2119                         break;
2120                      }
2121                      NI_set_attribute(nel,"parent_type", "SUMA_mask");
2122                      NI_set_attribute(nel,"parent_idcode", ADO_ID(ado));
2123                      /* set up some defaults color
2124                         (see matlab's rgbdectohex for visual aid)
2125                         info for AFNI interface */
2126                            NI_set_attribute(nel,
2127                               "afni_surface_controls_toggle", "on");
2128                            NI_set_attribute(nel,
2129                               "afni_surface_controls_nodes","none");
2130                            NI_set_attribute(nel,
2131                               "afni_surface_controls_lines",
2132                                  SUMA_RGB_to_hex(mdo->init_col, NULL));
2133                            NI_set_attribute(nel,
2134                               "afni_surface_controls_plusminus","none");
2135                            NI_SET_INT(nel,
2136                                  "afni_surface_controls_linewidth", 10 );
2137 
2138                      /* send surface nel */
2139                      if (LocalHead)
2140                         fprintf(SUMA_STDERR,"%s: Sending SURF_iXYZ nel...\n ",                                                FuncName) ;
2141                      nn = NI_write_element(
2142                               SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2143                                              NI_TALK_MODE ) ;
2144 
2145                      if( nn < 0 ){
2146                           SUMA_S_Err("NI_write_element failed\n");
2147                      }
2148 
2149                      if (LocalHead) SUMA_ShowNel(nel);
2150                      NI_free_element(nel);
2151                      nel = NULL;
2152                      ++nels_sent;
2153                   }
2154                   if (1) {
2155                      /* send node normals       ZSS Oct 05 04 */
2156                      nel = SUMA_makeNI_SurfINORM (SO);
2157                      if (!nel) {
2158                         SUMA_S_Err("SUMA_makeNI_SurfINORM failed");
2159                         break;
2160                      }
2161                      NI_set_attribute(nel,"parent_type", "SUMA_mask");
2162                      NI_set_attribute(nel,"parent_idcode", ADO_ID(ado));
2163                      /* send surface nel */
2164                      if (LocalHead)
2165                         fprintf(SUMA_STDERR,
2166                                 "%s: Sending SURF_NORM nel ...\n", FuncName) ;
2167                      nn = NI_write_element(
2168                               SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2169                                              NI_TALK_MODE ) ;
2170                      if( nn < 0 ){
2171                           SUMA_S_Err("NI_write_element failed");
2172                      }
2173                      NI_free_element(nel);
2174                      nel = NULL;
2175                      ++nels_sent;
2176                   }
2177 
2178                   if (1) {
2179                      /* send triangles */
2180                      nel = SUMA_makeNI_SurfIJK (SO);
2181                      if (!nel) {
2182                         SUMA_S_Err("SUMA_makeNI_SurfIJK failed");
2183                         break;
2184                      }
2185                      NI_set_attribute(nel,"parent_type", "SUMA_mask");
2186                      NI_set_attribute(nel,"parent_idcode", ADO_ID(ado));
2187                      /* send surface nel */
2188                      if (LocalHead)
2189                         fprintf(SUMA_STDERR,"%s: Sending SURF_IJK nel ...\n",
2190                                             FuncName) ;
2191                      nn = NI_write_element(
2192                               SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2193                                              NI_TALK_MODE ) ;
2194 
2195                      if( nn < 0 ){
2196                         SUMA_S_Err("NI_write_element failed");
2197                      }
2198                      NI_free_element(nel);
2199                      nel = NULL;
2200                      ++nels_sent;
2201                   }
2202                   if (nels_sent) {
2203                      /* mark surface as sent to afni */
2204                      SO->SentToAfni = YUP;
2205                   } else {
2206                      SUMA_SL_Warn("Nothing sent dude, what's happening?");
2207                   }
2208                }
2209 
2210                if (1) {
2211                   SUMA_LH("Sending new center, SO = %p", SO);
2212                   nel = NI_new_data_element("SUMA_mask", 0);
2213                   NI_set_attribute(nel, "idcode", ADO_ID(ado));
2214                   NI_SET_FLOATv(nel, "new_cen", EngineData->fv3, 3);
2215                   if ((nn = NI_write_element(
2216                               SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2217                                              NI_TALK_MODE ))<0) {
2218                           SUMA_S_Err("NI_write_element failed\n");
2219                   }
2220                   if (LocalHead) SUMA_ShowNel(nel);
2221                   NI_free_element(nel);
2222                   nel = NULL;
2223                   ++nels_sent;
2224                }
2225 
2226             } break;
2227 
2228          case SE_SetAfniSurfList:
2229             /* expects ivec in EngineData and a string in s saying what is to be
2230                sent, a flag in i 1=report transmission, 0 = be quiet*/
2231             { int nels_sent, N_Send, *SendList;
2232               char *stmp = NULL;
2233               static char LastPrefix[THD_MAX_PREFIX+1] = {"nuda"};
2234                if (EngineData->ivec_Dest != NextComCode ||
2235                   EngineData->s_Dest != NextComCode ||
2236                   EngineData->i_Dest != NextComCode) {
2237                   fprintf (SUMA_STDERR,
2238                      "Error %s: Data not destined correctly for %s (%d).\n",
2239                      FuncName, NextCom, NextComCode);
2240                   break;
2241                }
2242                N_Send = EngineData->ivec->n;
2243                SendList = EngineData->ivec->v;
2244                /* send to afni the list of surfaces in SendList*/
2245                if (N_Send) {
2246                   for (ii=0; ii<N_Send; ++ii) {
2247                      nels_sent = 0;
2248                      SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SendList[ii]].OP);
2249                      if (EngineData->i && SO->Label)
2250                         fprintf(SUMA_STDERR,"%s: Sending surface %s (%s)...\n",
2251                                              FuncName, SO->Label, EngineData->s);
2252                      if (SUMA_iswordin(EngineData->s,"NodeList") == 1) {
2253                         nel = SUMA_makeNI_SurfIXYZ (SO);
2254                         if (!nel) {
2255                            fprintf(SUMA_STDERR,
2256                                     "Error %s: SUMA_makeNI_SurfIXYZ failed\n",
2257                                     FuncName);
2258                            break;
2259                         }
2260                         /* set up some defaults color
2261                            (see matlab's rgbdectohex for visual aid)
2262                            info for AFNI interface */
2263                         switch(ii) {
2264                            case 0: /* typically wm left*/
2265                               NI_set_attribute(nel,
2266                                  "afni_surface_controls_toggle", "on");
2267                               NI_set_attribute(nel,
2268                                  "afni_surface_controls_nodes","none");
2269                               NI_set_attribute(nel,
2270                                  "afni_surface_controls_lines","#00ff00");
2271                                                             /* green 0 255 0 */
2272                               NI_set_attribute(nel,
2273                                  "afni_surface_controls_plusminus","none");
2274                               break;
2275                            case 1: /* typically pial left */
2276                               NI_set_attribute(nel,
2277                                  "afni_surface_controls_toggle", "on");
2278                               NI_set_attribute(nel,
2279                                  "afni_surface_controls_nodes","none");
2280                               NI_set_attribute(nel,
2281                                  "afni_surface_controls_lines","#0000ff");
2282                                                          /* 0 0  225  blue */
2283                               NI_set_attribute(nel,
2284                                  "afni_surface_controls_plusminus","none");
2285                               break;
2286                            case 2: /* typically wm right */
2287                               NI_set_attribute(nel,
2288                                  "afni_surface_controls_toggle", "on");
2289                               NI_set_attribute(nel,
2290                                  "afni_surface_controls_nodes","none");
2291                               NI_set_attribute(nel,
2292                                  "afni_surface_controls_lines","#ffff00");
2293                                                             /* green 0 255 0*/
2294                               NI_set_attribute(nel,
2295                                  "afni_surface_controls_plusminus","none");
2296                               break;
2297                            case 4: /* typically pial right */
2298                               NI_set_attribute(nel,
2299                                  "afni_surface_controls_toggle", "on");
2300                               NI_set_attribute(nel,
2301                                  "afni_surface_controls_nodes","none");
2302                               NI_set_attribute(nel,
2303                                  "afni_surface_controls_lines","#ff0000");
2304                                                             /* red 255 0 0 */
2305                               NI_set_attribute(nel,
2306                                  "afni_surface_controls_plusminus","none");
2307                               break;
2308                            default: /* hot pink */
2309                               NI_set_attribute(nel,
2310                                  "afni_surface_controls_toggle", "on");
2311                               NI_set_attribute(nel,
2312                                  "afni_surface_controls_nodes","none");
2313                               NI_set_attribute(nel,
2314                                  "afni_surface_controls_lines","#ff69b4");
2315                                                    /* hot pink 255 105 180 */
2316                               NI_set_attribute(nel,
2317                                  "afni_surface_controls_plusminus","none");
2318                               break;
2319                         }
2320                         /* send surface nel */
2321                         if (LocalHead)
2322                            fprintf(SUMA_STDERR,"%s: Sending SURF_iXYZ nel...\n ",                                                FuncName) ;
2323                         nn = NI_write_element(
2324                                  SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2325                                                 NI_TALK_MODE ) ;
2326 
2327                         if( nn < 0 ){
2328                              SUMA_S_Err("NI_write_element failed\n");
2329                         }
2330 
2331                         #if 0
2332                            {
2333                               NI_stream nstdout;
2334                               nstdout = NI_stream_open( "fd:1","w");
2335                               if( nstdout == NULL ){
2336                                  fprintf(SUMA_STDERR,"Can't open fd:1\n");
2337                                  break;
2338                               }
2339                               NI_write_element( nstdout , nel , NI_TEXT_MODE ) ;
2340                               NI_stream_close(nstdout);
2341                            }
2342                         #endif
2343 
2344                         NI_free_element(nel);
2345                         nel = NULL;
2346                         ++nels_sent;
2347                      }
2348                      if (SUMA_iswordin(EngineData->s,"NodeNormList") == 1) {
2349                         /* send node normals       ZSS Oct 05 04 */
2350                         nel = SUMA_makeNI_SurfINORM (SO);
2351                         if (!nel) {
2352                            SUMA_S_Err("SUMA_makeNI_SurfINORM failed");
2353                            break;
2354                         }
2355                         /* send surface nel */
2356                         if (LocalHead)
2357                            fprintf(SUMA_STDERR,
2358                                    "%s: Sending SURF_NORM nel ...\n", FuncName) ;
2359                         nn = NI_write_element(
2360                                  SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2361                                                 NI_TALK_MODE ) ;
2362                         if( nn < 0 ){
2363                              SUMA_S_Err("NI_write_element failed");
2364                         }
2365                         NI_free_element(nel);
2366                         nel = NULL;
2367                         ++nels_sent;
2368                      }
2369 
2370                      if (SUMA_iswordin(EngineData->s,"FaceSetList") == 1) {
2371                         /* send triangles */
2372                         nel = SUMA_makeNI_SurfIJK (SO);
2373                         if (!nel) {
2374                            SUMA_S_Err("SUMA_makeNI_SurfIJK failed");
2375                            break;
2376                         }
2377                         /* send surface nel */
2378                         if (LocalHead)
2379                            fprintf(SUMA_STDERR,"%s: Sending SURF_IJK nel ...\n",
2380                                                FuncName) ;
2381                         nn = NI_write_element(
2382                                  SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel ,
2383                                                 NI_TALK_MODE ) ;
2384 
2385                         if( nn < 0 ){
2386                            SUMA_S_Err("NI_write_element failed");
2387                         }
2388                         NI_free_element(nel);
2389                         nel = NULL;
2390                         ++nels_sent;
2391                      }
2392                      if (nels_sent) {
2393                         /* mark surface as sent to afni */
2394                         SO->SentToAfni = YUP;
2395                      } else {
2396                         SUMA_SL_Warn("Nothing sent dude, what's happening?");
2397                      }
2398                   }
2399                   /* Now make afni switch to the surface volume of the
2400                      last surface
2401                   ZSS Sept 28 06: To avoid the jamming of
2402                   AFNI and SUMA's write buffers. It used to be
2403                   That AFNI switched automatically at the first surface
2404                   and started writing colored data while suma was still
2405                   writing surfaces. As a result, both programs got stuck
2406                   waiting for the write operation to finish and it never
2407                   did because buffers got full and no one was busy listening
2408                   Kudos to Rick R. for having figured the Ladies' bug source */
2409                   SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SendList[N_Send-1]].OP);
2410                   if (SO->VolPar && SO->VolPar->filecode) {
2411                      if (strcmp(LastPrefix, SO->VolPar->prefix)) {
2412                         nel = NI_new_data_element("ni_do", 0);
2413                         NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
2414                         stmp = SUMA_append_string("SWITCH_UNDERLAY A.",
2415                                                   SO->VolPar->prefix);
2416                         stmp = SUMA_append_replace_string(stmp, "0", " ", 1);
2417                         NI_set_attribute ( nel, "ni_object", stmp);
2418                         fprintf(SUMA_STDERR,
2419                               "%s: Sending switch underlay command to (%s)...\n",                               FuncName, stmp);
2420                         if (NI_write_element(
2421                                  SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel,
2422                                                 NI_TALK_MODE ) < 0) {
2423                            SUMA_SLP_Err("Failed to send SWITCH_ANATOMY to afni");
2424                         }
2425                         NI_free_element(nel) ; nel = NULL;
2426                         if (stmp) SUMA_free(stmp); stmp = NULL;
2427                         snprintf(LastPrefix, THD_MAX_PREFIX, "%s",
2428                                  SO->VolPar->prefix);
2429                      }
2430                   }
2431 
2432                }
2433 
2434                break;
2435             }
2436 
2437          case SE_SetAfniSurf:
2438             /* expects nothing in EngineData */
2439             {  int N_Send, *SendList, ti=1;
2440                SUMA_IVEC ivec;
2441                /* send to afni the list of anatomically correct surfaces
2442                   and with a surface volume*/
2443                /* No surfaces are sent twice because there should not be
2444                   duplicate  local domain parent surfaces in SUMAg_DOv */
2445                /* prior to Wed Nov  6 17:47:20 EST 2002, only mappable surfaces
2446                   that are related to the ones shown in the viewer
2447                   were being sent to AFNI. Now all mappable surfaces loaded are
2448                   sent regardless of what is shown */
2449                /* Jan. 08 04:
2450                   All anatomically correct surfaces are now sent to AFNI */
2451                SendList =
2452                   SUMA_FormSOListToSendToAFNI(SUMAg_DOv , SUMAg_N_DOv, &N_Send);
2453                if (N_Send > 0) {
2454                   ivec.v = SendList;
2455                   ivec.n = N_Send;
2456                   ED = SUMA_InitializeEngineListData (SE_SetAfniSurfList);
2457                   if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
2458                                                   SEF_ivec, (void *)(&ivec),
2459                                                   SES_Suma, (void *)sv,
2460                                                   NOPE,
2461                                                   SEI_Tail, NULL))) {
2462                      fprintf(SUMA_STDERR,
2463                              "Error %s: Failed to register element\n", FuncName);
2464                      break;
2465                   }
2466                   if (!(LocElm = SUMA_RegisterEngineListCommand (
2467                         list, ED,
2468                         SEF_s, (void *)("NodeList, FaceSetList, NodeNormList"),
2469                         SES_Suma, (void *)sv, NOPE,
2470                         SEI_In, LocElm))) {
2471                      fprintf(SUMA_STDERR,
2472                              "Error %s: Failed to register element\n", FuncName);
2473                      break;
2474                   }
2475                   if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
2476                                                 SEF_i, (void *)&ti,
2477                                                 SES_Suma, (void *)sv, NOPE,
2478                                                 SEI_In, LocElm))) {
2479                      fprintf(SUMA_STDERR,
2480                              "Error %s: Failed to register element\n", FuncName);
2481                      break;
2482                   }
2483                   if (SendList) SUMA_free(SendList); SendList = NULL;
2484                }else {
2485                   if (N_Send < 0 &&
2486                       !SUMA_Anatomical_DOs(SUMAg_DOv , SUMAg_N_DOv, NULL)) {
2487                      SUMA_SLP_Warn(
2488                         "None of the surfaces were marked as 'Anatomical'\n"
2489                         "So none were sent to AFNI. You can label a surface\n"
2490                         "as Anatomical by adding 'Anatomical = Y' where the \n"
2491                         "surface is declared in the .spec file.");
2492                   }
2493                }
2494 
2495                break;
2496             }
2497 
2498          case SE_SetAfniThisSurf:
2499             /* expects an idcode_str in EngineData->cp and what needs to be sent
2500                in EngineData->s for surface to be sent to AFNI */
2501             {
2502                SUMA_IVEC ivec;
2503                if (EngineData->s_Dest != NextComCode ||
2504                   EngineData->cp_Dest != NextComCode ||
2505                   EngineData->i_Dest != NextComCode) {
2506                   fprintf (SUMA_STDERR,
2507                            "Error %s: Data not destined correctly for %s \n"
2508                            "((%d %d %d) %d).\n",
2509                      FuncName, NextCom,
2510                      EngineData->s_Dest, EngineData->cp_Dest,
2511                      EngineData->i_Dest, NextComCode);
2512                   break;
2513                }
2514                i = SUMA_findSO_inDOv(EngineData->cp, SUMAg_DOv, SUMAg_N_DOv);
2515                if (i<0) {
2516                   SUMA_SL_Err("Surface Not Found!");
2517                   break;
2518                }
2519                ivec.n = 1;
2520                ivec.v = (int*)SUMA_malloc(ivec.n*sizeof(int));
2521                ivec.v[0] = i;
2522                ED = SUMA_InitializeEngineListData (SE_SetAfniSurfList);
2523                if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
2524                                                       SEF_ivec, (void *)(&ivec),
2525                                                       SES_Suma, (void *)sv, NOPE,
2526                                                       SEI_Tail, NULL))) {
2527                   fprintf( SUMA_STDERR,
2528                            "Error %s: Failed to register element\n", FuncName);
2529                   break;
2530                }
2531                if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
2532                                                 SEF_s, (void *)(EngineData->s),
2533                                                 SES_Suma, (void *)sv, NOPE,
2534                                                 SEI_In, LocElm))) {
2535                   fprintf( SUMA_STDERR,
2536                            "Error %s: Failed to register element\n", FuncName);
2537                   break;
2538                }
2539                if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
2540                                                 SEF_i, (void *)&(EngineData->i),
2541                                                 SES_Suma, (void *)sv, NOPE,
2542                                                 SEI_In, LocElm))) {
2543                   fprintf(SUMA_STDERR,
2544                           "Error %s: Failed to register element\n", FuncName);
2545                   break;
2546                }
2547                SUMA_free(ivec.v);
2548                break;
2549             }
2550 
2551          case SE_ToggleShowSelectedNode:
2552             /* expects nothing in EngineData */
2553             {
2554                int st = SUMA_SV_GetShowSelectedDatum(sv);
2555                SUMA_SV_SetShowSelectedDatum(sv, !st,NOPE);
2556             }
2557             break;
2558 
2559          case SE_SetSelectedNode: {
2560             SUMA_ALL_DO *adodat=NULL;
2561             char *idcode=NULL, *eee=NULL;
2562             NI_element *nel=NULL;
2563 
2564             /* expects a node (datum) index in i and maybe a ngr in ngr
2565             ngr is only being used when AFNI is the src of the call*/
2566             if (EngineData->i_Dest   != NextComCode ||
2567                 EngineData->ngr_Dest != NextComCode) {
2568                fprintf (SUMA_STDERR,
2569                         "Error %s: Data not destined correctly for %s (%d).\n",
2570                         FuncName, NextCom, NextComCode);
2571                break;
2572             }
2573             if (!(ado = SUMA_SV_Focus_ADO(sv))) {
2574                /* No so in focus */
2575                SUMA_S_Err("No SO/DO in focus");
2576                break;
2577             }
2578 
2579             if ( EngineData->ngr &&
2580                  (nel = SUMA_FindNgrNamedElement(EngineData->ngr,
2581                                                  "SUMA_crosshair_xyz"))) {
2582                   if ((idcode = NI_get_attribute(nel, "surface_idcode")) &&
2583                       (adodat = iDO_ADO(SUMA_whichDOg(idcode)))) {
2584                 /* Make sure datum can be related to the DO in Focus
2585                    For now, all one gets is surfaces, but volume id will
2586                    come next. Then you'll need to check for grid match perhaps
2587                    before proceeding*/
2588                       if (!SUMA_isRelated(adodat, ado,2)) {
2589                         SUMA_LH("No relative of mine");
2590                         break;
2591                       }
2592                   }
2593             }
2594 
2595             if (EngineData->i >= 0 &&
2596                   EngineData->i <= SUMA_ADO_Max_Datum_Index(ado)) {
2597                switch (ado->do_type) {
2598                   case VO_type:
2599                      if ( EngineData->iv15_Dest != NextComCode ||
2600                           EngineData->fv15_Dest != NextComCode ) {
2601                         SUMA_S_Err(
2602                            "Data not destined correctly for VOtype %s (%d).\n",
2603                             NextCom, NextComCode);
2604                         break;
2605                      }
2606                      SUMA_ADO_Set_SelectedDatum(ado, EngineData->i,
2607                                     (void *)EngineData->iv15,
2608                                     (void *)EngineData->fv15);
2609                      break;
2610                   case TRACT_type:
2611                      if ( EngineData->iv15_Dest != NextComCode ) {
2612                         SUMA_S_Err(
2613                            "Data not destined correctly for VOtype %s (%d).\n",
2614                             NextCom, NextComCode);
2615                         break;
2616                      }
2617                      SUMA_ADO_Set_SelectedDatum(ado,
2618                                 EngineData->i, (void *)EngineData->iv15, NULL);
2619                      break;
2620                   default:
2621                      SUMA_ADO_Set_SelectedDatum(ado, EngineData->i, NULL, NULL);
2622                      break;
2623                }
2624             } else {
2625                /* ignore -1, used in initializations */
2626                if (EngineData->i != -1) {
2627                   SUMA_SLP_Err(
2628                         "Datum index (%d) < 0 || >= Number of data nodes (%d)",
2629                         EngineData->i, SUMA_ADO_Max_Datum_Index(ado)+1);
2630                   SUMA_DUMP_TRACE("Whence the bad index");
2631                }
2632                break;
2633             }
2634             /* Nick's options. Jump to the sub-brick index corresponding
2635                to node */
2636             if (!(curColPlane = SUMA_ADO_CurColPlane(ado))) {
2637                SUMA_S_Err("No cur plane");
2638                break;
2639             }
2640             SUMA_LHv("Have %d, %d and %d\n",
2641                SUMAg_CF->YokeIntToNode,
2642                SDSET_VECNUM(curColPlane->dset_link),
2643                SUMA_ADO_N_Datum(ado));
2644             if (SUMAg_CF->YokeIntToNode   &&
2645                 !(SDSET_VECNUM(curColPlane->dset_link) %
2646                                              SUMA_ADO_N_Datum(ado))) {
2647                itmp = SDSET_VECNUM(curColPlane->dset_link) /
2648                                              SUMA_ADO_N_Datum(ado);
2649                if (!SUMA_SwitchColPlaneIntensity(ado, curColPlane,
2650                                                  EngineData->i*itmp, 1)) {
2651                   SUMA_S_Err("Failed to yoke intensity to node index");
2652                }
2653             }
2654             SUMAg_CF->YokeIntToNode = 0;
2655 
2656             /* NB: I find it strange that there is this block here
2657                followed by a similar one in SUMA_UpdateNodeField
2658                Check for possible duplications ... */
2659             if (SUMAg_CF->callbacks && !SUMAg_CF->HoldClickCallbacks) {
2660                SUMA_LH("Activating callbacks");
2661                if (!SUMA_Selected_Node_Activate_Callbacks (
2662                         ado, curColPlane,
2663                         EngineData->Src, EngineData->ngr)) {
2664                   SUMA_S_Err("Failed to activate callbacks");
2665                }
2666             }
2667 
2668             /* get the controller up if it is not, and the mood is right*/
2669             SUMA_LH("Get controller up");
2670             SUMA_OpenSurfCont_if_other(sv->X->TOPLEVEL, ado, sv);
2671 
2672             SUMA_LH("Update node field");
2673             SUMA_UpdateNodeField(ado);
2674             SUMA_LH("Done with SE_SetSelectedNode");
2675 
2676             /* Might need to update nodemask -- experimental, need much love
2677                and cleanup
2678                Limitations: 1- constant cmask operation
2679                             2- reloads all data for mask expression!
2680                             3- will not work without controller
2681                             4- Works only with integers */
2682             if (SUMAg_CF->Dev && ado->do_type == SO_type &&
2683                 (eee = SUMA_EnvVal("SUMA_TEMP_NODE_CMASK_EXPR"))){
2684                SUMA_SurfaceObject *SO=(SUMA_SurfaceObject *)ado;
2685                SUMA_DRAW_MASKS *DW = SO->DW;
2686                char *etmp=NULL, stmp[32];
2687                int nxyz;
2688                float val;
2689 
2690                /*
2691                   Toy example for expression:
2692   setenv SUMA_TEMP_NODE_CMASK_EXPR '-a labels.niml.dset -expr equals(a,$SEL)'
2693                   Or better yet, for the TT atlas isosurfaces
2694   setenv SUMA_TEMP_NODE_CMASK_EXPR '-a labels.niml.dset -expr equals(a,mod($SEL,200))+equals(a,mod($SEL,200)+200)'
2695               */
2696                TLH(1);
2697                DW->user_exp =
2698                   SUMA_copy_string(eee);
2699                DW->cmask_exp = SUMA_copy_string(DW->user_exp);
2700                if (SUMA_GetValuesAtSelection(ado, 1, &val, NULL, NULL)) {
2701                   sprintf(stmp,"%d", (int)val);
2702                   SUMA_Swap_String(&(DW->cmask_exp), "$SEL", stmp);
2703                   if (!DW->last_cmask_exp ||
2704                        strcmp(DW->last_cmask_exp, DW->cmask_exp)) {
2705                      /* This is a brute force regen, just for testing */
2706                      SUMA_LH("Evaluating %s", DW->cmask_exp);
2707                      SUMA_ifree(DW->nodemask);
2708                      etmp = SUMA_copy_string(DW->cmask_exp); /* EDT_calcmask
2709                                                          modifies the string */
2710                      DW->nodemask =  EDT_calcmask(etmp, &nxyz, SO->N_Node );
2711                      SUMA_ifree(etmp);
2712                      if (!DW->nodemask) {
2713                         SUMA_S_Err("Failed to setup mask with %s",
2714                                    DW->cmask_exp);
2715                      } else {
2716                         if (nxyz != SO->N_Node) {
2717                            SUMA_S_Err("Bigus calamitous!\n"
2718                                    "length of mask (%d) != SO->N_Node (%d).\n",
2719                                       nxyz, SO->N_Node);
2720                            SUMA_ifree(DW->nodemask);
2721                         } else {
2722                            DW->last_cmask_exp = SUMA_copy_string(DW->cmask_exp);
2723                            for (i=0, DW->N_nz_nodemask=0; i<SO->N_Node; ++i)
2724                               if (DW->nodemask[i]) ++DW->N_nz_nodemask;
2725                            ++DW->PatchRegenID;
2726                            SUMA_LH("OK, %d non zeros, regenID %d",
2727                                   DW->N_nz_nodemask, DW->PatchRegenID);
2728                         }
2729                      }
2730 
2731                   } else {
2732                      SUMA_LH("No re-eval last_cmask_exp: %s",
2733                              DW->last_cmask_exp);
2734                   }
2735                } else {
2736                   SUMA_LH("Failed to get selection!");
2737                }
2738                TLH(0);
2739             }
2740 
2741             break; }
2742          case SE_ToggleShowSelectedFaceSet:
2743             /* expects nothing ! */
2744             {
2745                int st = SUMA_SV_GetShowSelectedFaceSet(sv);
2746                SUMA_SV_SetShowSelectedFaceSet(sv,!st,NOPE);
2747             }
2748             break;
2749 
2750          case SE_SetSelectedFaceSet:
2751             /* expects the index for the selected FaceSet */
2752             if (EngineData->i_Dest != NextComCode) {
2753                fprintf (SUMA_STDERR,
2754                         "Error %s: Data not destined correctly for %s (%d).\n",
2755                         FuncName, NextCom, NextComCode);
2756                break;
2757             }
2758             if (!(ado = SUMA_SV_Focus_ADO(sv))) {
2759                SUMA_S_Err("No SO/ADO in focus");
2760                break;
2761             }
2762             switch(ado->do_type) {
2763                case SO_type: {
2764                   SUMA_SurfaceObject *SO=(SUMA_SurfaceObject *)ado;
2765                   SUMA_VisX_Pointers4Display(SO, 1);/*coordinates as displayed*/
2766                   if (EngineData->i < 0 || EngineData->i >= SO->N_FaceSet) {
2767                      if (EngineData->i != -1){
2768                         SUMA_SLP_Err("Node index < 0 || "
2769                                      "> Number of FaceSets in surface");
2770                      }
2771                      break;
2772                   }
2773                   ND = SO->NodeDim;
2774                   NP = SO->FaceSetDim;
2775                   ip = NP * EngineData->i;
2776                   id = ND * SO->FaceSetList[ip];
2777                   SO->FaceSetMarker->n0[0] = SO->NodeList[id];
2778                   SO->FaceSetMarker->n0[1] = SO->NodeList[id+1];
2779                   SO->FaceSetMarker->n0[2] = SO->NodeList[id+2];
2780                   id = ND * SO->FaceSetList[ip+1];
2781                   SO->FaceSetMarker->n1[0] = SO->NodeList[id];
2782                   SO->FaceSetMarker->n1[1] = SO->NodeList[id+1];
2783                   SO->FaceSetMarker->n1[2] = SO->NodeList[id+2];
2784                   id = ND * SO->FaceSetList[ip+2];
2785                   SO->FaceSetMarker->n2[0] = SO->NodeList[id];
2786                   SO->FaceSetMarker->n2[1] = SO->NodeList[id+1];
2787                   SO->FaceSetMarker->n2[2] = SO->NodeList[id+2];
2788                   SO->FaceSetMarker->NormVect[0] = SO->FaceNormList[ip];
2789                   SO->FaceSetMarker->NormVect[1] = SO->FaceNormList[ip+1];
2790                   SO->FaceSetMarker->NormVect[2] = SO->FaceNormList[ip+2];
2791 
2792                   SO->SelectedFaceSet = EngineData->i;
2793                   SUMA_VisX_Pointers4Display(SO, 0);/* revert to surf cooords. */
2794                   SUMA_UpdateTriField(SO);
2795                   break; }
2796                case GDSET_type:
2797                   SUMA_S_Err("ambigous display method without variant");
2798                   break;
2799                case CDOM_type:
2800                   SUMA_S_Err("Help me please");
2801                   break;
2802                case GRAPH_LINK_type: {
2803                   SUMA_DSET *dset = SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)ado);
2804                   SUMA_GRAPH_SAUX *Saux = SDSET_GSAUX(dset);
2805                   if (EngineData->i < dset->Aux->range_node_index[0] ||
2806                       EngineData->i > dset->Aux->range_node_index[1]) {
2807                      if (EngineData->i != -1){
2808                         SUMA_SLP_Err("Node index < 0 || "
2809                                      "> Number of nodes in graph dataset");
2810                         SUMA_S_Errv("Index is %d, current range is: %ld %ld\n",
2811                                      EngineData->i,
2812                                      dset->Aux->range_node_index[0],
2813                                      dset->Aux->range_node_index[1]);
2814                         SUMA_DUMP_TRACE("WEIRD 3");
2815                      }
2816                      break;
2817                   }
2818                   Saux->PR->iAltSel[SUMA_ENODE_0] = EngineData->i;
2819                   Saux->PR->datum_index = -1;
2820                   SUMA_UpdatePointField((SUMA_ALL_DO*)ado);
2821                   break;}
2822                case TRACT_type: {
2823                   SUMA_TractDO *tdo = (SUMA_TractDO *)ado;
2824                   SUMA_TRACT_SAUX *Saux = TDO_TSAUX(tdo);
2825                   SUMA_LH("No alternate selection for tracts");
2826                   break;}
2827                case MASK_type: {
2828                   SUMA_S_Err("What would that be for a mask?");
2829                   break; }
2830                case VO_type: {
2831                   SUMA_S_Err("Nothing done for volumes here yet");
2832                   break; }
2833                default:
2834                   SUMA_S_Errv("Not ready for %s\n", ADO_TNAME(ado));
2835                   break;
2836             }
2837             break;
2838          case SE_ToggleCrossHair:
2839             /* expects nothing in EngineData */
2840             sv->ShowCrossHair = !sv->ShowCrossHair;
2841             XmToggleButtonSetState (sv->X->ViewMenu->mw[SW_ViewCrossHair],
2842                sv->ShowCrossHair, NOPE);
2843             break;
2844 
2845          case SE_SetCrossHair:
2846             /* Expects Cross Hair coordinates in fv3, and ADO in vp */
2847             if (EngineData->fv3_Dest != NextComCode ||
2848                 EngineData->vp_Dest != NextComCode) {
2849                fprintf (SUMA_STDERR,
2850                         "Error %s: Data not destined correctly for %s (%d).\n",
2851                         FuncName, NextCom, NextComCode);
2852                break;
2853             }
2854             ado = (SUMA_ALL_DO *)EngineData->vp;
2855             if (LocalHead)
2856                fprintf(SUMA_STDERR,"%s: Setting cross hair at %f %f %f\n",
2857                                     FuncName, EngineData->fv3[0],
2858                                     EngineData->fv3[1],
2859                                     EngineData-> fv3[2]);
2860             sv->Ch->c[0]= EngineData->fv3[0];
2861             sv->Ch->c[1]= EngineData->fv3[1];
2862             sv->Ch->c[2]= EngineData->fv3[2];
2863 
2864             /* are we in VisX mode? */
2865             if (ado && ado->do_type == SO_type &&
2866                 (SO = (SUMA_SurfaceObject *)ado) && SO->VisX.Applied) {
2867                                                          /* undo the VisX */
2868                SUMA_Apply_VisX_Chain(EngineData->fv3, 1, SO->VisX.Xchain, 1);
2869                sv->Ch->c_noVisX[0]= EngineData->fv3[0];
2870                sv->Ch->c_noVisX[1]= EngineData->fv3[1];
2871                sv->Ch->c_noVisX[2]= EngineData->fv3[2];
2872             } else {
2873                sv->Ch->c_noVisX[0]=sv->Ch->c[0];
2874                sv->Ch->c_noVisX[1]=sv->Ch->c[1];
2875                sv->Ch->c_noVisX[2]=sv->Ch->c[2];
2876             }
2877 
2878             /* Make slices go to same location */
2879             SUMA_VO_set_slices_XYZ(NULL, sv->Ch->c_noVisX);
2880 
2881             /* Attempt to update crosshair corrdinates
2882                in open surface controllers */
2883             SUMA_UpdateXhairField(sv);
2884             break;
2885 
2886          case SE_BindCrossHair:
2887             /* expects adoID to bind cross hair to*/
2888             if (EngineData->iv3_Dest != NextComCode) {
2889                fprintf (SUMA_STDERR,
2890                         "Error %s: Data not destined correctly for %s (%d).\n",
2891                         FuncName, NextCom, NextComCode);
2892                break;
2893             }
2894             sv->Ch->adoID = EngineData->iv3[0];
2895             sv->Ch->datumID = EngineData->iv3[1];
2896             sv->Ch->secID = EngineData->iv3[2];
2897             SUMA_UpdateCrossHairNodeLabelField(sv);
2898             break;
2899 
2900          case SE_SetSOinFocus:
2901             /* expects surface ID in i */
2902             if (EngineData->i_Dest != NextComCode) {
2903                fprintf (SUMA_STDERR,
2904                         "Error %s: Data not destined correctly for %s (%d).\n",
2905                         FuncName, NextCom, NextComCode);
2906                break;
2907             }
2908             if (sv->Focus_DO_ID != EngineData->i) {
2909                /* a new one, update */
2910                sv->Focus_DO_ID = EngineData->i;
2911                SUMA_UpdateViewerTitle(sv);
2912             }
2913             break;
2914 
2915          case SE_ToggleLockView:
2916             /* expects index of viewer in i to toggle its lock view */
2917             /* toggles the lock view button */
2918             if (EngineData->i_Dest != NextComCode) {
2919                fprintf (SUMA_STDERR,
2920                   "Error %s: Data not destined correctly for %s (%d).\n",
2921                         FuncName, NextCom, NextComCode);
2922                break;
2923             }
2924             SUMAg_CF->ViewLocked[EngineData->i] =
2925                         !SUMAg_CF->ViewLocked[EngineData->i];
2926             /* update button if needed*/
2927             if (EngineData->Src != SES_SumaWidget) {
2928                XmToggleButtonSetState (
2929                         SUMAg_CF->X->SumaCont->LockView_tbg[EngineData->i],
2930                         SUMAg_CF->ViewLocked[EngineData->i], NOPE);
2931             }
2932 
2933             /* call function to update the AllLock button */
2934             SUMA_set_LockView_atb ();
2935 
2936             break;
2937 
2938          case SE_ToggleLockAllViews:
2939             /* expects nothing, toggles all locked view buttons */
2940 
2941             /* get the current value of the button */
2942             {
2943                SUMA_Boolean CurState;
2944                CurState =
2945                   XmToggleButtonGetState (SUMAg_CF->X->SumaCont->LockAllView_tb);
2946                for (ii=0; ii< SUMA_MAX_SURF_VIEWERS; ++ii) {
2947                   /* set all buttons accrodingly */
2948                   XmToggleButtonSetState (
2949                      SUMAg_CF->X->SumaCont->LockView_tbg[ii], CurState, NOPE);
2950                   SUMAg_CF->ViewLocked[ii] = CurState;
2951                }
2952             }
2953             break;
2954 
2955          case SE_ToggleLockAllCrossHair:
2956             /* expects nothing, toggles cross hair lock for all viewers */
2957             {
2958                char LockName[100];
2959                SUMA_LockEnum_LockType (SUMAg_CF->Locked[0], LockName);
2960                fprintf (SUMA_STDERR,
2961                         "%s: Switching Locktype from %s", FuncName, LockName);
2962                /* change the locking type of viewer 0 */
2963                SUMAg_CF->Locked[0] = (int)fmod(SUMAg_CF->Locked[0]+1,
2964                                           SUMA_N_Lock_Types);
2965                SUMA_LockEnum_LockType (SUMAg_CF->Locked[0], LockName);
2966                fprintf (SUMA_STDERR," %s\n", LockName);
2967                /* update the widget*/
2968                SUMA_set_Lock_rb (SUMAg_CF->X->SumaCont->Lock_rbg, 0,
2969                                  SUMAg_CF->Locked[0]);
2970                /* Change the locking type of all remaining viewers,
2971                   including unopen ones */
2972                for (ii=1; ii< SUMA_MAX_SURF_VIEWERS; ++ii) {
2973                   SUMAg_CF->Locked[ii] = SUMAg_CF->Locked[0];
2974                   SUMA_set_Lock_rb (SUMAg_CF->X->SumaCont->Lock_rbg, ii,
2975                                     SUMAg_CF->Locked[ii]);
2976                }
2977 
2978                /* now update the all lock keys */
2979                SUMA_set_Lock_arb (SUMAg_CF->X->SumaCont->Lock_rbg);
2980 
2981             }
2982             break;
2983 
2984          case SE_SetLockAllCrossHair:
2985             /* expects a Lock value in i , sets the lock of all viewers */
2986             if (EngineData->i_Dest != NextComCode) {
2987                fprintf (SUMA_STDERR,
2988                   "Error %s: Data not destined correctly for %s (%d).\n",
2989                   FuncName, NextCom, NextComCode);
2990                break;
2991             }
2992             {
2993 
2994                /* Change the locking type of all remaining viewers,
2995                      including unopen ones */
2996                for (ii=0; ii< SUMA_MAX_SURF_VIEWERS; ++ii) {
2997                   SUMAg_CF->Locked[ii] = EngineData->i;
2998                   SUMA_set_Lock_rb (SUMAg_CF->X->SumaCont->Lock_rbg, ii,
2999                                     SUMAg_CF->Locked[ii]);
3000                }
3001 
3002                /* now update the all lock keys */
3003                SUMA_set_Lock_arb (SUMAg_CF->X->SumaCont->Lock_rbg);
3004             }
3005             break;
3006 
3007          case SE_LockCrossHair:
3008             /* expects nothing in EngineData */
3009             /* calls other viewers and determine if the cross hair
3010                needs to be locked to the calling sv */
3011 
3012             /* check to see if other viewers need to share the fate */
3013             ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
3014             if (ii < 0) {
3015                fprintf (SUMA_STDERR,
3016                         "Error %s: Failed to find index of sv.\n", FuncName);
3017                break;
3018             }
3019             if (SUMAg_CF->Locked[ii]) { /* This one's locked, find out which
3020                                        other viewers are locked to this one */
3021                SUMA_LH("SV %d locked to something, maybe", ii);
3022                for (i=0; i < SUMAg_N_SVv; ++i) {
3023                   svi = &SUMAg_SVv[i];
3024                   if (i != ii) {
3025                      SUMA_LH("Tiz locked %d to sv %d", SUMAg_CF->Locked[i], i);
3026                      switch (SUMAg_CF->Locked[i]) {
3027                         case SUMA_No_Lock:
3028                            if (LocalHead)
3029                               fprintf (SUMA_STDERR,
3030                                        "%s: No lock for viewer %d.\n",
3031                                        FuncName, i);
3032                            break;
3033                         case SUMA_XYZ_Lock:
3034                            if (LocalHead)
3035                               fprintf (SUMA_STDERR,
3036                                        "%s: Try to XYZ lock viewer %d.\n",
3037                                        FuncName, i);
3038                            /* just set the XYZ, and free the binding
3039                               to the surfaces */
3040                            svi->Ch->c[0] = sv->Ch->c[0];
3041                            svi->Ch->c[1] = sv->Ch->c[1];
3042                            svi->Ch->c[2] = sv->Ch->c[2];
3043                            svi->Ch->datumID = -1;
3044                            svi->Ch->adoID = -1;
3045                            /* FORCE a redisplay */
3046                            svi->ResetGLStateVariables = YUP;
3047                            SUMA_handleRedisplay((XtPointer)svi->X->GLXAREA);
3048                            break;
3049                         case SUMA_I_Lock:
3050                            Found = NOPE;
3051                            if (iDO_isSO(sv->Ch->adoID)) { /* Surface click */
3052                               SUMA_SurfaceObject *SO1 = NULL, *SO2 = NULL;
3053 
3054                               SUMA_LHv("Try to I lock viewer %d to node"
3055                                        " %d.\n", i, sv->Ch->datumID);
3056 
3057                               /* determine the list of shown surfaces */
3058                               N_SOlist = SUMA_RegisteredSOs(svi, SUMAg_DOv,
3059                                                             SOlist);
3060 
3061                               /* first find the surface that the cross hair
3062                                  is bound to */
3063                               if (sv->Ch->adoID < 0) {
3064                                  fprintf (SUMA_STDERR,
3065                                           "%s: Cannot link from this viewer's "
3066                                           "cross hair. No bound surface.\n",
3067                                           FuncName);
3068                                  break;
3069                               }
3070                               if (sv->Ch->datumID < 0) {
3071                                  SUMA_S_Errv("Cannot link from this viewer's"
3072                                        " cross hair. No datumID for DO %s\n",
3073                                        iDO_label(sv->Ch->adoID));
3074                                  break;
3075                               }
3076 
3077                               SO1 = (SUMA_SurfaceObject *)
3078                                              SUMAg_DOv[sv->Ch->adoID].OP;
3079                               Found = NOPE;
3080                               it = 0;
3081                               while (it < N_SOlist && !Found) {
3082                                  SO2 = (SUMA_SurfaceObject *)
3083                                              SUMAg_DOv[SOlist[it]].OP;
3084                                  if (SUMA_isRelated_SO(SO1, SO2, 2)) {
3085                                        /* high level relationship is allowed,
3086                                           but with same-side enforcement.
3087                                           A level 3 returns a match based on
3088                                           the number of nodes only, but that
3089                                           can cause trouble between left and
3090                                           right hemisphere surfaces where the
3091                                           same node index does not refer
3092                                           necessarily to the same anatomical
3093                                           areas.   */
3094                                     svi->Ch->adoID = SOlist[it];
3095                                     if (sv->Ch->datumID > SO2->N_Node) {
3096                                        SUMA_S_Err("datumID is larger than"
3097                                              " N_Node. Setting datumID to 0.\n");
3098                                        svi->Ch->datumID = 0;
3099                                     }else{
3100                                        svi->Ch->datumID = sv->Ch->datumID;
3101                                     }
3102                                     /* set the XYZ */
3103                                     svi->Ch->c_noVisX[0] =
3104                                                SO2->NodeList[SO2->NodeDim*
3105                                                                svi->Ch->datumID];
3106                                     svi->Ch->c_noVisX[1] =
3107                                                SO2->NodeList[SO2->NodeDim*
3108                                                              svi->Ch->datumID+1];
3109                                     svi->Ch->c_noVisX[2] =
3110                                                SO2->NodeList[SO2->NodeDim*
3111                                                              svi->Ch->datumID+2];
3112                                     svi->Ch->c[0]=svi->Ch->c_noVisX[0];
3113                                     svi->Ch->c[1]=svi->Ch->c_noVisX[1];
3114                                     svi->Ch->c[2]=svi->Ch->c_noVisX[2];
3115                                     if (SO2->VisX.Applied) { /* Apply the VisX */
3116                                        SUMA_Apply_VisX_Chain(svi->Ch->c, 1,
3117                                                           SO2->VisX.Xchain, 0);
3118                                     }
3119                                     if (LocalHead)
3120                                        fprintf (SUMA_STDERR,
3121                                                 "%s: new XYZ %f %f %f\n",
3122                                                 FuncName,
3123                                                 svi->Ch->c[0], svi->Ch->c[1],
3124                                                 svi->Ch->c[2]);
3125                                     Found = YUP;
3126                                  }
3127                                  ++it;
3128                               }
3129                            } else if (iDO_isGLDO(sv->Ch->adoID)){
3130                               SUMA_GraphLinkDO *gldo1, *gldo2=NULL;
3131                               SUMA_DSET *dset=NULL;
3132                               char *variant=NULL;
3133                               int ido2;
3134                               float fv6[6];
3135                               SUMA_LHv("Try to I lock viewer %d to edge"
3136                                        " %d.\n", i, sv->Ch->datumID);
3137 
3138                               if (sv->Ch->adoID < 0) {
3139                                  fprintf (SUMA_STDERR,
3140                                           "%s: Cannot link from this viewer's "
3141                                           "cross hair. No bound graph.\n",
3142                                           FuncName);
3143                                  break;
3144                               }
3145                               if (sv->Ch->datumID < 0) {
3146                                  SUMA_LHv("No datumID for DO %s\n",
3147                                        iDO_label(sv->Ch->adoID));
3148                                  /* Don't exit here, because sometimes users
3149                                  select and entire set of edes, when they
3150                                  click on the nodes of a graph, you still
3151                                  want to refresh the other representations
3152                                  of that graph*/
3153                               }
3154                               gldo1 = (SUMA_GraphLinkDO *)
3155                                           SUMAg_DOv[sv->Ch->adoID].OP;
3156                               if (!(dset = SUMA_find_GLDO_Dset(gldo1))) {
3157                                  SUMA_S_Err("Seal Attack!");
3158                                  break;
3159                               }
3160                               Found = NOPE;
3161                               it = 0;
3162                               while (it < svi->N_DO && !Found) {
3163                                     ido2 = svi->RegistDO[it].dov_ind;
3164                                     if (iDO_isGLDO(ido2)) {
3165                                  gldo2 = (SUMA_GraphLinkDO *)SUMAg_DOv[ido2].OP;
3166                                  variant = iDO_variant(ido2);
3167                                     } else {
3168                                  gldo2 = NULL;
3169                                  variant = NULL;
3170                                     }
3171                                  if ((SUMA_find_GLDO_Dset(gldo2) == dset)&&
3172                                      SUMA_IS_REAL_VARIANT(variant)) {
3173                                     svi->Ch->adoID = ido2;
3174                                     svi->Ch->datumID = sv->Ch->datumID;
3175 
3176                                     /* set the XYZ */
3177                                     if (svi->Ch->datumID >= 0 &&
3178                                         (SUMA_GDSET_EdgeXYZ_eng(dset,
3179                                                 svi->Ch->datumID,
3180                                            iDO_variant(ido2), fv6))){
3181                                        svi->Ch->c[0] = (fv6[0]+fv6[3])/2.0;
3182                                        svi->Ch->c[1] = (fv6[1]+fv6[4])/2.0;
3183                                        svi->Ch->c[2] = (fv6[2]+fv6[5])/2.0;
3184                                        if (LocalHead)
3185                                           fprintf (SUMA_STDERR,
3186                                                    "%s: new XYZ %f %f %f\n",
3187                                                    FuncName,
3188                                                    svi->Ch->c[0], svi->Ch->c[1],
3189                                                    svi->Ch->c[2]);
3190                                        Found = YUP;
3191                                     } else {
3192                                        /* Still declare it found, even if coords
3193                                           are not set because datum index is < 0
3194                                           This is for updating when you select
3195                                           and edge's point/node */
3196                                        Found = YUP;
3197                                     }
3198                                  }
3199                                  ++it;
3200                               }
3201 
3202                            } else {
3203                               SUMA_LHv(
3204                                  "No linkage for clicks on objects like %s\n",
3205                                  iDO_label(sv->Ch->adoID));
3206                            }
3207                            if (!Found) {
3208                               if (LocalHead)
3209                                  fprintf (SUMA_STDERR,
3210                                           "%s: No related DOs found in"
3211                                           " viewer, cross hair will not be"
3212                                           "touched .\n", FuncName);
3213                               break;
3214                            } else {
3215                               /* FORCE a redisplay */
3216                               svi->ResetGLStateVariables = YUP;
3217                               SUMA_handleRedisplay(
3218                                        (XtPointer)svi->X->GLXAREA);
3219                            }
3220                            break;
3221                         default:
3222                            fprintf(SUMA_STDERR,
3223                                    "Error %s: Lock type (%d) undefined.\n",
3224                                    FuncName, SUMAg_CF->Locked[ii]);
3225                            break;
3226                      }
3227                   }
3228                }
3229             }else{
3230                /* not locked to anything */
3231                SUMA_LH("SV %d not locked to anything", ii);
3232             }
3233             break;
3234 
3235          case SE_SetAfniCrossHair:
3236             /* expects a Do_icor flag in i  */
3237             if (EngineData->i_Dest != NextComCode) {
3238                fprintf (SUMA_STDERR,
3239                   "Error %s: Data not destined correctly for %s (%d).\n",
3240                   FuncName, NextCom, NextComCode);
3241                break;
3242             }
3243             if (  SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
3244                   sv->LinkAfniCrossHair) {
3245                SUMA_LH("Sending cross hair nel: SUMA_crosshair_xyz") ;
3246                if (!(nel = SUMA_makeNI_CrossHair (sv))) {
3247                   SUMA_S_Err("SUMA_makeNI_CrossHair failed");
3248                   break;
3249                }
3250                if (EngineData->i) NI_set_attribute(nel,"Do_icor", "y");
3251                if ( (nn = NI_write_element(
3252                         SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] ,
3253                                  nel , NI_TEXT_MODE)) < 0) {
3254                   SUMA_S_Err("NI_write_element failed");
3255                }
3256                NI_free_element(nel); nel = NULL;
3257             }
3258 
3259             if ( SUMAg_CF->Connected_v[SUMA_HALLO_SUMA_LINE] ) {
3260                SUMA_LH("Sending cross hair nel: SUMA_crosshair_xyz") ;
3261                if (!(nel = SUMA_makeNI_CrossHair (sv))) {
3262                   SUMA_S_Err("SUMA_makeNI_CrossHair failed");
3263                   break;
3264                }
3265                if ( (nn = NI_write_element(
3266                         SUMAg_CF->ns_v[SUMA_HALLO_SUMA_LINE] ,
3267                                  nel , NI_TEXT_MODE)) < 0) {
3268                   SUMA_S_Err("NI_write_element failed");
3269                }
3270                NI_free_element(nel); nel = NULL;
3271             }
3272 
3273             if ( SUMAg_CF->Connected_v[SUMA_INSTA_TRACT_LINE] ) {
3274                NI_group *ngr=NULL;
3275                if (!(ngr = SUMA_makeNI_InstaTract_Query (sv))) {
3276                   SUMA_LH("SUMA_makeNI_InstaTract_Query failed, or "
3277                           "nothing found");
3278                   break;
3279                }
3280                if ( (nn = NI_write_element(
3281                         SUMAg_CF->ns_v[SUMA_INSTA_TRACT_LINE] ,
3282                                  ngr , NI_BINARY_MODE)) < 0) {
3283                   SUMA_S_Err("NI_write_element failed");
3284                }
3285                if (LocalHead) SUMA_ShowNel(ngr);
3286                NI_free_element(ngr); ngr = NULL;
3287             }
3288             break;
3289 
3290          case SE_SetGICORnode:
3291             /* expects nothing in EngineData */
3292             /* sends the current node to Group Icor */
3293             if (SUMAg_CF->giset && SUMAg_CF->Connected_v[SUMA_GICORR_LINE]
3294                 && !SUMAg_CF->HoldClickCallbacks &&
3295                 (SO = SUMA_SV_Focus_SO(sv))) {
3296                SUMA_LHv("Sending notice to GICOR, SO_ID: %d\n",
3297                               sv->Focus_DO_ID);
3298                if (SUMA_AFNI_gicor_setref(SO, SO->SelectedNode) < 0) {
3299                   SUMA_S_Err("Failed in SUMA_AFNI_gicor_setref");
3300                }
3301             }
3302 
3303             break;
3304 
3305          case SE_SetLookAtNode:
3306             /* expects a center XYZ in EngineData->fv15[0 .. 2]
3307             expects a normal vector in EngineData->fv15[3 .. 5] */
3308             if (EngineData->fv15_Dest != NextComCode) {
3309                fprintf (SUMA_STDERR,
3310                   "Error %s: Data not destined correctly for %s (%d).\n",
3311                   FuncName, NextCom, NextComCode);
3312                break;
3313             }
3314 
3315             { float CurrentDistance;
3316               float fm2_3[2][3]={ {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0} }, *dir;
3317 
3318             /* modify the ViewFrom Value such that the viewing distance
3319                remains the same */
3320             CurrentDistance = sqrt((sv->GVS[sv->StdView].ViewFrom[0] -
3321                                     sv->GVS[sv->StdView].ViewCenter[0]) *
3322                                    (sv->GVS[sv->StdView].ViewFrom[0] -
3323                                     sv->GVS[sv->StdView].ViewCenter[0]) +
3324                                    (sv->GVS[sv->StdView].ViewFrom[1] -
3325                                     sv->GVS[sv->StdView].ViewCenter[1]) *
3326                                    (sv->GVS[sv->StdView].ViewFrom[1] -
3327                                     sv->GVS[sv->StdView].ViewCenter[1]) +
3328                                    (sv->GVS[sv->StdView].ViewFrom[2] -
3329                                     sv->GVS[sv->StdView].ViewCenter[2]) *
3330                                    (sv->GVS[sv->StdView].ViewFrom[2] -
3331                                     sv->GVS[sv->StdView].ViewCenter[2]));
3332 
3333             /* set the ViewCenter Value to that of the node's XYZ*/
3334             sv->GVS[sv->StdView].ViewCenter[0] = EngineData->fv15[0];
3335             sv->GVS[sv->StdView].ViewCenter[1] = EngineData->fv15[1];
3336             sv->GVS[sv->StdView].ViewCenter[2] = EngineData->fv15[2];
3337 
3338             /* obtain the LookFrom point based on CurrentDistance and
3339                the normal vector */
3340             dir = &(EngineData->fv15[3]);
3341             SUMA_POINT_AT_DISTANCE(dir,
3342                   sv->GVS[sv->StdView].ViewCenter, CurrentDistance, fm2_3);
3343 
3344             fprintf(SUMA_STDOUT,"\nPoints: %f %f %f\n%f %f %f\n",
3345                fm2_3[0][0], fm2_3[0][1], fm2_3[0][2],
3346                fm2_3[1][0], fm2_3[1][1], fm2_3[1][2]);
3347 
3348             sv->GVS[sv->StdView].ViewFrom[0] = fm2_3[0][0];
3349             sv->GVS[sv->StdView].ViewFrom[1] = fm2_3[0][1];
3350             sv->GVS[sv->StdView].ViewFrom[2] = fm2_3[0][2];
3351 
3352             gluLookAt ( sv->GVS[sv->StdView].ViewFrom[0],
3353                         sv->GVS[sv->StdView].ViewFrom[1],
3354                         sv->GVS[sv->StdView].ViewFrom[2],
3355                         sv->GVS[sv->StdView].ViewCenter[0],
3356                         sv->GVS[sv->StdView].ViewCenter[1],
3357                         sv->GVS[sv->StdView].ViewCenter[2],
3358                         sv->GVS[sv->StdView].ViewCamUp[0],
3359                         sv->GVS[sv->StdView].ViewCamUp[1],
3360                         sv->GVS[sv->StdView].ViewCamUp[2]);
3361             }
3362 
3363             break;
3364          case SE_SetLookFrom:
3365             /* expects a center XYZ in EngineData->fv3[0 .. 2] */
3366             if (EngineData->fv3_Dest != NextComCode) {
3367                fprintf (SUMA_STDERR,
3368                         "Error %s:\n"
3369                         " Data not destined correctly for %s (%d).\n",
3370                         FuncName, NextCom, NextComCode);
3371                break;
3372             }
3373             /* set the LookFrom option */
3374             sv->GVS[sv->StdView].ViewFrom[0] = EngineData->fv3[0];
3375             sv->GVS[sv->StdView].ViewFrom[1] = EngineData->fv3[1];
3376             sv->GVS[sv->StdView].ViewFrom[2] = EngineData->fv3[2];
3377             gluLookAt ( sv->GVS[sv->StdView].ViewFrom[0],
3378                         sv->GVS[sv->StdView].ViewFrom[1],
3379                         sv->GVS[sv->StdView].ViewFrom[2],
3380                         sv->GVS[sv->StdView].ViewCenter[0],
3381                         sv->GVS[sv->StdView].ViewCenter[1],
3382                         sv->GVS[sv->StdView].ViewCenter[2],
3383                         sv->GVS[sv->StdView].ViewCamUp[0],
3384                         sv->GVS[sv->StdView].ViewCamUp[1],
3385                         sv->GVS[sv->StdView].ViewCamUp[2]);
3386             break;
3387 
3388          case SE_Redisplay_AllVisible:
3389             /* expects nothing in EngineData */
3390             /* post a redisplay to all visible viewers,
3391                Do the one where pointer is last */
3392             {
3393                int viewerorder[SUMA_MAX_SURF_VIEWERS], np = 0;
3394                /* set viewer order so that the one that
3395                last had the pointer gets displayed last */
3396                for (ii=0; ii<SUMAg_N_SVv; ++ii) {
3397                   if (ii != SUMAg_CF->PointerLastInViewer) {
3398                      viewerorder[np] = ii; ++np;
3399                   }
3400                }
3401                if (np < SUMAg_N_SVv) {
3402                   viewerorder[np] = SUMAg_CF->PointerLastInViewer;
3403                   ++np;
3404                }
3405                if (np != SUMAg_N_SVv) {
3406                   SUMA_S_Err("WTH?");
3407                }
3408                for (np=0; np<SUMAg_N_SVv; ++np) {
3409                   ii = viewerorder[np];
3410                   if (LocalHead)
3411                      fprintf (SUMA_STDERR,
3412                               "%s: Checking viewer %d.\n", FuncName, ii);
3413                   if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
3414                      /* you must check for both conditions because by default
3415                      all viewers are initialized to isShaded = NOPE, even before
3416                      they are ever opened */
3417                      if (LocalHead)
3418                         fprintf (SUMA_STDERR,
3419                                  "%s: Redisplaying viewer %d.\n", FuncName, ii);
3420                      SUMAg_SVv[ii].ResetGLStateVariables = YUP;
3421                      SUMA_postRedisplay(SUMAg_SVv[ii].X->GLXAREA, NULL, NULL);
3422                   }
3423                }
3424             }
3425             break;
3426 
3427 
3428          case SE_Redisplay:
3429             /* expects nothing in EngineData */
3430             /*post a redisplay to one specific viewer*/
3431             if (LocalHead) fprintf (SUMA_STDOUT,"%s: Redisplay ...", FuncName);
3432             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3433             if (LocalHead) fprintf (SUMA_STDOUT," Done\n");
3434             break;
3435 
3436          case SE_RedisplayNow:
3437             /* expects nothing in EngineData */
3438             /*call handle redisplay immediately to one specific viewer*/
3439             if (LocalHead)
3440                fprintf (SUMA_STDOUT,"%s: Redisplaying NOW ...", FuncName);
3441             sv->ResetGLStateVariables = YUP;
3442             SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3443             if (LocalHead) fprintf (SUMA_STDOUT," Done\n");
3444             break;
3445 
3446          case SE_RedisplayNow_AllVisible:
3447             /* expects nothing in EngineData */
3448             /* causes  an immediate redisplay to all visible viewers
3449                The viewer that had the pointer last gets
3450                displayed last. This is similar in concept
3451                to SE_RedisplayNow_AllOtherVisible */
3452             {
3453                int viewerorder[SUMA_MAX_SURF_VIEWERS], np = 0;
3454                /* set viewer order so that the one that
3455                last had the pointer gets displayed last */
3456                for (ii=0; ii<SUMAg_N_SVv; ++ii) {
3457                   if (ii != SUMAg_CF->PointerLastInViewer) {
3458                      viewerorder[np] = ii; ++np;
3459                   }
3460                }
3461                if (np < SUMAg_N_SVv) {
3462                   viewerorder[np] = SUMAg_CF->PointerLastInViewer;
3463                   ++np;
3464                }
3465                if (np != SUMAg_N_SVv) {
3466                   SUMA_S_Err("WTH?");
3467                }
3468                for (np=0; np<SUMAg_N_SVv; ++np) {
3469                   ii = viewerorder[np];
3470                   if (LocalHead)
3471                      fprintf (SUMA_STDERR,
3472                               "%s: Checking viewer %d.\n", FuncName, ii);
3473                   if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
3474                      /* you must check for both conditions because by default
3475                      all viewers are initialized to isShaded = NOPE, even before
3476                      they are ever opened */
3477                      if (LocalHead)
3478                         fprintf (SUMA_STDERR,
3479                                  "%s: Redisplaying viewer %d.\n", FuncName, ii);
3480                      SUMAg_SVv[ii].ResetGLStateVariables = YUP;
3481                      SUMA_handleRedisplay((XtPointer)SUMAg_SVv[ii].X->GLXAREA);
3482                      SUMA_LHv("Returned redisplaying viewer %d.\n", ii);
3483                   }
3484                }
3485             }
3486             break;
3487 
3488          case SE_RedisplayNow_AllOtherVisible:
3489             /* expects nothing in EngineData, expects sv in srcp*/
3490             /* causes an immediate redisplay to all visible viewers
3491                other than sv*/
3492             for (ii=0; ii<SUMAg_N_SVv; ++ii) {
3493                if (LocalHead)
3494                   fprintf (SUMA_STDERR,"%s: Checking viewer %d.\n",
3495                            FuncName, ii);
3496                if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL &&
3497                      &(SUMAg_SVv[ii]) != sv) {
3498                   /* you must check for both conditions because by default
3499                   all viewers are initialized to isShaded = NOPE, even before
3500                   they are ever opened */
3501                   if (LocalHead)
3502                      fprintf (SUMA_STDERR,"%s: Redisplaying viewer %d.\n",
3503                               FuncName, ii);
3504                   SUMAg_SVv[ii].ResetGLStateVariables = YUP;
3505                   SUMA_handleRedisplay((XtPointer)SUMAg_SVv[ii].X->GLXAREA);
3506                }
3507             }
3508             break;
3509 
3510          case SE_ResetOpenGLState:
3511             /* reset OPEN GL's state variables */
3512             /* expects the surface viewer pointer in vp */
3513             if (EngineData->vp_Dest != NextComCode) {
3514                SUMA_S_Err("Data not destined correctly for %s (%d).\n",
3515                           NextCom, NextComCode);
3516                break;
3517             }
3518             SUMA_LH("Resetting OpenGL state variables.\n");
3519 
3520             /* No need to call SUMA_OpenGLStateReset,
3521                that is now done in SUMA_display */
3522             svi = (SUMA_SurfaceViewer *)EngineData->vp;
3523             svi->ResetGLStateVariables = YUP;
3524             break;
3525 
3526          case SE_ToggleForeground:
3527             /* expects nothing in EngineData */
3528             /* Show/hide the foreground */
3529             sv->ShowForeground = !sv->ShowForeground;
3530             if (!sv->ShowForeground) {
3531                fprintf(SUMA_STDOUT,"%s: Foreground Colors Off.\n", FuncName);
3532             } else {
3533                fprintf(SUMA_STDOUT,"%s: Foreground Colors ON.\n", FuncName);
3534             }
3535             /* set the color remix flag */
3536             if (!SUMA_SetShownLocalRemixFlag (sv)) {
3537                fprintf (SUMA_STDERR,
3538                         "Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n",
3539                         FuncName);
3540                break;
3541             }
3542             break;
3543 
3544          case SE_ToggleBackground:
3545             /* expects nothing in EngineData */
3546             /* Show/hide the background */
3547             sv->ShowBackground = !sv->ShowBackground;
3548             if (!sv->ShowBackground) {
3549                fprintf(SUMA_STDOUT,"%s: Background Colors OFF.\n", FuncName);
3550             } else {
3551                fprintf(SUMA_STDOUT,"%s: Background Colors ON.\n", FuncName);
3552             }
3553             /* set the color remix flag */
3554             if (!SUMA_SetShownLocalRemixFlag (sv)) {
3555                fprintf (SUMA_STDERR,
3556                         "Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n",
3557                         FuncName);
3558                break;
3559             }
3560             break;
3561 
3562          case SE_Home:
3563             /* expects nothing in EngineData, needs sv */
3564             SUMA_SetGLHome(sv);
3565             break;
3566 
3567          case SE_Home_AllVisible:
3568             /* expects nothing in EngineData, needs no sv */
3569             {
3570                for (ii=0; ii<SUMAg_N_SVv; ++ii) {
3571                   SUMA_LHv("Checking viewer %d.\n", ii);
3572                   if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
3573                      /* you must check for both conditions because by default
3574                      all viewers are initialized to isShaded = NOPE,
3575                      even before they are ever opened */
3576                      SUMA_LHv("Home call viewer %d.\n", ii);
3577                      if (!list) {
3578                         SUMA_S_Err(
3579                            "Should not be inside SUMA_Engine: ZSS Feb 02 05.\n");
3580                         /* list = SUMA_CreateList();*/
3581                         break;
3582                      }
3583                      SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home,
3584                                                       SES_Suma, &SUMAg_SVv[ii]);
3585                   }
3586                }
3587             }
3588             break;
3589 
3590          case SE_FOVreset:
3591             /* expects nothing in EngineData */
3592             sv->FOV[sv->iState] = SUMA_sv_auto_fov(sv);
3593                         /* reset the zooming */
3594             /* Now update the zoom compensation variable */
3595             if (sv->ZoomCompensate) {
3596                sv->ZoomCompensate = sv->FOV[sv->iState] /
3597                                     SUMA_sv_auto_fov(sv);
3598                if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0;
3599                   /* weird stuff at zc_fac higher that 1.5 */
3600                else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;
3601             }
3602 
3603             break;
3604 
3605          case SE_SetNodeColor:
3606             /* expects a four-columned fm in EngineData->fm[0 .. N][0..3]
3607             [Node Index] [R] [G] [B] RGB between 0 and 1*/
3608             if (EngineData->fm_Dest != NextComCode) {
3609                fprintf (SUMA_STDERR,
3610                         "Error %s: Data not destined correctly for %s (%d).\n",
3611                         FuncName, NextCom, NextComCode);
3612                break;
3613             }
3614 
3615             if ((SO = SUMA_SV_Focus_SO(sv))) {
3616                GLfloat *glar_ColorList;
3617                glar_ColorList = SUMA_GetColorList(sv, SO->idcode_str);
3618                if (!glar_ColorList) {
3619                   SUMA_S_Err("NULL color list array. Trouble.");
3620                   break;
3621                }
3622                for (i=0; i < EngineData->N_rows; ++i){
3623                   ii = (int)(EngineData->fm[i][0]);
3624                   glar_ColorList[4*ii] = EngineData->fm[i][1];
3625                   glar_ColorList[4*ii+1] = EngineData->fm[i][2];
3626                   glar_ColorList[4*ii+2] = EngineData->fm[i][3];
3627                   glar_ColorList[4*ii+3] = 0.5;
3628                }
3629             }
3630             break;
3631 
3632          case SE_FlipLight0Pos:
3633             /* expects nothing in EngineData */
3634             sv->light0_position[0] *= -1;
3635             sv->light0_position[1] *= -1;
3636             sv->light0_position[2] *= -1;
3637             sv->lit_for *= -1;
3638             glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
3639             break;
3640 
3641          case SE_SetLight0Pos:
3642             /* expects light XYZ position in fv[3] */
3643             if (EngineData->fv3_Dest != NextComCode) {
3644                fprintf (SUMA_STDERR,
3645                   "Error %s: Data not destined correctly for %s (%d).\n",
3646                      FuncName, NextCom, NextComCode);
3647                break;
3648             }
3649             sv->light0_position[0] = EngineData->fv3[0];
3650             sv->light0_position[1] = EngineData->fv3[1];
3651             sv->light0_position[2] = EngineData->fv3[2];
3652             glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
3653             break;
3654 
3655          case SE_HighlightNodes:
3656             /* highlight nodes inside the search box */
3657             /* expects Node XYZ in EngineData->fv15[0..2]
3658             Box dimensions in EngineData->fv15[3..5] */
3659             if (EngineData->fv15_Dest != NextComCode) {
3660                SUMA_S_Errv("Data not destined correctly for %s (%d).\n",
3661                            NextCom, NextComCode);
3662                break;
3663             }
3664             if ((SO = SUMA_SV_Focus_SO(sv))) {
3665                SUMA_ISINBOX IB;
3666 
3667                ND = SO->NodeDim;
3668 
3669                SUMA_etime (&tt, 0);
3670                IB = SUMA_isinbox (SO->NodeList, SO->N_Node,
3671                            &(EngineData->fv15[0]), &(EngineData->fv15[3]),  YUP);
3672                delta_t = SUMA_etime (&tt, 1);
3673                fprintf (SUMA_STDOUT,"Elapsed time for isinbox operation: %f\n",
3674                                     delta_t);
3675                fprintf (SUMA_STDOUT,"\t%d nodes (out of %d) found in box\n",
3676                                     IB.nIsIn, SO->N_Node);
3677 
3678                if (IB.nIsIn) { /* found some, find the closest node */
3679                   /* locate the closest node and store it's id in EngineData*/
3680                   SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, ft, it);
3681 
3682                   /* XYZ and normal of the closest to the center */
3683                   /* Color the nodes*/
3684                   fm = (float **)SUMA_allocate2D(IB.nIsIn, 4, sizeof(float));
3685                   if (fm == NULL) {
3686                      fprintf(SUMA_STDERR,
3687                              "Error %s: Could not allocate for fm.\n", FuncName);
3688                      break;
3689                   }
3690                   for (i=0; i < IB.nIsIn; ++i) {
3691                       /* id = ND * IB.IsIn[i]; */
3692                       /*fprintf (SUMA_STDOUT,"\t[%d] %f %f %f\n", IB.IsIn[i] ,\
3693                                    SO->NodeList[id], SO->NodeList[id+1],
3694                                    SO->NodeList[id+2]);*/
3695                      /* color those nodes in yellow, just for kicks */
3696                      fm[i][0] = (float)IB.IsIn[i];
3697                      fm[i][1] = 0;
3698                      fm[i][2] = 0.4;
3699                      fm[i][3] = 0.4;
3700                   }
3701 
3702                   /* Place a call to Redisplay and SetNodeColor */
3703                   ED = SUMA_InitializeEngineListData (SE_SetNodeColor);
3704                   ED->N_cols = 4;
3705                   ED->N_rows = IB.nIsIn;
3706                   if (!SUMA_RegisterEngineListCommand (  list, ED,
3707                                                          SEF_fm, (void*)fm,
3708                                                          SES_Suma, (void *)sv,
3709                                                          NOPE,
3710                                                          SEI_Head, NULL)) {
3711                      fprintf(SUMA_STDERR,
3712                              "Error %s: Failed to register element\n", FuncName);
3713                      break;
3714                   }
3715                   ED = SUMA_InitializeEngineListData (SE_Redisplay);
3716                   SUMA_RegisterEngineListCommand (  list, ED,
3717                                                     SEF_Empty, NULL,
3718                                                     SES_Suma, (void *)sv, NOPE,
3719                                                     SEI_Head, NULL);
3720 
3721                   /* free fm since it was copied to EngineData*/
3722                   if (fm) SUMA_free2D ((char **)fm, IB.nIsIn);
3723 
3724                   /* get ridd of IB's vectors */
3725                   if (!SUMA_Free_IsInBox (&IB)) {
3726                      fprintf( SUMA_STDERR,
3727                               "Error %s: Failed to free IB\n", FuncName);
3728                   }
3729                } else { /* no node is close enough */
3730                   /* Do nothing yet */
3731                   fprintf (SUMA_STDOUT,
3732                            "\nNo nodes found inside the specified box.\n");
3733                }
3734             }
3735             break;
3736 
3737          case SE_GetNearestNode:
3738             /* lookfor nodes inside the search box */
3739             /* expects Node XYZ in EngineData->fv15[0..2]
3740             Box dimensions in EngineData->fv15[3..5] */
3741             if (EngineData->fv15_Dest != NextComCode) {
3742                fprintf (SUMA_STDERR,
3743                         "Error %s: Data not destined correctly for %s (%d).\n",
3744                         FuncName, NextCom, NextComCode);
3745                break;
3746             }
3747             if ((SO = SUMA_SV_Focus_SO(sv))){
3748                SUMA_ISINBOX IB;
3749 
3750                ND = SO->NodeDim;
3751                SUMA_etime (&tt, 0);
3752                IB = SUMA_isinbox (SO->NodeList, SO->N_Node,
3753                                  &(EngineData->fv15[0]), &(EngineData->fv15[3]),
3754                                  YUP);
3755                delta_t = SUMA_etime (&tt, 1);
3756                fprintf (SUMA_STDOUT,
3757                         "Elapsed time for isinbox operation: %f\n", delta_t);
3758                fprintf (SUMA_STDOUT,
3759                         "\t%d nodes (out of %d) found in box\n",
3760                         IB.nIsIn, SO->N_Node);
3761 
3762                if (IB.nIsIn) { /* found some, find the closest node */
3763                   /* locate the closest node and store it's id in EngineData*/
3764                   SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, ft, it);
3765 
3766                   /* get the XYZ and normal of that node */
3767                   id = ND * IB.IsIn[it];
3768                   fv15[0] = SO->NodeList[id];
3769                   fv15[1] = SO->NodeList[id+1];
3770                   fv15[2] = SO->NodeList[id+2];
3771                   fv15[3] = SO->NodeNormList[id];
3772                   fv15[4] = SO->NodeNormList[id+1];
3773                   fv15[5] = SO->NodeNormList[id+2];
3774 
3775                   ED = SUMA_InitializeEngineListData (SE_SetLookAtNode);
3776                   if (!SUMA_RegisterEngineListCommand (  list, ED,
3777                                                          SEF_fv15, (void *)fv15,
3778                                                          SES_Suma, (void *)sv,
3779                                                          NOPE,
3780                                                          SEI_Head, NULL)) {
3781                      fprintf( SUMA_STDERR,
3782                               "Error %s: Failed to register element\n",
3783                               FuncName);
3784                      break;
3785                   }
3786 
3787                   /* get ridd of IB's vectors */
3788                   if (!SUMA_Free_IsInBox (&IB)) {
3789                      fprintf( SUMA_STDERR,
3790                               "Error %s: Failed to free IB\n", FuncName);
3791                   }
3792                } else { /* no node is close enough */
3793                   /* Do nothing yet */
3794                }
3795             }
3796             break;
3797 
3798          case SE_SetRotMatrix:
3799             /* expects a rotation matrix in fm, 4x4 */
3800             /* takes the rotation matrix 3x3 with 0 in 4th row and column
3801             and 1.0 at 4,4
3802             makes a quaternion from it and sets csv->currentQuat
3803             and posts redisplay */
3804             if (EngineData->fm_Dest != NextComCode) {
3805                fprintf (SUMA_STDERR,
3806                         "Error %s: "
3807                         "Data not destined correctly for %s (%d).\n",
3808                         FuncName, NextCom, NextComCode);
3809                break;
3810             }
3811             if (EngineData->N_rows != 4 || EngineData->N_cols != 4) {
3812                fprintf( SUMA_STDERR,
3813                         "Error %s: "
3814                         "fm must have 4 cols and 4 rows in SetRotMatrix\n",
3815                         FuncName);
3816                break;
3817             }
3818             if (!SUMA_mattoquat (EngineData->fm,
3819                                  sv->GVS[sv->StdView].currentQuat))
3820                {
3821                   fprintf( SUMA_STDERR,
3822                            "Error %s: Failed in SUMA_mattoquat\n", FuncName);
3823                   break;
3824                }
3825             break;
3826 
3827          case SE_SetObjectCont:
3828          case SE_SetSurfCont:
3829             /* expects a ngr and ADO in vp */
3830             if (  EngineData->ngr_Dest != NextComCode ||
3831                   EngineData->vp_Dest != NextComCode) {
3832                fprintf (SUMA_STDERR,
3833                         "Error %s: Data not destined correctly for %s (%d).\n"
3834                         "Have %d and %d\n",
3835                         FuncName, NextCom, NextComCode,
3836                         EngineData->ngr_Dest, EngineData->vp_Dest);
3837                break;
3838             }
3839             ado = (SUMA_ALL_DO *)EngineData->vp;
3840             if (!(SurfCont = SUMA_ADO_Cont(ado))) {
3841                SUMA_S_Err("Need SurfCont for %s", ADO_LABEL(ado));
3842                break;
3843             }
3844 
3845             if (NI_get_attribute(EngineData->ngr, "switch_surf")) {
3846                int is;
3847 
3848                if (SUMA_iswordsame(ADO_GROUP(ado), sv->CurGroupName) != 1) {
3849                   SUMA_S_Errv(
3850                      "ADO %s is of group %s while viewer is of group %s.\n"
3851                      "Need to switch group before switch_surf\n",
3852                      ADO_LABEL(ado), ADO_GROUP(ado), sv->CurGroupName);
3853                   break;
3854                }
3855                is = SUMA_WhichState(ADO_STATE(ado), sv, sv->CurGroupName);
3856                if (is < 0) {
3857                   SUMA_S_Errv("Surface %s of group %s, viewer in group %s\n"
3858                               "No surface of state %s found.\n",
3859                                ADO_LABEL(ado), ADO_GROUP(ado), sv->CurGroupName ,
3860                                ADO_STATE(ado));
3861                   break;
3862                }
3863                if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
3864                                        is, sv->CurGroupName)) {
3865                   SUMA_S_Err("Failed to switch state"); break;
3866                } else {
3867                   sv->Focus_DO_ID = ADO_iDO(ado);
3868                   sv->NewGeom = YUP;   /* sv->ResetGLStateVariables
3869                                           was not enough */
3870                   /* remove this attribute and call engine again
3871                      for redisplay */
3872                   NI_set_attribute(EngineData->ngr, "switch_surf", NULL);
3873                   {
3874                      DList *llist = SUMA_CreateList();
3875                      SUMA_REGISTER_HEAD_COMMAND_NO_DATA(llist, SE_Redisplay,
3876                                                          SES_SumaFromAny, sv);
3877                      if (!SUMA_Engine (&llist)) {
3878                         fprintf( stderr,
3879                                  "Error %s: SUMA_Engine call failed.\n",
3880                                  FuncName);
3881                      }
3882                      /* update titles */
3883                      SUMA_UpdateViewerTitle(sv);
3884                   }
3885                }
3886             }
3887 
3888             if (NI_get_attribute(EngineData->ngr, "switch_dset")) {
3889                SUMA_OVERLAYS *ColPlane = SUMA_Fetch_OverlayPointer(
3890                   ado,
3891                   NI_get_attribute(EngineData->ngr, "switch_dset"),
3892                   &itmp);
3893 
3894                if (!ColPlane) {
3895                   SUMA_S_Errv("Failed to find dset %s\n",
3896                               NI_get_attribute(EngineData->ngr, "switch_dset"));
3897                   break;
3898                } else {
3899                   if (LocalHead)
3900                      fprintf (SUMA_STDERR,
3901                               "%s: Retrieved ColPlane named %s\n",
3902                               FuncName, ColPlane->Name);
3903                   SUMA_InitializeColPlaneShell(ado, ColPlane);
3904                   SUMA_UpdateColPlaneShellAsNeeded(ado);
3905                                  /* update other open ColPlaneShells */
3906                   /* If you're viewing one plane at a time, do a remix */
3907                   if (SurfCont->ShowCurForeOnly)
3908                            SUMA_Remixedisplay(ado);
3909                }
3910             }
3911 
3912             if (NI_get_attribute(EngineData->ngr, "switch_cmap")) {
3913                /* find the colormap */
3914                if ((itmp = SUMA_Find_ColorMap(
3915                               NI_get_attribute( EngineData->ngr, "switch_cmap"),
3916                                                 SUMAg_CF->scm->CMv,
3917                                                 SUMAg_CF->scm->N_maps, -2 )) < 0)
3918                {
3919                   SUMA_S_Err("Failed to find color map"); break;
3920                } else {
3921                   SUMA_COLOR_MAP *ColMap = SUMAg_CF->scm->CMv[itmp];
3922 
3923                   #if 0
3924                   /* Set the menu button to the current choice */
3925                   if (!SUMA_SetCmapMenuChoice(ado, ColMap->Name)) {
3926                      SUMA_SL_Err("Failed in SUMA_SetCmapMenuChoice");
3927                   }
3928 
3929                   /* switch to the recently loaded  cmap */
3930                   if (!SUMA_SwitchColPlaneCmap(ado, ColMap)) {
3931                      SUMA_SL_Err("Failed in SUMA_SwitchColPlaneCmap");
3932                   }
3933 
3934                   /* update Lbl fields */
3935                   SUMA_UpdateNodeLblField(ado);
3936                   #else
3937                   SUMA_SwitchCmap(ado, ColMap, 1);
3938                   #endif
3939                }
3940             }
3941 
3942             if (NI_get_attribute(EngineData->ngr, "switch_cmode")) {
3943                /* Set the menu button to the current choice */
3944                if (!SUMA_SetCmodeMenuChoice (ado,
3945                         NI_get_attribute(EngineData->ngr, "switch_cmode"))) {
3946                   SUMA_SL_Err("Failed in SUMA_SetCmodeMenuChoice");
3947                }
3948 
3949                /* update Lbl fields */
3950                SUMA_UpdateNodeLblField(ado);
3951             }
3952 
3953             if (NI_get_attribute(EngineData->ngr, "load_cmap")) {
3954                SUMA_LoadCmapFile (NI_get_attribute(EngineData->ngr, "load_cmap"),                                   (void *)ado);
3955             }
3956 
3957             if (NI_get_attribute(EngineData->ngr, "I_sb")) {
3958                NI_GET_INT(EngineData->ngr, "I_sb", itmp);
3959                /* inefficient implementation, but avoids duplicate code... */
3960                if (!SUMA_SwitchColPlaneIntensity(ado,
3961                         SurfCont->curColPlane, itmp, 1)) {
3962                   SUMA_S_Err("Failed in I_sb"); break;
3963                }
3964             }
3965             if ((cbuf = NI_get_attribute(EngineData->ngr, "Dsp"))) {
3966 
3967                /* inefficient implementation (causes redisplay,
3968                   but avoids duplicating code... */
3969                if (!SUMA_SetDsetViewMode(ado,
3970                      SUMA_ShowModeStr2ShowModeMenuItem(cbuf), 1)) {
3971                   SUMA_S_Err("Failed in Dsp"); break;
3972                }
3973             }
3974 
3975             /* Should you decide to fix/improve this block,
3976             You should call on function SUMA_SetRangeNew
3977             to set the values, that function will handle
3978             contralateral parallelization, but it does not
3979             seem to use the ShowMode variable so might want
3980             that added to SUMA_SetRangeNew_one ...
3981             Same for B_range and B_scale       ZSS July 2012 */
3982             if (NI_get_attribute(EngineData->ngr, "I_range")) {
3983                char *stmp = NULL;
3984 
3985                NI_GET_STR_CP(EngineData->ngr, "I_range", stmp);
3986                if (!stmp) {
3987                   SUMA_S_Err("Bad I_range");
3988                } else {
3989                   nn = SUMA_StringToNum(stmp, (void*)dv15, 3,2);
3990                   if (nn < 1 || nn > 2) {
3991                      SUMA_S_Err("Bad range string.");
3992                   }else {
3993                      if (nn == 1) {
3994                         dv15[0] = -SUMA_ABS(dv15[0]); dv15[1] = -dv15[0]; }
3995                      else if (dv15[0] > dv15[1]) {
3996                         ftmp = dv15[0]; dv15[0] = dv15[1]; dv15[1] = ftmp; }
3997                      /* have range, set it please */
3998                      SUMA_LHv("Have range of %f, %f\n", dv15[0], dv15[1]);
3999                      SurfCont->curColPlane->OptScl->IntRange[0] = dv15[0];
4000                      SurfCont->curColPlane->OptScl->IntRange[1] = dv15[1];
4001                      SUMA_INSERT_CELL_VALUE(SurfCont->SetRangeTable, 1, 1,
4002                                  SurfCont->curColPlane->OptScl->IntRange[0]);
4003                      SUMA_INSERT_CELL_VALUE(SurfCont->SetRangeTable, 1, 2,
4004                                  SurfCont->curColPlane->OptScl->IntRange[1]);
4005                      if (SurfCont->curColPlane->ShowMode > 0 &&
4006                          SurfCont->curColPlane->ShowMode <
4007                                              SW_SurfCont_DsetViewXXX ) {
4008                         if (!SUMA_ColorizePlane (SurfCont->curColPlane)) {
4009                            SUMA_SLP_Err("Failed to colorize plane.\n");
4010                         } else {
4011                            SUMA_Remixedisplay(ado);
4012                            SUMA_UpdateNodeValField(ado);
4013                            SUMA_UpdateNodeLblField(ado);
4014                         }
4015                      }
4016                   }
4017                   SUMA_free(stmp); stmp = NULL;
4018                }
4019             }
4020 
4021             if (NI_get_attribute(EngineData->ngr, "Clst")) {
4022                char *stmp = NULL;
4023                int an;
4024                float reset;
4025                NI_GET_STR_CP(EngineData->ngr, "Clst", stmp);
4026                if (!stmp) {
4027                   SUMA_S_Err("Bad Clst");
4028                } else {
4029                   nn = SUMA_StringToNum(stmp, (void*)dv15, 3,2);
4030                   if (nn != 2) {
4031                      SUMA_S_Err("Bad Clst string.");
4032                   } else {
4033                      /* set radius */
4034                      an = SUMA_SetClustValue(ado, SurfCont->curColPlane, 1, 1,
4035                           dv15[0], 0.0,
4036                           1, 0, &reset); /* don't redisp. yet */
4037                      if (an < 0) {
4038                         SUMA_S_Err("An error occurred setting radius");
4039                      } else {
4040                         /* set area */
4041                         an = SUMA_SetClustValue(ado, SurfCont->curColPlane, 1, 2,
4042                              dv15[1], 0.0,
4043                              1, 1, &reset); /* Now redisp. */
4044                         if (an < 0) {
4045                            SUMA_S_Err("An error occurred setting area");
4046                         }
4047                      }
4048                   }
4049                }
4050             }
4051 
4052             if (NI_get_attribute(EngineData->ngr, "UseClst")) {
4053                int tog = 0;
4054                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "UseClst", "y")) {
4055                   if (!SurfCont->curColPlane->OptScl->Clusterize) tog = 1;
4056                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "UseClst", "n")){
4057                   if (SurfCont->curColPlane->OptScl->Clusterize) tog = 1;
4058                } else {
4059                   SUMA_S_Errv("Bad value of %s for UseClst. Nothing done.\n",
4060                               NI_get_attribute(EngineData->ngr, "UseClst"));
4061                }
4062                if (tog) SUMA_SetClustTableTit(ado, SurfCont->curColPlane,
4063                                               1, 0, Button1);
4064             }
4065 
4066             if (NI_get_attribute(EngineData->ngr, "shw_0")) {
4067                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "shw_0", "y"))
4068                   SurfCont->curColPlane->OptScl->MaskZero = NOPE;
4069                else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "shw_0", "n"))
4070                   SurfCont->curColPlane->OptScl->MaskZero = YUP;
4071                else {
4072                   SUMA_S_Errv("Bad value of %s for shw_0, setting to 'y'\n",
4073                               NI_get_attribute(EngineData->ngr, "shw_0"));
4074                   SurfCont->curColPlane->OptScl->MaskZero = NOPE;
4075                }
4076                XmToggleButtonSetState ( SurfCont->ShowZero_tb,
4077                               SurfCont->curColPlane->OptScl->MaskZero, YUP);
4078             }
4079 
4080             if (NI_get_attribute(EngineData->ngr, "B_sb")) {
4081                NI_GET_INT(EngineData->ngr, "B_sb", itmp);
4082                /* inefficient implementation, but avoids duplicate code... */
4083                if (!SUMA_SwitchColPlaneBrightness(ado,
4084                         SurfCont->curColPlane, itmp, 1)) {
4085                   SUMA_S_Err("Failed in T_sb"); break;
4086                }
4087             }
4088 
4089             /* See comment for "I_range" above before making further
4090                changes here */
4091             if (NI_get_attribute(EngineData->ngr, "B_range")) {
4092                char *stmp = NULL;
4093                NI_GET_STR_CP(EngineData->ngr, "B_range", stmp);
4094                if (!stmp) {
4095                   SUMA_S_Err("Bad B_range");
4096                } else {
4097                   nn = SUMA_StringToNum(stmp, (void*)dv15, 3,2);
4098                   if (nn < 1 || nn > 2) {
4099                      SUMA_S_Err("Bad range string.");
4100                   }else {
4101                      if (nn == 1) {
4102                         dv15[0] = -SUMA_ABS(dv15[0]); dv15[1] = -dv15[0]; }
4103                      else if (dv15[0] > dv15[1]) {
4104                         ftmp = dv15[0]; dv15[0] = dv15[1]; dv15[1] = ftmp; }
4105                      /* have range, set it please */
4106                      SUMA_LHv("Have range of %f, %f\n", dv15[0], dv15[1]);
4107                      SurfCont->curColPlane->OptScl->BrightRange[0] = dv15[0];
4108                      SurfCont->curColPlane->OptScl->BrightRange[1] = dv15[1];
4109                      SUMA_INSERT_CELL_VALUE(SurfCont->SetRangeTable, 2, 1,
4110                               SurfCont->curColPlane->OptScl->BrightRange[0]);
4111                      SUMA_INSERT_CELL_VALUE(SurfCont->SetRangeTable, 2, 2,
4112                               SurfCont->curColPlane->OptScl->BrightRange[1]);
4113                      if (SurfCont->curColPlane->ShowMode > 0 &&
4114                          SurfCont->curColPlane->ShowMode  <
4115                                              SW_SurfCont_DsetViewXXX) {
4116                         if (!SUMA_ColorizePlane (SurfCont->curColPlane)) {
4117                            SUMA_SLP_Err("Failed to colorize plane.\n");
4118                         } else {
4119                            SUMA_Remixedisplay(ado);
4120                            SUMA_UpdateNodeValField(ado);
4121                            SUMA_UpdateNodeLblField(ado);
4122                         }
4123                      }
4124                   }
4125                   SUMA_free(stmp); stmp = NULL;
4126                }
4127             }
4128             /* See comment for "I_range" above before making further
4129                changes here */
4130             if (NI_get_attribute(EngineData->ngr, "B_scale")) {
4131                char *stmp = NULL;
4132                NI_GET_STR_CP(EngineData->ngr, "B_scale", stmp);
4133                if (!stmp) {
4134                   SUMA_S_Err("Bad B_scale");
4135                } else {
4136                   nn = SUMA_StringToNum(stmp, (void*)dv15, 3,2);
4137                   if (nn != 2) {
4138                      SUMA_S_Err("Bad scale string.");
4139                   }else {
4140                      if (nn == 1) {
4141                         dv15[0] = -SUMA_ABS(dv15[0]); dv15[1] = -dv15[0]; }
4142                      else if (dv15[0] > dv15[1]) {
4143                         ftmp = dv15[0]; dv15[0] = dv15[1]; dv15[1] = ftmp; }
4144                      /* have range, set it please */
4145                      SUMA_LHv("Have scale range of %f, %f\n",dv15[0], dv15[1]);
4146                      SurfCont->curColPlane->OptScl->BrightMap[0] = dv15[0];
4147                      SurfCont->curColPlane->OptScl->BrightMap[1] = dv15[1];
4148                      SUMA_INSERT_CELL_VALUE(SurfCont->SetRangeTable, 3, 1,
4149                               SurfCont->curColPlane->OptScl->BrightMap[0]);
4150                      SUMA_INSERT_CELL_VALUE(SurfCont->SetRangeTable, 3, 2,
4151                               SurfCont->curColPlane->OptScl->BrightMap[1]);
4152                      if (SurfCont->curColPlane->ShowMode > 0 &&
4153                          SurfCont->curColPlane->ShowMode <
4154                                              SW_SurfCont_DsetViewXXX) {
4155                         if (!SUMA_ColorizePlane (SurfCont->curColPlane)) {
4156                            SUMA_SLP_Err("Failed to colorize plane.\n");
4157                         } else {
4158                            SUMA_Remixedisplay(ado);
4159                            SUMA_UpdateNodeValField(ado);
4160                            SUMA_UpdateNodeLblField(ado);
4161                         }
4162                      }
4163                   }
4164                   SUMA_free(stmp); stmp = NULL;
4165                }
4166             }
4167 
4168             if (NI_get_attribute(EngineData->ngr, "T_sb")) {
4169                NI_GET_INT(EngineData->ngr, "T_sb", itmp);
4170                /* inefficient implementation, but avoids duplicate code... */
4171                if (!SUMA_SwitchColPlaneThreshold(ado,
4172                             SurfCont->curColPlane, itmp, 1)) {
4173                   SUMA_S_Err("Failed in T_sb"); break;
4174                }
4175             }
4176             if (NI_get_attribute(EngineData->ngr, "T_val")) {
4177                int unt;
4178                char *stmp=NULL;
4179                float val=0.0;
4180                stmp = SUMA_copy_string(NI_get_attribute(
4181                                                    EngineData->ngr, "T_val"));
4182                SUMA_LHv("Tval %s\n", stmp);
4183                unt = SUMA_NumStringUnits(stmp, 1);
4184                SUMA_LHv("Tval %s\n", stmp);
4185                if (SUMA_StringToNum(stmp, (void *)&val, 1, 1) != 1) {
4186                   SUMA_BEEP;
4187                   /* bad syntax, reset value*/
4188                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Bad syntax.\n", FuncName);
4189                } else {
4190                   switch (unt) {
4191                      case SUMA_P_VALUE_UNITS:
4192                         if (LocalHead)
4193                            fprintf( SUMA_STDERR,
4194                               "%s:\nUnits in p value, transforming %f\n",
4195                               FuncName, val);
4196                         /* transform value from P to threshold value */
4197                         val = (float)SUMA_Pval2ThreshVal (ado, (double)val);
4198                         if (LocalHead)
4199                               fprintf( SUMA_STDERR, "   to %f\n", val);
4200                         break;
4201                      case SUMA_PERC_VALUE_UNITS:
4202                SUMA_LH("Units in percentile value, transforming %f\n", val);
4203                val = SUMA_OverlayPercentile(SurfCont->curColPlane, 'T', val);
4204                         break;
4205                      default:
4206                         break;
4207                   }
4208                }
4209                SUMA_MODIFY_CELL_VALUE(SurfCont->SetThrScaleTable, 0,0, val);
4210 
4211                /* inefficient implementation, but avoids duplicate code... */
4212                SUMA_cb_SetScaleThr(EngineData->vp);
4213                SUMA_free(stmp);
4214             }
4215 
4216             if (NI_get_attribute(EngineData->ngr, "Dim")) {
4217                char stmp[50];
4218                NI_GET_FLOAT(EngineData->ngr, "Dim", ftmp);
4219                SUMA_ColPlane_NewDimFact(ado, NULL, ftmp, 0);
4220             }
4221             if (NI_get_attribute(EngineData->ngr, "Alf")) {
4222                char stmp[50];
4223                NI_GET_FLOAT(EngineData->ngr, "Alf", ftmp);
4224                SUMA_ColPlane_NewAlphaThresh(ado, NULL, ftmp, 0);
4225             }
4226             if (NI_get_attribute(EngineData->ngr, "Opa")) {
4227                char stmp[50];
4228                NI_GET_FLOAT(EngineData->ngr, "Opa", ftmp);
4229 
4230                #if 0 /* should be handled in new call format below */
4231                if (SurfCont && SurfCont->ColPlaneOpacity) {
4232                   SurfCont->ColPlaneOpacity->value = ftmp;
4233                   sprintf(stmp,"%.1f", ftmp);
4234                   SUMA_SET_TEXT_FIELD( SurfCont->ColPlaneOpacity->textfield,
4235                                        stmp);
4236                }
4237                #endif
4238                /* inefficient implementation, but avoids duplicate code... */
4239                SUMA_ColPlane_NewOpacity(ado, NULL, ftmp, 0);
4240             }
4241             if (NI_get_attribute(EngineData->ngr, "view_dset")) {
4242                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "view_dset", "y")) {
4243                   if (SurfCont->curColPlane->ShowMode < 0)
4244                      SurfCont->curColPlane->ShowMode =
4245                         -SurfCont->curColPlane->ShowMode;
4246                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4247                                                 "view_dset", "n")) {
4248                   if (SurfCont->curColPlane->ShowMode > 0)
4249                      SurfCont->curColPlane->ShowMode =
4250                                     -SurfCont->curColPlane->ShowMode;
4251                } else {
4252                   SUMA_S_Errv("Bad value of %s for view_dset, setting to 'y'\n",
4253                               NI_get_attribute(EngineData->ngr, "view_dset"));
4254                   SurfCont->curColPlane->ShowMode = SW_SurfCont_DsetViewCol;
4255                }
4256                SUMA_Set_Menu_Widget( SurfCont->DsetViewModeMenu,
4257                               SUMA_ShowMode2ShowModeMenuItem(
4258                                  SurfCont->curColPlane->ShowMode));
4259             }
4260             if (NI_get_attribute(EngineData->ngr, "do_draw_mask")) {
4261                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4262                                           "do_draw_mask", "All")) {
4263                   sv->DO_DrawMask = SDODM_All;
4264                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4265                                           "do_draw_mask", "CrossHair") ||
4266                           NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4267                                           "do_draw_mask", "n0CrossHair") ) {
4268                   sv->DO_DrawMask = SDODM_n0CrossHair;
4269                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4270                                           "do_draw_mask", "n1CrossHair") ) {
4271                   sv->DO_DrawMask = SDODM_n1CrossHair;
4272                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4273                                           "do_draw_mask", "n2CrossHair") ) {
4274                   sv->DO_DrawMask = SDODM_n2CrossHair;
4275                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4276                                           "do_draw_mask", "n3CrossHair") ) {
4277                   sv->DO_DrawMask = SDODM_n3CrossHair;
4278                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4279                                           "do_draw_mask", "Hide")) {
4280                   sv->DO_DrawMask = SDODM_Hide;
4281                }
4282                /* redisplay */
4283                SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4284             }
4285             if (NI_get_attribute(EngineData->ngr, "view_surf")) {
4286                switch (ado->do_type) {
4287                   case SO_type:
4288                      SO = (SUMA_SurfaceObject *)ado;
4289                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "view_surf", "y")) {
4290                   SO->Show = YUP;
4291                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,"view_surf","n")){
4292                   SO->Show = NOPE;
4293                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4294                                           "view_surf", "Viewer")) {
4295                   SUMA_SET_SO_POLYMODE(SO,SRM_ViewerDefault);
4296                   SUMA_Set_Menu_Widget( SurfCont->RenderModeMenu,
4297                          SUMA_RenderMode2RenderModeMenuItem(SO->PolyMode+1));
4298                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4299                                           "view_surf", "Fill")) {
4300                   SUMA_SET_SO_POLYMODE(SO,SRM_Fill);
4301                   SUMA_Set_Menu_Widget( SurfCont->RenderModeMenu,
4302                          SUMA_RenderMode2RenderModeMenuItem(SO->PolyMode+1));
4303                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4304                                           "view_surf", "Line")) {
4305                   SUMA_SET_SO_POLYMODE( SO, SRM_Line );
4306                   SUMA_Set_Menu_Widget( SurfCont->RenderModeMenu,
4307                          SUMA_RenderMode2RenderModeMenuItem(SO->PolyMode+1));
4308                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4309                                           "view_surf", "Points")) {
4310                   SUMA_SET_SO_POLYMODE(SO,SRM_Points);
4311                   SUMA_Set_Menu_Widget( SurfCont->RenderModeMenu,
4312                          SUMA_RenderMode2RenderModeMenuItem(SO->PolyMode+1));
4313                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4314                                           "view_surf", "Hide")) {
4315                   SUMA_SET_SO_POLYMODE(SO,SRM_Hide);
4316                   SUMA_Set_Menu_Widget( SurfCont->RenderModeMenu,
4317                          SUMA_RenderMode2RenderModeMenuItem(SO->PolyMode+1));
4318                } else {
4319                   SUMA_S_Errv("Bad value of %s for view_surf, setting to 'y'\n",
4320                               NI_get_attribute(EngineData->ngr, "view_surf"));
4321                   SO->Show = YUP; SUMA_SET_SO_POLYMODE(SO,SRM_Fill);
4322                }
4323                /* redisplay */
4324                SUMA_SiSi_I_Insist();   /* did not think that was necessary...
4325                                           But DriveSuma's -view_surf failed
4326                                           to redisplay properly unless you
4327                                           called the command twice or
4328                                           move the cursor into the GLXAREA.
4329                                           This line appears to fix the
4330                                           problem... */
4331                SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4332                      break;
4333                   default:
4334                      SUMA_S_Err("Not ready with view_surf for type %s",
4335                               ADO_TNAME(ado));
4336                      break;
4337                }
4338             }
4339             if (NI_get_attribute(EngineData->ngr, "trans_surf")) {
4340                switch (ado->do_type) {
4341                   case SO_type:
4342                      SO = (SUMA_SurfaceObject *)ado;
4343                      if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4344                                                 "trans_surf", "Viewer")) {
4345                         SUMA_Set_ADO_TransMode(ado,STM_ViewerDefault,
4346                                                0, 1);
4347                      } else {
4348                         int N=0;
4349                         NI_GET_INT(EngineData->ngr, "trans_surf", N);
4350                         if (N < 0 || N > 16) {
4351                            SUMA_S_Errv("Bad value for trans_surf of %s\n",
4352                               NI_get_attribute(EngineData->ngr, "trans_surf"));
4353                         } else {
4354                            SUMA_Set_ADO_TransMode(ado,(N+STM_0), 0, 1);
4355                         }
4356                      }
4357                      /* redisplay */
4358                      SUMA_SiSi_I_Insist(); /* did not think that was necessary...
4359                                                 But DriveSuma's -view_surf failed
4360                                                 to redisplay properly unless you
4361                                                 called the command twice or
4362                                                 move the cursor into the GLXAREA.
4363                                                 This line appears to fix the
4364                                                 problem... */
4365                      SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4366                      break;
4367                      #if 0 /* UNTESTED, don't uncomment until you test*/
4368                   case VolumeObject_type:{
4369                      SUMA_VolumeObject *VO = (SUMA_VolumeObject *)ado;
4370                      SUMA_VOL_SAUX *VSaux;
4371                      if (!(VSaux = ADO_VSaux(ado))) {
4372                         SUMA_S_Warn("No VSaux"); break;
4373                      }
4374                      if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4375                                                 "trans_surf", "Viewer")) {
4376                         SUMA_Set_ADO_TransMode(ado,SATM_ViewerDefault,
4377                                                0, 1);
4378                      } else {
4379                         int N=0;
4380                         NI_GET_INT(EngineData->ngr, "trans_surf", N);
4381                         if (N < 0 || N > 16) {
4382                            SUMA_S_Errv("Bad value for trans_surf of %s\n",
4383                               NI_get_attribute(EngineData->ngr, "trans_surf"));
4384                         } else {
4385                            SUMA_Set_ADO_TransMode(ado,(N+SATM_0), 0, 1);
4386                         }
4387                      }
4388                      /* redisplay */
4389                      SUMA_SiSi_I_Insist(); /* did not think that was necessary...
4390                                                 But DriveSuma's -view_surf failed
4391                                                 to redisplay properly unless you
4392                                                 called the command twice or
4393                                                 move the cursor into the GLXAREA.
4394                                                 This line appears to fix the
4395                                                 problem... */
4396                      SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4397                      break; }
4398                      #endif
4399                   default:
4400                      SUMA_S_Err("Not ready with trans_surf for type %s",
4401                               ADO_TNAME(ado));
4402                      break;
4403                }
4404             }
4405 
4406             if (NI_get_attribute(EngineData->ngr, "1_only")) {
4407                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "1_only", "y")) {
4408                   itmp = YUP;
4409                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "1_only", "n")) {
4410                   itmp = NOPE;
4411                } else {
4412                   SUMA_S_Errv("Bad value of %s for 1_only, setting to 'y'\n",
4413                               NI_get_attribute(EngineData->ngr, "1_only"));
4414                   itmp = YUP;
4415                }
4416                if (!SUMA_ColPlaneShowOneFore_Set(ado, itmp, 0)) {
4417                   SUMA_S_Err("Failed to set one only");
4418                   break;
4419                }
4420             }
4421 
4422             if (NI_get_attribute(EngineData->ngr, "View_Surf_Cont")) {
4423                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4424                                         "View_Surf_Cont", "y")) {
4425                   if (!SUMA_viewSurfaceCont(NULL, ado, sv)) {
4426                      SUMA_S_Err("Failed open surfcont");
4427                      break;
4428                   }
4429                } else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4430                                                "View_Surf_Cont", "n")) {
4431                   SUMA_LH("Closing surface controller");
4432                   SUMA_cb_closeSurfaceCont(NULL, (XtPointer)ado, NULL);
4433                }
4434             }
4435 
4436             if (NI_get_attribute(EngineData->ngr,"Masks")) {
4437                SUMA_cb_Mask(NULL, ado, sv);
4438             }
4439 
4440             if (NI_get_attribute(EngineData->ngr,"2xMasks")) {
4441                SUMA_cb_Mask(NULL, ado, sv);
4442                SUMA_cb_Mask(NULL, ado, sv);
4443             }
4444 
4445             if ((cbuf = NI_get_attribute(EngineData->ngr,
4446                                           "Write_Surf_Cont_Help"))) {
4447                if (!SUMA_WriteCont_Help(SO_type, TXT, cbuf)) {
4448                   SUMA_S_Err("Failed to write SurfCont help to %s", cbuf);
4449                }
4450             }
4451 
4452             if ((cbuf = NI_get_attribute(EngineData->ngr,
4453                                           "Snap_Surf_Cont_Widgets"))) {
4454                if (!SUMA_Snap_AllCont(SO_type, cbuf)) {
4455                   SUMA_S_Err("Failed to write SurfCont widgets to %s", cbuf);
4456                }
4457             }
4458 
4459             if ((cbuf = NI_get_attribute(EngineData->ngr,
4460                                           "Write_Surf_Cont_Sphinx_Help"))) {
4461                if (!SUMA_WriteCont_Help(SO_type, SPX, cbuf)) {
4462                   SUMA_S_Err("Failed to write SurfCont help to %s", cbuf);
4463                }
4464             }
4465 
4466             if ((cbuf = NI_get_attribute(EngineData->ngr,
4467                                           "Write_Suma_Cont_Help"))) {
4468                if (!SUMA_WriteCont_Help(not_DO_type, TXT, cbuf)) {
4469                   SUMA_S_Err("Failed to write SumaCont help to %s", cbuf);
4470                }
4471             }
4472 
4473             if ((cbuf = NI_get_attribute(EngineData->ngr,
4474                                           "Snap_Suma_Cont_Widgets"))) {
4475                if (!SUMA_Snap_AllCont(not_DO_type, cbuf)) {
4476                   SUMA_S_Err("Failed to write SumaCont widgets to %s", cbuf);
4477                }
4478             }
4479 
4480             if ((cbuf = NI_get_attribute(EngineData->ngr,
4481                                           "Write_Suma_Cont_Sphinx_Help"))) {
4482                if (!SUMA_WriteCont_Help(not_DO_type, SPX, cbuf)) {
4483                   SUMA_S_Err("Failed to write SumaCont help to %s", cbuf);
4484                }
4485             }
4486 
4487             if ((cbuf = NI_get_attribute(EngineData->ngr,
4488                                           "Write_Tract_Cont_Help"))) {
4489                if (!SUMA_WriteCont_Help(TRACT_type, TXT, cbuf)) {
4490                   SUMA_S_Err("Failed to write TractCont help to %s", cbuf);
4491                }
4492             }
4493 
4494             if ((cbuf = NI_get_attribute(EngineData->ngr,
4495                                           "Snap_Tract_Cont_Widgets"))) {
4496                if (!SUMA_Snap_AllCont(TRACT_type, cbuf)) {
4497                   SUMA_S_Err("Failed to write TractCont widgets to %s", cbuf);
4498                }
4499             }
4500 
4501             if ((cbuf = NI_get_attribute(EngineData->ngr,
4502                                           "Write_Tract_Cont_Sphinx_Help"))) {
4503                if (!SUMA_WriteCont_Help(TRACT_type, SPX, cbuf)) {
4504                   SUMA_S_Err("Failed to write TractCont help to %s", cbuf);
4505                }
4506             }
4507 
4508             if ((cbuf = NI_get_attribute(EngineData->ngr,
4509                                           "Write_Mask_Cont_Help"))) {
4510                if (!SUMA_WriteCont_Help(MASK_type, TXT, cbuf)) {
4511                   SUMA_S_Err("Failed to write MaskCont help to %s", cbuf);
4512                }
4513             }
4514 
4515             if ((cbuf = NI_get_attribute(EngineData->ngr,
4516                                           "Snap_Mask_Cont_Widgets"))) {
4517                if (!SUMA_Snap_AllCont(MASK_type, cbuf)) {
4518                   SUMA_S_Err("Failed to write MaskCont widgets to %s", cbuf);
4519                }
4520             }
4521 
4522             if ((cbuf = NI_get_attribute(EngineData->ngr,
4523                                           "Write_Mask_Cont_Sphinx_Help"))) {
4524                if (!SUMA_WriteCont_Help(MASK_type, SPX, cbuf)) {
4525                   SUMA_S_Err("Failed to write MaskCont help to %s", cbuf);
4526                }
4527             }
4528 
4529 
4530             if ((cbuf = NI_get_attribute(EngineData->ngr,
4531                                           "Write_Vol_Cont_Help"))) {
4532                if (!SUMA_WriteCont_Help(VO_type, TXT, cbuf)) {
4533                   SUMA_S_Err("Failed to write TractCont help to %s", cbuf);
4534                }
4535             }
4536 
4537             if ((cbuf = NI_get_attribute(EngineData->ngr,
4538                                           "Snap_Vol_Cont_Widgets"))) {
4539                if (!SUMA_Snap_AllCont(VO_type, cbuf)) {
4540                   SUMA_S_Err("Failed to write VolCont widgets to %s", cbuf);
4541                }
4542             }
4543 
4544             if ((cbuf = NI_get_attribute(EngineData->ngr,
4545                                           "Write_Vol_Cont_Sphinx_Help"))) {
4546                if (!SUMA_WriteCont_Help(VO_type, SPX, cbuf)) {
4547                   SUMA_S_Err("Failed to write TractCont help to %s", cbuf);
4548                }
4549             }
4550 
4551             if ((cbuf = NI_get_attribute(EngineData->ngr,
4552                                           "Write_Graph_Cont_Help"))) {
4553                if (!SUMA_WriteCont_Help(GRAPH_LINK_type, TXT, cbuf)) {
4554                   SUMA_S_Err("Failed to write GraphCont help to %s", cbuf);
4555                }
4556             }
4557 
4558             if ((cbuf = NI_get_attribute(EngineData->ngr,
4559                                           "Snap_Graph_Cont_Widgets"))) {
4560                if (!SUMA_Snap_AllCont(GRAPH_LINK_type, cbuf)) {
4561                   SUMA_S_Err("Failed to write GraphCont widgets to %s", cbuf);
4562                }
4563             }
4564 
4565             if ((cbuf = NI_get_attribute(EngineData->ngr,
4566                                           "Write_Graph_Cont_Sphinx_Help"))) {
4567                if (!SUMA_WriteCont_Help(GRAPH_LINK_type, SPX, cbuf)) {
4568                   SUMA_S_Err("Failed to write GraphCont help to %s", cbuf);
4569                }
4570             }
4571 
4572             if ((cbuf = NI_get_attribute(EngineData->ngr,
4573                                           "Write_ROI_Cont_Help"))) {
4574                if (!SUMA_WriteCont_Help(ROIdO_type, TXT, cbuf)) {
4575                   SUMA_S_Err("Failed to write ROICont help to %s", cbuf);
4576                }
4577             }
4578 
4579             if ((cbuf = NI_get_attribute(EngineData->ngr,
4580                                           "Snap_ROI_Cont_Widgets"))) {
4581                if (!SUMA_Snap_AllCont(ROIdO_type, cbuf)) {
4582                   SUMA_S_Err("Failed to write ROICont widgets to %s", cbuf);
4583                }
4584             }
4585 
4586             if ((cbuf = NI_get_attribute(EngineData->ngr,
4587                                           "Write_ROI_Cont_Sphinx_Help"))) {
4588                if (!SUMA_WriteCont_Help(ROIdO_type, SPX, cbuf)) {
4589                   SUMA_S_Err("Failed to write ROICont help to %s", cbuf);
4590                }
4591             }
4592 
4593             if ((cbuf = NI_get_attribute(EngineData->ngr,
4594                                           "Write_Mouse_Keyb_Help"))) {
4595                FILE *fout = fopen(cbuf,"w");
4596                if (!fout) {
4597                   SUMA_S_Err("Failed to open %s for writing", cbuf);
4598                } else {
4599                   SUMA_help_message(fout, TXT);
4600                   fclose(fout); fout = NULL;
4601                }
4602             }
4603 
4604             if ((cbuf = NI_get_attribute(EngineData->ngr,
4605                                           "Write_Mouse_Keyb_Sphinx_Help"))) {
4606                FILE *fout = fopen(cbuf,"w");
4607                if (!fout) {
4608                   SUMA_S_Err("Failed to open %s for writing", cbuf);
4609                } else {
4610                   SUMA_help_message(fout, SPX);
4611                   fclose(fout); fout = NULL;
4612                }
4613             }
4614 
4615             if ((cbuf = NI_get_attribute(EngineData->ngr,
4616                                          "Write_Mouse_Cmap_Keyb_Help"))) {
4617                FILE *fout = fopen(cbuf,"w");
4618                if (!fout) {
4619                   SUMA_S_Err("Failed to open %s for writing", cbuf);
4620                } else {
4621                   SUMA_cmap_help_message(fout, TXT);
4622                   fclose(fout); fout = NULL;
4623                }
4624             }
4625 
4626             if ((cbuf = NI_get_attribute(EngineData->ngr,
4627                                          "Write_Mouse_Cmap_Keyb_Sphinx_Help"))) {
4628                FILE *fout = fopen(cbuf,"w");
4629                if (!fout) {
4630                   SUMA_S_Err("Failed to open %s for writing", cbuf);
4631                } else {
4632                   SUMA_cmap_help_message(fout, SPX);
4633                   fclose(fout); fout = NULL;
4634                }
4635             }
4636 
4637             if ((cbuf = NI_get_attribute(EngineData->ngr,
4638                                          "Delete_All_Masks"))) {
4639                SUMA_DeleteAllMasks(NULL, NULL, 0);
4640             }
4641 
4642             if ((cbuf = NI_get_attribute(EngineData->ngr,
4643                                          "Load_Masks"))) {
4644                SUMA_LoadMultiMasks(cbuf, NULL);
4645             }
4646 
4647             if ((cbuf = NI_get_attribute(EngineData->ngr,
4648                                          "Save_Masks"))) {
4649                SUMA_SaveMultiMasks(cbuf, NULL);
4650             }
4651 
4652             break;
4653 
4654          case SE_SetViewerCont:
4655             /* expects a ngr and ADO in vp */
4656             if (  EngineData->ngr_Dest != NextComCode ||
4657                   EngineData->vp_Dest != NextComCode) {
4658                fprintf (SUMA_STDERR,
4659                         "Error %s: Data not destined correctly for %s (%d).\n"
4660                         "Have %d and %d\n",
4661                         FuncName, NextCom, NextComCode,
4662                         EngineData->ngr_Dest, EngineData->vp_Dest);
4663                break;
4664             }
4665             ado = (SUMA_ALL_DO *)EngineData->vp;
4666             if (NI_get_attribute(EngineData->ngr, "inout_notify")) {
4667                if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr, "inout_notify", "y"))
4668                   SUMA_setIO_notify(1);
4669                else if (NI_IS_STR_ATTR_EQUAL(EngineData->ngr,
4670                                              "inout_notify", "n"))
4671                   SUMA_setIO_notify(0);
4672                else {
4673                   SUMA_S_Errv("Bad value of %s for inout_notify, "
4674                               "setting to 'n'\n",
4675                               NI_get_attribute(EngineData->ngr, "inout_notify"));
4676                   SUMA_setIO_notify(0);
4677                }
4678 
4679             }
4680 
4681             if (NI_get_attribute(EngineData->ngr, "bkg_col")) {
4682                char *stmp = NULL;
4683                NI_GET_STR_CP(EngineData->ngr, "bkg_col", stmp);
4684                if (!stmp) {
4685                   SUMA_S_Err("Bad bkg_col");
4686                } else {
4687                   nn = SUMA_StringToNum(stmp, (void*)dv15, 4,4);
4688                   if (nn != 4) {
4689                      SUMA_S_Err("Bad bkg_col string.");
4690                   } else {
4691                      /* have bkg_col, set it please */
4692                      SUMA_LHv("Have bkg_col of %f, %f, %f, %f\n",
4693                               dv15[0], dv15[1], dv15[2], dv15[3]);
4694                      sv->clear_color[0] = dv15[0];
4695                      sv->clear_color[1] = dv15[1];
4696                      sv->clear_color[2] = dv15[2];
4697                      sv->clear_color[3] = dv15[3];
4698                      {
4699                         DList *llist = SUMA_CreateList();
4700                         SUMA_REGISTER_HEAD_COMMAND_NO_DATA(llist, SE_Redisplay,
4701                                                             SES_SumaFromAny, sv);
4702                         if (!SUMA_Engine (&llist)) {
4703                            fprintf( stderr,
4704                                     "Error %s: SUMA_Engine call failed.\n",
4705                                     FuncName);
4706                         }
4707                      }
4708                   }
4709                   SUMA_free(stmp); stmp = NULL;
4710                }
4711             }
4712             /* autorecord prefix? */
4713             if (NI_get_attribute(EngineData->ngr, "autorecord")) {
4714                if (SUMAg_CF->autorecord) SUMA_free(SUMAg_CF->autorecord);
4715                SUMAg_CF->autorecord = SUMA_SetAutoRecord(
4716                   NI_get_attribute(EngineData->ngr, "autorecord"));
4717             }
4718 
4719             /* search for the keys */
4720             if (NI_get_attribute(EngineData->ngr,"N_Key")) {
4721                char *stmp=NULL, nc, *vbuf=NULL, *strgval=NULL;
4722                int k, rep,  N_rep = 1, redisp=0;
4723                float pauz=0.0, delta_t=0.0;
4724                struct timeval tt;
4725                DList *llist = NULL;
4726                LocalHead = NOPE;
4727                NI_GET_INT(EngineData->ngr,"N_Key", itmp);
4728                for (ii=0; ii<itmp; ++ii) {
4729                   sprintf(tmpstr, "Key_%d", ii);
4730                   NI_GET_STR_CP(EngineData->ngr,tmpstr, stmp);
4731                   sprintf(tmpstr, "Key_rep_%d", ii);
4732                   NI_GET_INT(EngineData->ngr,tmpstr, N_rep);
4733                   sprintf(tmpstr, "Key_pause_%d", ii);
4734                   NI_GET_FLOAT(EngineData->ngr,tmpstr, pauz);
4735                   sprintf(tmpstr, "Key_redis_%d", ii);
4736                   NI_GET_INT(EngineData->ngr,tmpstr, redisp);
4737                   sprintf(tmpstr, "Key_strval_%d", ii);
4738                   strgval = NI_get_attribute(EngineData->ngr, tmpstr);
4739                   SUMA_LHv("Rep=%d, Pause=%f, Redis=%d\n, Strgval=%s",
4740                            N_rep, pauz, redisp, CHECK_NULL_STR(strgval));
4741                   if (stmp && (nc = strlen(stmp))) {
4742                      k = SUMA_KeyPress(stmp, NULL);
4743                      if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] =
4744                         toupper(stmp[strlen(stmp)-1]);
4745                      for (rep=0; rep<N_rep; ++rep) {
4746                         SUMA_LHv(".............rep %d\n", rep);
4747                         SUMA_etime(&tt, 0);
4748                         switch (k) {
4749                            case XK_bracketleft:
4750                               if (!SUMA_bracketleft_Key(sv, stmp, "drivesuma")) {
4751                                  SUMA_S_Err("Failed in Key function.");
4752                               }
4753                               break;
4754                            case XK_bracketright:
4755                               if (!SUMA_bracketright_Key(sv, stmp,"drivesuma")) {
4756                                  SUMA_S_Err("Failed in Key function.");
4757                               }
4758                               break;
4759                            case XK_0:
4760                            case XK_1:
4761                            case XK_2:
4762                            case XK_3:
4763                            case XK_4:
4764                            case XK_5:
4765                            case XK_6:
4766                            case XK_7:
4767                            case XK_8:
4768                            case XK_9:
4769                               // sprintf(stmp, "%d", k);   // DO NOT DELETE
4770                               if (!SUMA_Numeral_Key(sv, stmp, "drivesuma")) {
4771                                  SUMA_S_Err("Failed in Key function.");
4772                               }
4773                               break;
4774                            case XK_a:
4775                            case XK_A:
4776                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'A';
4777                               if (!SUMA_A_Key(sv, stmp, "drivesuma")) {
4778                                  SUMA_S_Err("Failed in Key function.");
4779                               }
4780                               break;
4781                            case XK_b:
4782                            case XK_B:
4783                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'B';
4784                               if (!SUMA_B_Key(sv, stmp, "drivesuma")) {
4785                                  SUMA_S_Err("Failed in Key function.");
4786                               }
4787                               break;
4788                            case XK_c:
4789                            case XK_C:
4790                               // // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'C';
4791                               if (!SUMA_C_Key(sv, stmp, "drivesuma")) {
4792                                  SUMA_S_Err("Failed in Key function.");
4793                               }
4794                               break;
4795                            case XK_d:
4796                            case XK_D:
4797                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'D';
4798                               if (!SUMA_D_Key(sv, stmp, "drivesuma")) {
4799                                  SUMA_S_Err("Failed in Key function.");
4800                               }
4801                               break;
4802                            case XK_f:
4803                            case XK_F:
4804                               if (!SUMA_F_Key(sv, stmp, "drivesuma")) {
4805                                  SUMA_S_Err("Failed in Key function.");
4806                               }
4807                               break;
4808                            case XK_g:
4809                            case XK_G:
4810                               if (!SUMA_G_Key(sv, stmp, "drivesuma")) {
4811                                  SUMA_S_Err("Failed in Key function.");
4812                               }
4813                               break;
4814                            case XK_h:
4815                            case XK_H:
4816                               if (!SUMA_H_Key(sv, stmp, "drivesuma")) {
4817                                  SUMA_S_Err("Failed in Key function.");
4818                               }
4819                               break;
4820                            case XK_j:
4821                            case XK_J:
4822                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'J';
4823                               if (!SUMA_J_Key(sv, stmp, "drivesuma", strgval)) {
4824                                  SUMA_S_Err("Failed in Key function.");
4825                               }
4826                               break;
4827                            case XK_l:
4828                            case XK_L:
4829                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'L';
4830                               if (!SUMA_L_Key(sv, stmp, "drivesuma", strgval)) {
4831                                  SUMA_S_Err("Failed in Key function.");
4832                               }
4833                               break;
4834                            case XK_m:
4835                            case XK_M:
4836                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'M';
4837                               if (!SUMA_M_Key(sv, stmp, "drivesuma")) {
4838                                  SUMA_S_Err("Failed in Key function.");
4839                               }
4840                               break;
4841                            case XK_n:
4842                            case XK_N:
4843                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'N';
4844                               if (!SUMA_N_Key(sv, stmp, "drivesuma")) {
4845                                  SUMA_S_Err("Failed in Key function.");
4846                               }
4847                               break;
4848                            case XK_o:
4849                            case XK_O:
4850                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'O';
4851                               if (!SUMA_O_Key(sv, stmp, "drivesuma")) {
4852                                  SUMA_S_Err("Failed in Key function.");
4853                               }
4854                               break;
4855                            case XK_p:
4856                            case XK_P:
4857                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'P';
4858                               if (!SUMA_P_Key(sv, stmp, "drivesuma")) {
4859                                  SUMA_S_Err("Failed in Key function.");
4860                               }
4861                               break;
4862                            case XK_r:
4863                            case XK_R:
4864                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'R';
4865                               if (!SUMA_R_Key(sv, stmp, "drivesuma")) {
4866                                  SUMA_S_Err("Failed in Key function.");
4867                               }
4868                               break;
4869                            case XK_s:
4870                            case XK_S:
4871                               if (!SUMA_S_Key(sv, stmp, "drivesuma")) {
4872                                  SUMA_S_Err("Failed in Key function.");
4873                               }
4874                               break;
4875                            case XK_t:
4876                            case XK_T:
4877                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'T';
4878                               if (!SUMA_T_Key(sv, stmp, "drivesuma")) {
4879                                  SUMA_S_Err("Failed in Key function.");
4880                               }
4881                               break;
4882                            case XK_u:
4883                            case XK_U:
4884                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'U';
4885                               if (!SUMA_U_Key(sv, stmp, "drivesuma")) {
4886                                  SUMA_S_Err("Failed in Key function.");
4887                               }
4888                               break;
4889                            case XK_w:
4890                            case XK_W:
4891                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'W';
4892                               if (!SUMA_W_Key(sv, stmp, "drivesuma")) {
4893                                  SUMA_S_Err("Failed in Key function.");
4894                               }
4895                               break;
4896                            case XK_z:
4897                            case XK_Z:
4898                               // if (strstr(stmp, "Shift")) stmp[strlen(stmp)-1] = 'Z';
4899                               if (!SUMA_Z_Key(sv, stmp, "drivesuma")) {
4900                                  SUMA_S_Err("Failed in Key function.");
4901                               }
4902                               break;
4903                            case XK_Up:
4904                               if (!SUMA_Up_Key(sv, stmp, "drivesuma")) {
4905                                  SUMA_S_Err("Failed in Key function.");
4906                               }
4907                               break;
4908                            case XK_Down:
4909                               if (!SUMA_Down_Key(sv, stmp, "drivesuma")) {
4910                                  SUMA_S_Err("Failed in Key function.");
4911                               }
4912                               break;
4913                            case XK_Left:
4914                               if (!SUMA_Left_Key(sv, stmp, "drivesuma")) {
4915                                  SUMA_S_Err("Failed in Key function.");
4916                               }
4917                               break;
4918                            case XK_Right:
4919                               if (!SUMA_Right_Key(sv, stmp, "drivesuma")) {
4920                                  SUMA_S_Err("Failed in Key function.");
4921                               }
4922                               break;
4923                            case XK_space:
4924                               if (!SUMA_space_Key(sv, stmp, "drivesuma")) {
4925                                  SUMA_S_Err("Failed in Key function.");
4926                               }
4927                               break;
4928                            case XK_slash:
4929                               if (!SUMA_slash_Key(sv, stmp, "drivesuma")) {
4930                                  SUMA_S_Err("Failed in Key function.");
4931                               }
4932                               break;
4933                            case XK_period:
4934                               if (!SUMA_period_Key(sv, stmp, "drivesuma")) {
4935                                  SUMA_S_Err("Failed in Key function.");
4936                               }
4937                               break;
4938                            case XK_comma:
4939                               if (!SUMA_comma_Key(sv, stmp, "drivesuma")) {
4940                                  SUMA_S_Err("Failed in Key function.");
4941                               }
4942                               break;
4943                            case XK_plus:
4944                               if (!SUMA_plus_Key(sv, stmp, "drivesuma")) {
4945                                  SUMA_S_Err("Failed in Key function.");
4946                               }
4947                               break;
4948                            case XK_minus:
4949                               if (!SUMA_minus_Key(sv, stmp, "drivesuma")) {
4950                                  SUMA_S_Err("Failed in Key function.");
4951                               }
4952                               break;
4953                            case XK_equal:
4954                               if (!SUMA_equal_Key(sv, stmp, "drivesuma")) {
4955                                  SUMA_S_Err("Failed in Key function.");
4956                               }
4957                               break;
4958                            case XK_F1:
4959                               if (!SUMA_F1_Key(sv, stmp, "drivesuma")) {
4960                                  SUMA_S_Err("Failed in Key function.");
4961                               }
4962                               break;
4963                            case XK_F2:
4964                               if (!SUMA_F2_Key(sv, stmp, "drivesuma")) {
4965                                  SUMA_S_Err("Failed in Key function.");
4966                               }
4967                               break;
4968                            case XK_F3:
4969                               if (!SUMA_F3_Key(sv, stmp, "drivesuma")) {
4970                                  SUMA_S_Err("Failed in Key function.");
4971                               }
4972                               break;
4973                            case XK_F4:
4974                               if (!SUMA_F4_Key(sv, stmp, "drivesuma")) {
4975                                  SUMA_S_Err("Failed in Key function.");
4976                               }
4977                               break;
4978                            case XK_F5:
4979                               if (!SUMA_F5_Key(sv, stmp, "drivesuma")) {
4980                                  SUMA_S_Err("Failed in Key function.");
4981                               }
4982                               break;
4983                            case XK_F6:
4984                               if (!SUMA_F6_Key(sv, stmp, "drivesuma")) {
4985                                  SUMA_S_Err("Failed in Key function.");
4986                               }
4987                               break;
4988                            case XK_F7:
4989                               if (!SUMA_F7_Key(sv, stmp, "drivesuma")) {
4990                                  SUMA_S_Err("Failed in Key function.");
4991                               }
4992                               break;
4993                            case XK_F8:
4994                               if (!SUMA_F8_Key(sv, stmp, "drivesuma")) {
4995                                  SUMA_S_Err("Failed in Key function.");
4996                               }
4997                               break;
4998                            case XK_F9:
4999                               if (!SUMA_F9_Key(sv, stmp, "drivesuma")) {
5000                                  SUMA_S_Err("Failed in Key function.");
5001                               }
5002                               break;
5003                            case XK_F10:
5004                               /* strgval can be used to set the value directly
5005                                  in the future. But it is not implemented
5006                                  in SUMA_F10_Key yet ... */
5007                               if (!SUMA_F10_Key(sv,stmp, "drivesuma", strgval)) {
5008                                  SUMA_S_Err("Failed in Key function.");
5009                               }
5010                               break;
5011                            case XK_F11:
5012                               if (!SUMA_F11_Key(sv, stmp,"drivesuma", strgval)) {
5013                                  SUMA_S_Err("Failed in Key function.");
5014                               }
5015                               break;
5016                            case XK_F12:
5017                               if (!SUMA_F12_Key(sv, stmp, "drivesuma")) {
5018                                  SUMA_S_Err("Failed in Key function.");
5019                               }
5020                               break;
5021                            case XK_VoidSymbol:
5022                               SUMA_S_Errv("No good key for %s\n", stmp);
5023                               break;
5024                            default:
5025                               SUMA_S_Errv("Don't know how to deal with %s "
5026                                           "in drive mode\n", stmp);
5027                               break;
5028                         } /* end switch k */
5029                         /* do we need a call for redisplay now? */
5030                         if ((redisp || pauz != 0.0f )) {
5031                            /* a redisplay is already pending
5032                            (from the key functions), kill it or it will get
5033                            executed later*/
5034                            SUMA_remove_workproc2(  SUMA_handleRedisplay,
5035                                                    sv->X->GLXAREA );
5036                            llist = SUMA_CreateList ();
5037                            SUMA_REGISTER_TAIL_COMMAND_NO_DATA(llist,
5038                                        SE_RedisplayNow, SES_SumaFromAny, sv);
5039                            SUMA_LH("Forcing redisplay");
5040                            SUMA_Engine (&llist);
5041                         }
5042 
5043                         /* check on delay */
5044                         if (pauz < 0) {
5045                            char buf[100];
5046                            sprintf( buf,
5047                                  "Pausing DriveSuma at Key %s, rep=%d, N_rep=%d",
5048                                  stmp, rep, N_rep);
5049                            SUMA_LH("Calling user pause...");
5050                            #if 1
5051                               SUMA_PauseForUser(sv->X->TOPLEVEL, buf,
5052                                                 SWP_POINTER_OFF, NULL, 0, -1.0);
5053                            #else /* kept here to illustrate bug */
5054          /* very slow when called repeatedly except when you open the
5055          'Close All Viewers' thing by hand with SHFTESC then press No.
5056          In that case, repeated calls to SUMA_ForceUser_YesNo are quite fast.
5057          The problem in the XtManage call once the dialog is created. It takes
5058          forever to return. One solution, implemented in PauseForUser, is
5059          to destroy the widget each time and recreate it anew. Not a big deal.*/
5060                               SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
5061                                                    "Close All Viewers?",
5062                                                    SUMA_YES, SWP_DONT_CARE);
5063                            #endif
5064                         } else if (pauz > 0.0f) {
5065                            SUMA_LHv("Sleeping for %dms\n",
5066                                     (int) ((pauz-delta_t)*1000));
5067                            delta_t = SUMA_etime(&tt, 1);
5068                            if (delta_t < pauz) {
5069                               NI_sleep((int) ((pauz-delta_t)*1000));
5070                            }
5071                         }
5072                      } /* end of rep */
5073                      SUMA_free(stmp); stmp = NULL;
5074                   }  /* end have iith key */
5075                }  /* end loop all keys */
5076             }
5077             break;
5078 
5079          case SE_SetRecorderCont:
5080             /* expects a ngr */
5081             if (EngineData->ngr_Dest != NextComCode ) {
5082                fprintf (SUMA_STDERR,
5083                         "Error %s: Data not destined correctly for %s (%d).\n"
5084                         "Have %d \n",
5085                         FuncName, NextCom, NextComCode, EngineData->ngr_Dest);
5086                break;
5087             }
5088             {
5089                char *stmp=NULL, *sname=NULL;
5090                int ifrom = -1, ito = -1, NoTsEt = -999999;
5091                if (NI_get_attribute(EngineData->ngr, "Anim_Dup")) {
5092                   NI_GET_INT(EngineData->ngr,"Anim_Dup", itmp);
5093                   if (!NI_GOT || itmp < 0) {
5094                      itmp = 0;
5095                   }
5096                   SUMA_LHv("Going for %d\n", itmp);
5097                   ISQ_set_anim_dup(itmp);
5098                }
5099                if (NI_get_attribute(EngineData->ngr, "Save_As")) {
5100 
5101                   #if 1
5102                   ifrom = ito = NoTsEt;
5103                   NI_GET_INT(EngineData->ngr, "Save_From", itmp);
5104                   if (!NI_GOT) {
5105                      itmp = -1;
5106                   } else {
5107                      ifrom = itmp;
5108                   }
5109                   NI_GET_INT(EngineData->ngr, "Save_To", itmp);
5110                   if (!NI_GOT) {
5111                      itmp = -1;
5112                   }else {
5113                      ito = itmp;
5114                   }
5115 
5116                   NI_GET_STR_CP(EngineData->ngr, "Save_As", stmp);
5117                   if (!stmp) {
5118                      SUMA_S_Err("Empty Save_As");
5119                      goto CLEAN_RECORDER_CONT;
5120                   }
5121                   fn = SUMA_ParseFname(stmp,
5122                                        NI_get_attribute(EngineData->ngr,
5123                                        "Caller_Working_Dir"));
5124                   if (!(sname = SUMA_copy_string(fn->FileName_NoExt))) {
5125                      sname = SUMA_copy_string("no_name");
5126                   }
5127                   sname = SUMA_append_replace_string(fn->AbsPath, sname, "", 2);
5128                   if (ito == NoTsEt && ifrom == NoTsEt) {
5129                      if (SUMA_IMG_EXT(fn->Ext)) {
5130                         ifrom = -1; ito = 0;/* nothing set, save last one */
5131                      } else if (SUMA_ANIM_EXT(fn->Ext)) {
5132                         ifrom = 0; ito = 0;
5133                            /* nothing set, save all in animation */
5134                      } else {
5135                         SUMA_S_Errv("No support for extension %s\n", fn->Ext);
5136                         goto CLEAN_RECORDER_CONT;
5137                      }
5138                   }
5139                   if (ito == NoTsEt || ifrom == NoTsEt) {
5140                      SUMA_S_Errv("Erreur! Horreur! ito=%d, ifrom=%d"
5141                                  " (NotSet=%d)\n", ito, ifrom , NoTsEt);
5142                      goto CLEAN_RECORDER_CONT;
5143                   }
5144                   #else
5145                   NI_GET_INT(EngineData->ngr, "Save_One", itmp);
5146                   if (NI_GOT) {
5147                      if (itmp == -1) { ifrom = -1; ito = 0; }
5148                      else if (itmp >= 0) { ifrom = itmp; ito = ifrom; }
5149                      else {
5150                         SUMA_S_Errv("Bad value for -save_one (%d)\n", itmp);
5151                         break;
5152                      }
5153                   }
5154 
5155                   NI_GET_STR_CP(EngineData->ngr, "Save_As", stmp);
5156                   if (!stmp) {
5157                      SUMA_S_Err("Empty Save_As");
5158                      goto CLEAN_RECORDER_CONT;
5159                   }
5160                   fn = SUMA_ParseFname(stmp,
5161                                        NI_get_attribute( EngineData->ngr,
5162                                                          "Caller_Working_Dir"));
5163                   if (!(sname = SUMA_copy_string(fn->FileName_NoExt))) {
5164                      sname = SUMA_copy_string("no_name");
5165                   }
5166                   sname = SUMA_append_replace_string(fn->AbsPath, sname, "", 2);
5167 
5168                   /* more checking */
5169                   if (ito < 0 && ifrom < 0) {
5170                      if (SUMA_IMG_EXT(fn->Ext)) {
5171                         ifrom = -1; ito = 0;/* nothing set, save last one */
5172                      } else if (SUMA_ANIM_EXT(fn->Ext)) {
5173                         ifrom = 0; ito = 0;/* nothing set, save all in animation */
5174                      } else {
5175                         SUMA_S_Errv("No support for extension %s\n", fn->Ext);
5176                         goto CLEAN_RECORDER_CONT;
5177                      }
5178                   }
5179                   #endif
5180                   if (ifrom > ito && ito > 0) {
5181                      /* note that negative indices are OK, see ISQ_save_anim */
5182                      SUMA_S_Errv("Error: ifrom=%d > ito=%d\n", ifrom, ito);
5183                      goto CLEAN_RECORDER_CONT;
5184                   }
5185                   if (  SUMA_iswordsame_ci(fn->Ext,".agif") ||
5186                         SUMA_iswordsame_ci(fn->Ext,".gif")) {
5187                      ISQ_snap_agif_rng(sname, ifrom, ito);
5188                   } else if ( SUMA_iswordsame_ci(fn->Ext,".mpeg") ||
5189                               SUMA_iswordsame_ci(fn->Ext,".mpg")) {
5190                      ISQ_snap_mpeg_rng(sname, ifrom, ito);
5191                   } else if ( SUMA_iswordsame_ci(fn->Ext,".jpeg") ||
5192                               SUMA_iswordsame_ci(fn->Ext,".jpg")) {
5193                      ISQ_snap_jpeg_rng(sname, ifrom, ito);
5194                   } else if (SUMA_iswordsame_ci(fn->Ext,".png") ) {
5195                      ISQ_snap_png_rng(sname, ifrom, ito);
5196                   } else {
5197                      SUMA_S_Errv("Not ready to deal with format %s\n", tmpstr);
5198                      goto CLEAN_RECORDER_CONT;
5199                   }
5200                }
5201                CLEAN_RECORDER_CONT:
5202                if (stmp) SUMA_free(stmp); stmp = NULL;
5203                if (sname) SUMA_free(sname); sname = NULL;
5204                if (fn) fn = SUMA_Free_Parsed_Name(fn);
5205             }
5206             break;
5207          /*case SE_Something:
5208             break;*/
5209 
5210          case SE_BadCode:
5211             fprintf(SUMA_STDERR,"Error SUMA_Engine: Command ->%s<- Not understood. Perhaps Code is not defined in SUMA_CommandCode\n", NextCom);
5212             break;
5213 
5214       } /* switch NextComCode */
5215 
5216       /* release used Element */
5217       if (LocalHead) fprintf (SUMA_STDERR, "\n%s: Releasing Engine Element.\n", FuncName);
5218       if (!SUMA_ReleaseEngineListElement (list, NextElem_CANT_TOUCH_THIS)) {
5219             fprintf(SUMA_STDERR,"Error SUMA_Engine: Failed to Release element \n");
5220          }
5221 
5222    } /* cycle through NextCom */
5223 
5224    if (LocalHead) fprintf (SUMA_STDERR, "\n%s: Destroying List.\n", FuncName);
5225    /* If you get here, all is well, destroy the list since it is empty*/
5226    list = SUMA_DestroyList (list);
5227    *listp = NULL;
5228 
5229    SUMA_RETURN (YUP);
5230 }
5231 
SUMA_nimlEngine2Engine(NI_group * ngr)5232 void *SUMA_nimlEngine2Engine(NI_group *ngr)
5233 {
5234    static char FuncName[]={"SUMA_nimlEngine2Engine"};
5235    DList *list = NULL;
5236    int  isv, itmp;
5237    SUMA_NI_COMMAND_CODE cc;
5238    SUMA_EngineData *ED = NULL;
5239    DListElmt *el=NULL;
5240    void *Ret = NULL;
5241    char *adoid=NULL, *svid=NULL, *name=NULL, *adolabel=NULL,
5242         ename[32], lhs[64], rhs[256], *enveqn=NULL, *attr=NULL;
5243    SUMA_ALL_DO *ado = NULL;
5244    SUMA_SurfaceViewer *sv = NULL;
5245    SUMA_X_SurfCont *SurfCont=NULL;
5246    SUMA_PARSED_NAME *fn = NULL;
5247    SUMA_Boolean LocalHead = NOPE;
5248 
5249    SUMA_ENTRY;
5250 
5251    if (!ngr) { SUMA_S_Err("NULL input"); SUMA_RETURN(Ret); }
5252    if (LocalHead) SUMA_ShowNel(ngr);
5253    if (strcmp(ngr->name, "EngineCommand")) {
5254       fprintf (SUMA_STDERR,
5255                "Error %s: group name (%s) is not (EngineCommand)\n",
5256                FuncName, ngr->name);
5257       SUMA_RETURN(Ret);
5258    }
5259 
5260    /* Is this a valid command? */
5261    cc = SUMA_niCommandCode(NI_get_attribute(ngr,"Command"));
5262    if (cc == SE_Empty || cc == SE_BadCode) {
5263       SUMA_S_Errv("Bad command code %s",
5264                   SUMA_CHECK_NULL_STR(NI_get_attribute(ngr,"Command")));
5265       SUMA_RETURN(Ret);
5266    }
5267 
5268    /* do we have the classics? */
5269    itmp = 0;
5270    sprintf(ename,"ENV.%d", itmp);
5271    while ((attr=NI_get_attribute(ngr, ename))) {
5272       SUMA_LHv("Have %s:>%s<\n", ename, attr);
5273       lhs[0] = '\0'; rhs[0]='\0';
5274       if (SUMA_ParseLHS_RHS (attr, lhs, rhs)) {
5275          enveqn = (char *) malloc(strlen(lhs)+strlen(rhs)+4) ;
5276          sprintf(enveqn,"%s=%s", lhs, rhs);
5277          putenv(enveqn);
5278          SUMA_LHv("Got %s\n", enveqn);
5279       } else {
5280          SUMA_S_Errv("Failed to parse %s: %s\n",
5281                ename, attr);
5282       }
5283       sprintf(ename,"ENV.%d", ++itmp);
5284    }
5285 
5286    sv = NULL;
5287    svid = NI_get_attribute(ngr,"SV_id");
5288    if (svid) {
5289       isv = SUMA_TO_LOWER_C(svid[0])-'a';
5290       if (isv < 0 || isv > SUMAg_N_SVv) {
5291          /* try in case it was an int */
5292          isv = atoi(svid);
5293       }
5294       if (isv < 0 || isv > SUMAg_N_SVv) {
5295          SUMA_S_Errv("Bad SV_id of %s\n", svid);
5296          SUMA_RETURN(Ret);
5297       }
5298       sv = &(SUMAg_SVv[isv]);
5299       if (!sv->X->TOPLEVEL) {
5300          SUMA_S_Errv("Viewer %s must first be created "
5301                      "with a separate -com command.\n", svid);
5302          SUMA_RETURN(Ret);
5303       }
5304    }
5305    if (!sv) {
5306       sv = &(SUMAg_SVv[0]);
5307    }
5308    SUMA_LH("Viewer id %s, isv=%d sv=%p",svid?svid:"NULL", isv, sv);
5309 
5310    ado = NULL;
5311    if (!(adoid = NI_get_attribute(ngr,"SO_idcode")) &&
5312        !(adoid = NI_get_attribute(ngr,"DO_idcode")))
5313       adoid = NI_get_attribute(ngr,"ADO_idcode");
5314 
5315    if (adoid) {
5316       ado = SUMA_whichADO(adoid, SUMAg_DOv, SUMAg_N_DOv);
5317       if (!ado) {
5318          SUMA_S_Errv("DO with id %s not found.\n", adoid);
5319          SUMA_RETURN(Ret);
5320       }
5321    }
5322    if (!(adolabel = NI_get_attribute(ngr,"SO_label")) &&
5323        !(adolabel = NI_get_attribute(ngr,"DO_label")))
5324       adolabel = NI_get_attribute(ngr,"ADO_label");;
5325    if (adolabel) {
5326       if (ado && strcmp(adolabel, ADO_LABEL(ado))) {
5327          SUMA_S_Errv("Conflict between id %s (%s) and label (%s)",
5328                      ADO_ID(ado), ADO_LABEL(ado), adolabel);
5329          SUMA_RETURN(Ret);
5330       }
5331       if (!ado) { /* find ado based on label! */
5332          if ((adoid = SUMA_find_ADOidcode_from_label(adolabel,
5333                                           SUMAg_DOv, SUMAg_N_DOv))) {
5334             ado = SUMA_whichADO(adoid, SUMAg_DOv, SUMAg_N_DOv);
5335             if (!ado) {
5336                SUMA_S_Errv("ADO with id %s not found.\n", adoid);
5337                SUMA_RETURN(Ret);
5338             }
5339          }else {
5340             SUMA_S_Errv("ADO id from label %s not found.\n", adolabel);
5341             SUMA_RETURN(Ret);
5342          }
5343       }
5344    }
5345    if (!ado) ado = SUMA_SV_Focus_ADO(sv);
5346    if (!ado) {
5347       ado = SUMA_findanyFocusable_ADO(NULL);/* last resort */
5348    }
5349    if (!ado) {
5350       SUMA_S_Err("Have no ADOs to work with at all.\n");
5351       SUMA_RETURN(Ret);
5352    } else {
5353       if (LocalHead) {
5354          SUMA_LHv("Have ADO %s to work with\n", ADO_LABEL(ado));
5355       }
5356    }
5357    /* Create da list */
5358    if (!list) list = SUMA_CreateList ();
5359 
5360 
5361 
5362    SurfCont = SUMA_ADO_Cont(ado);
5363    /* OK, now, switch on that command and create the Engine structure */
5364    switch (cc) {
5365        case SE_niSetObjectCont:
5366        case SE_niSetSurfCont:
5367          if (!SurfCont) {
5368             SUMA_S_Err( "Unexpected NULL SurfCont\n"
5369                         "Please report error to author.");
5370             SUMA_RETURN(Ret);
5371          }
5372          if (!SUMA_isADO_Cont_Realized(ado)){
5373                                        /* better have a controller
5374                                                 before going crazy */
5375             if (0) { /* this option or the next behave in the same way */
5376                if (!SUMA_viewSurfaceCont(NULL, ado, sv)) {
5377                         SUMA_S_Err("Failed open surfcont");
5378                         break;
5379                }
5380             } else {
5381                ED = SUMA_InitializeEngineListData (SE_OpenSurfCont);
5382                if (!SUMA_RegisterEngineListCommand (
5383                            list, ED,
5384                            SEF_vp, (void *)ado,
5385                            SES_SumaFromAny, (void *)sv,
5386                            NOPE,
5387                            SEI_Head, NULL)) {
5388                   fprintf (SUMA_STDERR,
5389                            "Error %s: Failed to register command.\n", FuncName);
5390                }
5391             }
5392 
5393             /* make sure that business is closed if user does not control it */
5394             /* IF you close the window quickly, the colormap does not render
5395             and you can get into trouble then, this also happens if
5396             Drive SUMA orders an immediate surface controller closing after
5397             a dset load ... */
5398 
5399             if (!NI_get_attribute(ngr, "View_Surf_Cont"))
5400                NI_set_attribute(ngr, "View_Surf_Cont", "n");
5401          }
5402 
5403          if ((name = NI_get_attribute(ngr,"Dset_FileName"))) {
5404             /* Have a dset to load */
5405             ED = SUMA_InitializeEngineListData (SE_OpenDsetFile);
5406             if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
5407                                                       SEF_vp, (void *)ado,
5408                                                       SES_SumaFromAny,
5409                                                       (void *)sv, NOPE,
5410                                                       SEI_Tail, NULL))) {
5411                   fprintf (SUMA_STDERR,
5412                            "Error %s: Failed to register command.\n", FuncName);
5413             }
5414             if (!SUMA_RegisterEngineListCommand (  list, ED,
5415                                                       SEF_cp, (void *)name,
5416                                                       SES_SumaFromAny,
5417                                                       (void *)sv, NOPE,
5418                                                       SEI_In, el)) {
5419                   fprintf (SUMA_STDERR,
5420                            "Error %s: Failed to register command.\n", FuncName);
5421             }
5422          }
5423 
5424          if ((name = NI_get_attribute(ngr,"Mask_FileName"))) {
5425             /* Have a Mask to load */
5426             ED = SUMA_InitializeEngineListData (SE_OpenMaskFile);
5427             if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
5428                                                       SEF_vp, (void *)ado,
5429                                                       SES_SumaFromAny,
5430                                                       (void *)sv, NOPE,
5431                                                       SEI_Tail, NULL))) {
5432                   fprintf (SUMA_STDERR,
5433                            "Error %s: Failed to register command.\n", FuncName);
5434             }
5435             if (!SUMA_RegisterEngineListCommand (  list, ED,
5436                                                       SEF_cp, (void *)name,
5437                                                       SES_SumaFromAny,
5438                                                       (void *)sv, NOPE,
5439                                                       SEI_In, el)) {
5440                   fprintf (SUMA_STDERR,
5441                            "Error %s: Failed to register command.\n", FuncName);
5442             }
5443          }
5444 
5445          if ((name = NI_get_attribute(ngr,"Col_FileName"))) {
5446             /* Have a color file to load */
5447             ED = SUMA_InitializeEngineListData (SE_OpenColFile);
5448             if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
5449                                                       SEF_vp, (void *)ado,
5450                                                       SES_SumaFromAny,
5451                                                       (void *)sv, NOPE,
5452                                                       SEI_Tail, NULL))) {
5453                   fprintf (SUMA_STDERR,
5454                            "Error %s: Failed to register command.\n", FuncName);
5455             }
5456             if (!SUMA_RegisterEngineListCommand (  list, ED,
5457                                                       SEF_cp, (void *)name,
5458                                                       SES_SumaFromAny,
5459                                                       (void *)sv, NOPE,
5460                                                       SEI_In, el)) {
5461                   fprintf (SUMA_STDERR,
5462                            "Error %s: Failed to register command.\n", FuncName);
5463             }
5464          }
5465          /* all the rest can be handled in one engine call */
5466          ED = SUMA_InitializeEngineListData (SE_SetSurfCont);
5467          if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
5468                                                    SEF_ngr, (void *)ngr,
5469                                                    SES_SumaFromAny, (void *)sv,
5470                                                    NOPE,
5471                                                    SEI_Tail, NULL))) {
5472                fprintf (SUMA_STDERR,
5473                         "Error %s: Failed to register command.\n", FuncName);
5474          }
5475          if (!SUMA_RegisterEngineListCommand (  list, ED,
5476                                                    SEF_vp, (void *)ado,
5477                                                    SES_SumaFromAny, (void *)sv,
5478                                                    NOPE,
5479                                                    SEI_In, el)) {
5480                fprintf (SUMA_STDERR,
5481                         "Error %s: Failed to register command.\n", FuncName);
5482          }
5483          break;
5484       case SE_niSetViewerCont:
5485          if ((name = NI_get_attribute(ngr,"N_foreg_smooth"))) {
5486             SUMA_SetNumForeSmoothing(name, (void *)sv);
5487          }
5488          if ((name = NI_get_attribute(ngr,"N_final_smooth"))) {
5489             SUMA_SetNumFinalSmoothing(name, (void *)sv);
5490          }
5491          if ((name = NI_get_attribute(ngr,"VVS_FileName"))) {
5492             /* Have a vvs to load, do it straight up,
5493                no need to call some SE_SetViewerCont, a la SE_SetSurfCont yet */
5494             if ((fn = SUMA_ParseFname(name,
5495                                  NI_get_attribute(ngr,
5496                                        "Caller_Working_Dir")))) {
5497                SUMA_LoadVisualState(fn->FullName, (void *)sv);
5498             }
5499             if (fn) fn = SUMA_Free_Parsed_Name(fn);
5500          }
5501          if ((name = NI_get_attribute(ngr,"DO_FileName"))) {
5502             /* Have a DO to load, straight up too*/
5503             if ((fn = SUMA_ParseFname(name,
5504                                  NI_get_attribute(ngr,
5505                                        "Caller_Working_Dir")))) {
5506                SUMA_LoadSegDO(fn->FullName, (void *)sv);
5507             }
5508             if (fn) fn = SUMA_Free_Parsed_Name(fn);
5509          }
5510          if ((name = NI_get_attribute(ngr,"DoViewerSetup"))) {
5511             /* have something to do with viewer setup */
5512             if (!SUMA_ApplyVisualState((NI_element *)ngr, sv)) {
5513                SUMA_S_Err("Failed to apply state");
5514                SUMA_RETURN(Ret);
5515             }
5516          }
5517          /* all the rest can be handled in one engine call */
5518          ED = SUMA_InitializeEngineListData (SE_SetViewerCont);
5519          if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
5520                                                    SEF_ngr, (void *)ngr,
5521                                                    SES_SumaFromAny, (void *)sv,
5522                                                    NOPE,
5523                                                    SEI_Tail, NULL))) {
5524                fprintf (SUMA_STDERR,
5525                         "Error %s: Failed to register command.\n", FuncName);
5526          }
5527          if (!SUMA_RegisterEngineListCommand (  list, ED,
5528                                                    SEF_vp, (void *)ado,
5529                                                    SES_SumaFromAny, (void *)sv,
5530                                                    NOPE,
5531                                                    SEI_In, el)) {
5532                fprintf (SUMA_STDERR,
5533                         "Error %s: Failed to register command.\n", FuncName);
5534          }
5535          break;
5536       case SE_niSetRecorderCont:
5537          ED = SUMA_InitializeEngineListData (SE_SetRecorderCont);
5538          if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
5539                                                    SEF_ngr, (void *)ngr,
5540                                                    SES_SumaFromAny, (void *)sv,
5541                                                    NOPE,
5542                                                    SEI_Tail, NULL))) {
5543                fprintf (SUMA_STDERR,
5544                         "Error %s: Failed to register command.\n", FuncName);
5545          }
5546 
5547          break;
5548       case SE_niKillSuma:
5549          XtCloseDisplay( SUMAg_CF->X->DPY_controller1 ) ;
5550          selenium_close();/* close selenium opened browser windows if open */
5551          exit(0);
5552          break;
5553       case SE_GetLabel:
5554            {
5555                /* show the current surface label */
5556                SUMA_SurfaceObject *SO=NULL;
5557                char *lbls;
5558 //              lbls = ADO_LABEL(ado);
5559                SO = (SUMA_SurfaceObject *)ado;
5560                lbls = SUMA_GetLabelsAtSelection(ado,
5561                       SO->SelectedNode, -1);
5562                sumaout = SUMA_drive_get_outstream();
5563                fprintf(sumaout,"%s\n",lbls);
5564                fflush(sumaout);
5565             }
5566             break;
5567 
5568       default:
5569          SUMA_S_Errv("Cannot deal with command %s yet.\n",
5570                      NI_get_attribute(ngr,"command"));
5571          SUMA_RETURN(Ret);
5572          break;
5573 
5574    }
5575 
5576    if (!SUMA_Engine(&list)) {
5577       SUMA_SLP_Err("Failed to execute command.");
5578       SUMA_RETURN(Ret);
5579    }
5580 
5581 
5582    SUMA_RETURN(Ret);
5583 }
5584 
5585 /*!
5586    ans = SUMA_RegisteredSOs (sv, dov, SO_IDs);
5587    gets the IDs (indices into dov) and number of the Surface Objects shown in sv
5588    \param sv (SUMA_SurfaceViewer *) the surface viewer structure
5589    \param dov (SUMA_DO *) the Displayable Objects vector (accessible to sv)
5590    \param SO_IDs (int *) pre-allocated integer vector that will contain the IDs of the SO shown in sv
5591          send NULL if you do not care for it and all you'll get is ans
5592    \ret ans (int) the number of SOs shown in SV
5593    Still confused ? read the code for the function, it is shorter than the documentation.
5594 */
SUMA_RegisteredSOs(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int * SO_IDs)5595 int SUMA_RegisteredSOs (SUMA_SurfaceViewer *sv, SUMA_DO *dov, int *SO_IDs)
5596 {
5597    static char FuncName[]={"SUMA_RegisteredSOs"};
5598    int i, k = 0;
5599 
5600    SUMA_ENTRY;
5601 
5602    for (i=0; i< sv->N_DO; ++i) {
5603       if (SUMA_isSO_G(dov[sv->RegistDO[i].dov_ind], sv->CurGroupName)) {
5604          if (SO_IDs != NULL) SO_IDs[k] = sv->RegistDO[i].dov_ind;
5605          ++k;
5606       }
5607    }
5608 
5609    SUMA_RETURN (k);
5610 }
5611 /*!
5612    ans = SUMA_VisibleSOs (sv, dov, SO_IDs);
5613    gets the IDs (indices into dov) and number of the Surface Objects
5614          registered with sv and with the SO->Side matching sv->ShowRight/
5615          sv->ShowLeft and with SO->Show set to YUP
5616    \param sv (SUMA_SurfaceViewer *) the surface viewer structure
5617    \param dov (SUMA_DO *) the Displayable Objects vector (accessible to sv)
5618    \param SO_IDs (int *) pre-allocated integer vector that will contain the
5619          IDs of the SO shown in sv
5620          send NULL if you do not care for it and all you'll get is ans
5621    \param forpicking (int) 1 --> surface rendered as points will be
5622                                  considered invisible
5623 
5624    \ret ans (int) the number of SOs shown in SV
5625    Still confused ? read the code for the function, it is shorter
5626    than the documentation.
5627 
5628    \sa SUMA_isVisibleSO, SUMA_Selectable_ADOs
5629 */
5630 
SUMA_VisibleSOs(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int * SO_IDs,int forpicking)5631 int SUMA_VisibleSOs (SUMA_SurfaceViewer *sv, SUMA_DO *dov, int *SO_IDs,
5632                      int forpicking)
5633 {
5634    static char FuncName[]={"SUMA_VisibleSOs"};
5635    SUMA_SurfaceObject *SO=NULL;
5636    int i, k = 0;
5637    SUMA_Boolean LocalHead = NOPE;
5638 
5639    SUMA_ENTRY;
5640 
5641    for (i=0; i< sv->N_DO; ++i) {
5642       if (SUMA_isSO_G(dov[sv->RegistDO[i].dov_ind], sv->CurGroupName)) {
5643          SO = (SUMA_SurfaceObject *)dov[sv->RegistDO[i].dov_ind].OP;
5644          if (SO_SHOWING(SO, sv) && (!forpicking || SO->PolyMode != SRM_Points)) {
5645             if (  SO->Side == SUMA_NO_SIDE ||
5646                   SO->Side == SUMA_SIDE_ERROR  ||
5647                   SO->Side == SUMA_LR) {
5648                if (SO_IDs) {
5649                   SO_IDs[k] = sv->RegistDO[i].dov_ind;
5650                }
5651                ++k;
5652             } else if (  (SO->Side == SUMA_RIGHT && sv->ShowRight) ||
5653                          (SO->Side == SUMA_LEFT && sv->ShowLeft) ) {
5654                if (SO_IDs) {
5655                   SO_IDs[k] = sv->RegistDO[i].dov_ind;
5656                }
5657                ++k;
5658             }
5659          }
5660       } else {
5661       	 switch (dov[sv->RegistDO[i].dov_ind].ObjectType) {
5662 	    case CDOM_type:
5663 	       SUMA_LH("So how do we handle the visibility of surfaces "
5664 	               "within a CIFTI object? Is this the place for it?");
5665 	       break;
5666 	 }
5667       }
5668    }
5669 
5670    SUMA_RETURN (k);
5671 }
5672 
SUMA_VisibleMDOs(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int * MDO_IDs)5673 int SUMA_VisibleMDOs (SUMA_SurfaceViewer *sv, SUMA_DO *dov, int *MDO_IDs)
5674 {
5675    static char FuncName[]={"SUMA_VisibleMDOs"};
5676    SUMA_MaskDO *MDO=NULL;
5677    int i, k = 0;
5678    SUMA_Boolean LocalHead = NOPE;
5679 
5680    SUMA_ENTRY;
5681 
5682    for (i=0; i< sv->N_DO; ++i) {
5683       if (dov[sv->RegistDO[i].dov_ind].ObjectType != MASK_type) continue;
5684       MDO = (SUMA_MaskDO *)dov[sv->RegistDO[i].dov_ind].OP;
5685       if (!MDO_IS_SHADOW(MDO) && MDO_SHOWING(MDO, sv)) {
5686          if (  MDO->SO->Side == SUMA_NO_SIDE ||
5687                MDO->SO->Side == SUMA_SIDE_ERROR  ||
5688                MDO->SO->Side == SUMA_LR) {
5689             if (MDO_IDs) {
5690                MDO_IDs[k] = sv->RegistDO[i].dov_ind;
5691             }
5692             ++k;
5693          } else if (  (MDO->SO->Side == SUMA_RIGHT && sv->ShowRight) ||
5694                       (MDO->SO->Side == SUMA_LEFT && sv->ShowLeft) ) {
5695             if (MDO_IDs) {
5696                MDO_IDs[k] = sv->RegistDO[i].dov_ind;
5697             }
5698             ++k;
5699          }
5700       }
5701    }
5702 
5703    SUMA_RETURN (k);
5704 }
5705 
5706 /*
5707    Is this the kind of DO that can be selected in SUMA
5708    In other terms, can it be loaded and viewed with nothing
5709    else?
5710 */
SUMA_is_iDO_Selectable(int dov_id)5711 int SUMA_is_iDO_Selectable(int dov_id)
5712 {
5713    static char FuncName[]={"SUMA_is_iDO_Selectable"};
5714 
5715    switch (iDO_type(dov_id)){
5716       case SO_type:
5717       case TRACT_type:
5718       case GRAPH_LINK_type:
5719       case MASK_type:
5720       case VO_type:
5721       case CDOM_type:
5722          return(1);
5723       default:
5724          return(0);
5725    }
5726 }
5727 
SUMA_Selectable_ADOs(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int * SO_IDs)5728 int SUMA_Selectable_ADOs (SUMA_SurfaceViewer *sv, SUMA_DO *dov, int *SO_IDs)
5729 {
5730    static char FuncName[]={"SUMA_Selectable_ADOs"};
5731    SUMA_SurfaceObject *SO=NULL;
5732    int i, k = 0;
5733    SUMA_NIDO *SDO=NULL;
5734    SUMA_Boolean LocalHead = NOPE;
5735 
5736    SUMA_ENTRY;
5737 
5738    for (i=0; i< sv->N_DO; ++i) {
5739       SUMA_LHv("Checking on %s\n", iDO_label(sv->RegistDO[i].dov_ind));
5740       if (SUMA_isSO_G(dov[sv->RegistDO[i].dov_ind], sv->CurGroupName)) {
5741          SO = (SUMA_SurfaceObject *)dov[sv->RegistDO[i].dov_ind].OP;
5742          if (SO_SHOWING(SO, sv)) {
5743             if (  SO->Side == SUMA_NO_SIDE ||
5744                   SO->Side == SUMA_SIDE_ERROR  ||
5745                   SO->Side == SUMA_LR) {
5746                if (SO_IDs) {
5747                   SO_IDs[k] = sv->RegistDO[i].dov_ind;
5748                }
5749                ++k;
5750             } else if (  (SO->Side == SUMA_RIGHT && sv->ShowRight) ||
5751                          (SO->Side == SUMA_LEFT && sv->ShowLeft) ) {
5752                if (SO_IDs) {
5753                   SO_IDs[k] = sv->RegistDO[i].dov_ind;
5754                }
5755                ++k;
5756             }
5757          }
5758       } else {
5759          switch (dov[sv->RegistDO[i].dov_ind].ObjectType) {
5760             case SO_type:
5761                /* ignore, escaped from above isSO_G */
5762                break;
5763             case GRAPH_LINK_type:
5764                /* avoid the shadow ... */
5765                if (!SUMA_IS_GOOD_STATE(
5766                      iDO_state(sv->RegistDO[i].dov_ind))) break;
5767                /* OK, keep */
5768                if (SO_IDs) {
5769                   SO_IDs[k] = sv->RegistDO[i].dov_ind;
5770                }
5771                ++k;
5772                break;
5773             case TRACT_type:
5774             case MASK_type:
5775             case CDOM_type:
5776             case VO_type:
5777                if (SO_IDs) {
5778                   SO_IDs[k] = sv->RegistDO[i].dov_ind;
5779                }
5780                ++k;
5781                break;
5782 	    default:
5783                SUMA_LHv("Ignoring %s\n", iDO_label(sv->RegistDO[i].dov_ind));
5784                break;
5785          }
5786       }
5787    }
5788 
5789    SUMA_RETURN (k);
5790 }
5791 
SUMA_ADOs_WithSurfCont(SUMA_DO * dov,int N_dov,int * dov_IDs)5792 int SUMA_ADOs_WithSurfCont (SUMA_DO *dov, int N_dov, int *dov_IDs)
5793 {
5794    static char FuncName[]={"SUMA_ADOs_WithSurfCont"};
5795    SUMA_SurfaceObject *SO=NULL;
5796    int i, k = 0;
5797    SUMA_NIDO *SDO=NULL;
5798    SUMA_Boolean LocalHead = NOPE;
5799 
5800    SUMA_ENTRY;
5801 
5802    for (i=0; i< N_dov; ++i) {
5803       if (SUMA_ADO_Cont((SUMA_ALL_DO*)SUMAg_DOv[i].OP)) {
5804                   dov_IDs[k] = i;
5805                ++k;
5806       }
5807    }
5808 
5809    SUMA_RETURN (k);
5810 }
5811 
5812 
5813 /*!
5814    \brief YUP if surface is visible in a viewer
5815    \sa SUMA_VisibleSOs
5816 */
SUMA_isVisibleDO(SUMA_SurfaceViewer * sv,SUMA_DO * dov,SUMA_ALL_DO * ado)5817 SUMA_Boolean SUMA_isVisibleDO (SUMA_SurfaceViewer *sv,
5818                                SUMA_DO *dov, SUMA_ALL_DO *ado)
5819 {
5820    static char FuncName[]={"SUMA_isVisibleDO"};
5821    SUMA_SurfaceObject *SO=NULL;
5822    SUMA_SurfaceObject *curSO=NULL;
5823    int i, k = 0;
5824    SUMA_Boolean LocalHead = NOPE;
5825 
5826    SUMA_ENTRY;
5827    switch(ado->do_type) {
5828       case SO_type:
5829          curSO = (SUMA_SurfaceObject *)ado;
5830          for (i=0; i< sv->N_DO; ++i) {
5831             if (SUMA_isSO_G(dov[sv->RegistDO[i].dov_ind], sv->CurGroupName)) {
5832                SO = (SUMA_SurfaceObject *)dov[sv->RegistDO[i].dov_ind].OP;
5833                if (curSO == SO) {
5834                   if (SO_SHOWING(SO, sv)) {
5835                      if ( SO->Side == SUMA_NO_SIDE ||
5836                           SO->Side == SUMA_SIDE_ERROR ) {
5837                         SUMA_RETURN(YUP);
5838                         ++k;
5839                      } else if (  (SO->Side == SUMA_RIGHT && sv->ShowRight) ||
5840                                   (SO->Side == SUMA_LEFT && sv->ShowLeft) ) {
5841                         SUMA_RETURN(YUP);
5842                         ++k;
5843                      }
5844                   }
5845                }
5846             }
5847          }
5848          break;
5849       case GDSET_type:
5850          SUMA_S_Err("Can't judge this without variant");
5851          SUMA_RETURN(NOPE);
5852          break;
5853       case CDOM_type:
5854       case VO_type:
5855       case MASK_type:
5856       case TRACT_type:
5857       case GRAPH_LINK_type:
5858          for (i=0; i< sv->N_DO; ++i) {
5859             if (dov[sv->RegistDO[i].dov_ind].OP == ado)  SUMA_RETURN(YUP);
5860          }
5861          SUMA_RETURN(YUP);
5862          break;
5863       default:
5864          SUMA_S_Errv("Nothing to do with %s\n",
5865                SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type));
5866          SUMA_RETURN(NOPE);
5867    }
5868 
5869    SUMA_RETURN(NOPE);
5870 
5871 }
SUMA_isRegisteredSO(SUMA_SurfaceViewer * sv,SUMA_DO * dov,SUMA_SurfaceObject * curSO)5872 SUMA_Boolean SUMA_isRegisteredSO (SUMA_SurfaceViewer *sv,
5873                                   SUMA_DO *dov, SUMA_SurfaceObject *curSO)
5874 {
5875    static char FuncName[]={"SUMA_isRegisteredSO"};
5876    SUMA_SurfaceObject *SO=NULL;
5877    int i, k = 0;
5878 
5879    SUMA_ENTRY;
5880 
5881    for (i=0; i< sv->N_DO; ++i) {
5882       if (1) {
5883          SO = (SUMA_SurfaceObject *)dov[sv->RegistDO[i].dov_ind].OP;
5884          if (curSO == SO) {
5885             SUMA_RETURN(YUP);
5886          }
5887       }
5888    }
5889 
5890    SUMA_RETURN(NOPE);
5891 }
5892 
SUMA_ADO_isRegistered(SUMA_SurfaceViewer * sv,SUMA_ALL_DO * ado)5893 SUMA_Boolean SUMA_ADO_isRegistered(SUMA_SurfaceViewer *sv, SUMA_ALL_DO *ado)
5894 {
5895    static char FuncName[]={"SUMA_ADO_isRegistered"};
5896    return(SUMA_isRegisteredDO(sv, SUMAg_DOv, ado));
5897 }
5898 
SUMA_isRegisteredDO(SUMA_SurfaceViewer * sv,SUMA_DO * dov,SUMA_ALL_DO * curDO)5899 SUMA_Boolean SUMA_isRegisteredDO (SUMA_SurfaceViewer *sv,
5900                                   SUMA_DO *dov, SUMA_ALL_DO *curDO)
5901 {
5902    static char FuncName[]={"SUMA_isRegisteredDO"};
5903    SUMA_ALL_DO *DO=NULL;
5904    int i, k = 0;
5905 
5906    SUMA_ENTRY;
5907 
5908    for (i=0; i< sv->N_DO; ++i) {
5909       if (1) {
5910          DO = (SUMA_ALL_DO *)dov[sv->RegistDO[i].dov_ind].OP;
5911          if (curDO == DO) {
5912             SUMA_RETURN(YUP);
5913          }
5914       }
5915    }
5916 
5917    SUMA_RETURN(NOPE);
5918 }
5919 
5920 
5921 /*!
5922    Return 1st decent, preferably anat correct state(i.e. not shadown state)
5923 */
SUMA_FirstGoodState(SUMA_SurfaceViewer * sv)5924 int SUMA_FirstGoodState(SUMA_SurfaceViewer *sv)
5925 {
5926    static char FuncName[] = {"SUMA_FirstGoodState"};
5927    int inxt, iok;
5928 
5929    SUMA_ENTRY;
5930 
5931    inxt = 0; iok = -1;
5932    while (inxt < sv->N_VSv) {
5933       if (SUMA_IS_GOOD_STATE(sv->VSv[inxt].Name)) {
5934          if (sv->VSv[inxt].AnatCorrect) {
5935             SUMA_RETURN(inxt);
5936          } else {
5937             if (iok < 0) iok = inxt;
5938          }
5939       }
5940       ++inxt;
5941    }
5942 
5943    SUMA_RETURN(iok);
5944 }
SUMA_FirstGoodAnatCorrState(SUMA_SurfaceViewer * sv)5945 int SUMA_FirstGoodAnatCorrState(SUMA_SurfaceViewer *sv)
5946 {
5947    static char FuncName[] = {"SUMA_FirstGoodAnatCorrState"};
5948    int inxt, iok;
5949 
5950    SUMA_ENTRY;
5951 
5952    inxt = 0; iok = -1;
5953    while (inxt < sv->N_VSv) {
5954       if (SUMA_IS_GOOD_STATE(sv->VSv[inxt].Name)) {
5955          if (sv->VSv[inxt].AnatCorrect) {
5956             SUMA_RETURN(inxt);
5957          }
5958       }
5959       ++inxt;
5960    }
5961 
5962    SUMA_RETURN(iok);
5963 }
5964 
5965 
5966 /*!
5967    nxtState = SUMA_NextState(sv);
5968 
5969    get the next Viewing State available in sv
5970    \param sv (SUMA_SurfaceViewer *) pointer to surface viewer structure
5971    \ret nxtState (int) the index into sv->VSv of the next state
5972       -1 if there is trouble
5973       icur is returned if there is no next state of the group sv->CurGroupName
5974    \sa SUMA_PrevState
5975 */
SUMA_NextState(SUMA_SurfaceViewer * sv)5976 int SUMA_NextState(SUMA_SurfaceViewer *sv)
5977 {
5978    static char FuncName[] = {"SUMA_NextState"};
5979    int inxt, icur;
5980    SUMA_Boolean LocalHead = NOPE;
5981 
5982    SUMA_ENTRY;
5983 
5984    icur = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
5985    if (icur < 0) {
5986       SUMA_S_Err("SUMA_WhichState failed.");
5987       SUMA_RETURN (-1);
5988    } else {
5989       inxt = (icur + 1) % sv->N_VSv;
5990       do {
5991          /* Now see if the upcoming one is of the same group */
5992          if (inxt == icur) {
5993             /* back where we started */
5994             SUMA_RETURN(inxt);
5995          } else if (strncmp(sv->VSv[inxt].Name,"TheShadow",9)) {
5996             if (!strcmp(sv->VSv[inxt].Group, sv->CurGroupName) ||
5997                 (!strcmp(sv->VSv[inxt].Group, "ANY"))) {
5998                /* group match, good, go back */
5999                SUMA_RETURN(inxt);
6000             }
6001          } else {
6002             /* Skip the shadow state */
6003          }
6004          inxt = (inxt + 1) % sv->N_VSv;
6005       } while (1);
6006    }
6007 
6008    /* should not get here */
6009    SUMA_SL_Err("Flow error");
6010    SUMA_RETURN (-1);
6011 }
6012 
6013 /*!
6014    precState = SUMA_PreviState (sv);
6015    get the previous Viewing State available in sv
6016    \sa SUMA_NextState
6017 */
SUMA_PrevState(SUMA_SurfaceViewer * sv)6018 int SUMA_PrevState(SUMA_SurfaceViewer *sv)
6019 {
6020    static char FuncName[] = {"SUMA_PrevState"};
6021    int inxt, icur;
6022    SUMA_Boolean LocalHead = NOPE;
6023 
6024    SUMA_ENTRY;
6025 
6026    icur = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
6027    if (icur < 0) {
6028       fprintf(SUMA_STDERR,"Error %s: SUMA_WhichState failed.\n", FuncName);
6029       SUMA_RETURN (-1);
6030    } else {
6031       inxt = icur -1; if (inxt < 0) inxt = sv->N_VSv + inxt;
6032       do {
6033          /* Now see if the upcoming one is of the same group */
6034          if (inxt == icur) {
6035             /* back where we started */
6036             SUMA_RETURN(inxt);
6037          } else if (strncmp(sv->VSv[inxt].Name,"TheShadow",9)) {
6038             if (!strcmp(sv->VSv[inxt].Group, sv->CurGroupName) ||
6039                 (!strcmp(sv->VSv[inxt].Group, "ANY"))) {
6040                /* group match, good, go back */
6041                SUMA_RETURN(inxt);
6042             }
6043          } else {
6044             /* Skip the shadow state */
6045          }
6046          inxt = inxt -1; if (inxt < 0) inxt = sv->N_VSv + inxt;
6047       } while (1);
6048    }
6049 
6050    SUMA_RETURN (-1);
6051 }
6052 
6053 
6054 
6055 /*!
6056    SOnxtID = SUMA_NextSO (dov, n_dov, CurrentIDcode, SOnxt);
6057    Get the next Surface Object in DOv
6058    \param dov (SUMA_DO *) vector containing all displayable objects
6059    \param n_dov (int) number of elements in dov
6060    \param CurrentIDcode (char *) idcode of current surface
6061    \param SOnxt (SUMA_SurfaceObject *) pointer to next surface object
6062    \ret SOnxtID (int) index into dov of SOnxt (-1) if there's an error
6063 */
6064 
SUMA_NextSO(SUMA_DO * dov,int n_dov,char * idcode,SUMA_SurfaceObject * SOnxt)6065 int SUMA_NextSO (SUMA_DO *dov, int n_dov, char *idcode, SUMA_SurfaceObject *SOnxt)
6066 {
6067    static char FuncName[] = {"SUMA_NextSO"};
6068    int icur, icheck, ncheck;
6069 
6070    SUMA_ENTRY;
6071 
6072    if (SOnxt != NULL) {
6073       fprintf(SUMA_STDERR,"Error %s: SOnxt should be null when you call this function.\n", FuncName);
6074       SUMA_RETURN (-1);
6075    }
6076    if (n_dov < 1) {
6077       fprintf(SUMA_STDERR,"Error %s: dov contains no elements.\n", FuncName);
6078       SUMA_RETURN (-1);
6079    }
6080    icur = SUMA_findSO_inDOv (idcode, dov, n_dov);
6081    if (icur < 0) {
6082       fprintf (SUMA_STDERR,"Error %s: idcode not found in dov.\n", FuncName);
6083       SUMA_RETURN (-1);
6084    }
6085 
6086    ncheck = 0;
6087    icheck = icur;
6088    while (ncheck < n_dov) {
6089       icheck = (icheck + 1) % n_dov;
6090       /*fprintf(SUMA_STDERR,"%s: Checking %d\n", FuncName, icheck);*/
6091       if (SUMA_isSO(dov[icheck])) {
6092          /*fprintf(SUMA_STDERR,"%s: Settling on %d\n", FuncName, icheck);*/
6093          SOnxt = (SUMA_SurfaceObject *)dov[icheck].OP;
6094          SUMA_RETURN (icheck);
6095       }
6096       ++ncheck;
6097    }
6098    /* should not get here */
6099    SUMA_RETURN (-1);
6100 }
6101 
6102 /*!
6103    Replaces one surface in RegisteredDO with another
6104 */
SUMA_SwitchSO(SUMA_DO * dov,int N_dov,int SOcurID,int SOnxtID,SUMA_SurfaceViewer * sv)6105 SUMA_Boolean SUMA_SwitchSO (SUMA_DO *dov, int N_dov,
6106                             int SOcurID, int SOnxtID, SUMA_SurfaceViewer *sv)
6107 {
6108    static char FuncName[]={"SUMA_SwitchSO"};
6109    SUMA_Axis *EyeAxis;
6110    int EyeAxis_ID;
6111    char CommString[100];
6112    SUMA_EngineData ED;
6113    DList *list = NULL;
6114 
6115    SUMA_ENTRY;
6116 
6117    /* unregister the current surface from RegisteredDO */
6118    /*fprintf(SUMA_STDERR,"%s: Unregistering DOv[%d]...\n", FuncName, SOcurID);*/
6119    if (!SUMA_UnRegisterDO(SOcurID, sv)) {
6120       fprintf(SUMA_STDERR,"Error %s: Failed to UnRegisterDO.\n", FuncName);
6121       SUMA_RETURN (NOPE);
6122    }
6123 
6124    /* set the focus ID to the current surface */
6125    sv->Focus_DO_ID = SOnxtID;
6126 
6127    /* register the new surface in RegisteredDO */
6128    /*fprintf(SUMA_STDERR,"%s: Registering DOv[%d]...\n",
6129              FuncName, sv->Focus_DO_ID); */
6130    if (!SUMA_RegisterDO(sv->Focus_DO_ID, sv)) {
6131       fprintf(SUMA_STDERR,"Error %s: Failed to RegisterDO.\n", FuncName);
6132       SUMA_RETURN (NOPE);
6133    }
6134 
6135    /* modify the rotation center */
6136    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
6137       fprintf (SUMA_STDERR,
6138                "Error %s: Failed to update center of rotation", FuncName);
6139       SUMA_RETURN (NOPE);
6140    }
6141 
6142    /* set the viewing points */
6143    if (!SUMA_UpdateViewPoint(sv, dov, N_dov, 0)) {
6144       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
6145       SUMA_RETURN (NOPE);
6146    }
6147 
6148    /* Change the defaults of the eye axis to fit standard EyeAxis */
6149    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
6150 
6151    if (EyeAxis_ID < 0) {
6152       fprintf(SUMA_STDERR,"Error %s: No Eye Axis. %d\n", FuncName, EyeAxis_ID);
6153    } else {
6154       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
6155       SUMA_EyeAxisStandard (EyeAxis, sv);
6156    }
6157 
6158    /* do the light business */
6159    if (dov[sv->Focus_DO_ID].ObjectType == SO_type &&
6160        !SUMA_SetViewerLightsForSO(sv,
6161                   (SUMA_SurfaceObject *)(dov[sv->Focus_DO_ID].OP))) {
6162       SUMA_S_Warn("Failed to set viewer lights.\n"
6163                   "Use 'F' key to flip lights in SUMA\n"
6164                   "if necessary.");
6165    }
6166 
6167    /* do the axis setup */
6168    SUMA_WorldAxisStandard (sv->WAx, sv);
6169 
6170 
6171    /* Home call baby */
6172    if (!list) list = SUMA_CreateList();
6173    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
6174 
6175    if (!SUMA_Engine (&list)) {
6176       fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
6177    }
6178 
6179 
6180    /* take care of the cross hair's XYZ */
6181 
6182    /* to do elsewhere */
6183    /* when a cross hair needs to be communicated, you must use
6184       the LocalDomainParentID surface and not the Focus_Surface */
6185    SUMA_RETURN (YUP);
6186 }
6187 
6188 /*!
6189    \brief gets overlays from parent surface SO_prec to child surface SO_nxt
6190 
6191 */
SUMA_GetOverlaysFromParent(SUMA_SurfaceObject * SO_nxt,SUMA_SurfaceObject * SO_prec)6192 SUMA_Boolean SUMA_GetOverlaysFromParent(SUMA_SurfaceObject *SO_nxt,
6193                                         SUMA_SurfaceObject *SO_prec)
6194 {
6195    static char FuncName[]={"SUMA_GetOverlaysFromParent"};
6196    int j, OverInd=-1;
6197    SUMA_Boolean LocalHead = NOPE;
6198 
6199    SUMA_ENTRY;
6200 
6201    if (!SO_nxt || !SO_prec) {
6202       SUMA_SL_Err("Null input");
6203       SUMA_RETURN(NOPE);
6204    }
6205    if (!SUMA_isRelated_SO(SO_prec, SO_nxt, 1)) {
6206       SUMA_SL_Err("Surfaces are not level 1 related");
6207       SUMA_RETURN(NOPE);
6208    }
6209 
6210    /* Create a link to each overlay plane in the precursor unless
6211       such a plane exists already  */
6212    for (j=0; j < SO_prec->N_Overlays; ++j) {
6213       if (!SUMA_Fetch_OverlayPointer ((SUMA_ALL_DO *)SO_nxt,
6214                            SO_prec->Overlays[j]->Name, &OverInd)) {
6215          /* plane not found, create a link to it */
6216          SUMA_LHv("Overlay plane %s not found, creating the link.\n",
6217                   SO_prec->Overlays[j]->Name);
6218          SO_nxt->Overlays[SO_nxt->N_Overlays] =
6219                (SUMA_OVERLAYS *)SUMA_LinkToPointer((void*)SO_prec->Overlays[j]);
6220          /* it happens at times, that an overlay carries coordinate bias with it.
6221          When that happens, the bias should be added immediately */
6222          if (SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl) {
6223             if (SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl->BiasVect) {
6224                SUMA_LH("Adding coordbias");
6225                SUMA_AddVisX_CoordBias(  SO_nxt,
6226                      SO_nxt->Overlays[SO_nxt->N_Overlays],
6227                      SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl->DoBias,
6228                      SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl->BiasVect);
6229                /* Apply the business */
6230                if (!SUMA_ApplyVisXform(SO_nxt, "VisX",
6231                                        FORWARD_XFORM, 1)) {
6232                   SUMA_S_Warn("Failed to apply VisX transform");
6233                }
6234             }
6235          }
6236          /*increment the number of overlay planes */
6237          ++SO_nxt->N_Overlays;
6238       } else {
6239          /* plane found, do nothing */
6240          SUMA_LHv("Overlay plane %s found. Index#%d\n.",
6241                   SO_prec->Overlays[j]->Name, OverInd);
6242       }
6243    }
6244 
6245    SUMA_RETURN(YUP);
6246 }
6247 
6248 /*!
6249    ans = SUMA_SwitchState (dov, N_dov, sv, nxtstateID, nxtgroup);
6250 
6251    Replaces one viewing state with another
6252 
6253 */
SUMA_SwitchState(SUMA_DO * dov,int N_dov,SUMA_SurfaceViewer * sv,int nxtstateID,char * nxtgroup)6254 SUMA_Boolean SUMA_SwitchState (  SUMA_DO *dov, int N_dov,
6255                                  SUMA_SurfaceViewer *sv,
6256                                  int nxtstateID, char *nxtgroup)
6257 {
6258    static char FuncName[]={"SUMA_SwitchState"};
6259    SUMA_Axis *EyeAxis;
6260    int EyeAxis_ID, I_C, ND, id;
6261    char CommString[100];
6262    SUMA_EngineData ED;
6263    int curstateID, i, j, jmax, prec_ID, *MembSOs=NULL, N_MembSOs=0;
6264    int RegSO[SUMA_MAX_DISPLAYABLE_OBJECTS], N_RegSO;
6265    SUMA_SurfaceObject *SO_nxt, *SO_prec, *SO1, *SO2, *SOtmp=NULL;
6266    SUMA_DO_Types ttv[10]={SO_type, GRAPH_LINK_type, NOT_SET_type};
6267    float *XYZ, *XYZmap, zfac = 0.0;
6268    DList *list = NULL;
6269    SUMA_Boolean LocalHead = NOPE;
6270 
6271    SUMA_ENTRY;
6272 
6273    XYZ = NULL;
6274    XYZmap = NULL;
6275 
6276    curstateID = SUMA_WhichState(sv->State, sv, sv->CurGroupName);
6277    zfac = sv->FOV[curstateID]/SUMA_sv_auto_fov(sv);
6278    if (zfac > 10) zfac = 10.0;
6279    if (zfac < 0.005) zfac = 0.005;
6280 
6281    /* unregister all the surfaces for the current view */
6282    if (LocalHead)
6283          fprintf( SUMA_STDERR,
6284                   "%s: Request to change to id %d\n"
6285                   "Unregistering state %d (%s), sv(%p)->State = %s\n",
6286                   FuncName, nxtstateID, curstateID, sv->VSv[curstateID].Name,
6287                   sv, sv->State);
6288    for (i=0; i<sv->VSv[curstateID].N_MembDO; ++i) {
6289       if (!SUMA_UnRegisterDO(sv->VSv[curstateID].MembDO[i].dov_ind, sv)) {
6290          fprintf(SUMA_STDERR,"Error %s: Failed to UnRegisterDO.\n", FuncName);
6291          SUMA_RETURN (NOPE);
6292       }
6293    }
6294 
6295    /* adopt the new group */
6296    if (strcmp(sv->CurGroupName, nxtgroup)) {
6297       SUMA_LH("Changing group...");
6298       if (!SUMA_AdoptGroup(sv, nxtgroup)) {
6299          SUMA_SLP_Err("Failed to adopt new group");
6300          SUMA_RETURN(NOPE);
6301       }
6302    } else {
6303       SUMA_LH("No group change...");
6304    }
6305 
6306    /* register all the surfaces/DOs from the next view */
6307 
6308    /* Need to set the state before you go into Registering DOs    May 2013 */
6309    sv->State =  sv->VSv[nxtstateID].Name;
6310    sv->iState = nxtstateID;
6311 
6312    SUMA_LHv("Registering %d DOs of state %d (%s)...\n",
6313             sv->VSv[nxtstateID].N_MembDO, nxtstateID,
6314             sv->VSv[nxtstateID].Name);
6315    for (i=0; i<sv->VSv[nxtstateID].N_MembDO; ++i) {
6316       if (!SUMA_RegisterDO(sv->VSv[nxtstateID].MembDO[i].dov_ind, sv)) {
6317          fprintf(SUMA_STDERR,"Error %s: Failed to RegisterDO.\n", FuncName);
6318          SUMA_RETURN (NOPE);
6319       }
6320    }
6321 
6322    /* if have two surfaces, keep them from overlapping */
6323    N_RegSO = SUMA_RegisteredSOs (sv, dov, RegSO);
6324    if (N_RegSO > 2) {
6325       SUMA_LH( "Will not attempt\n"
6326                      "to separate more than\n"
6327                      "2 surfaces.\n");
6328    } else if (N_RegSO == 2) {
6329       SO1 = (SUMA_SurfaceObject *)dov[RegSO[0]].OP;
6330       SO2 = (SUMA_SurfaceObject *)dov[RegSO[1]].OP;
6331       SUMA_LHv("Computing separation for %s and %s\n",
6332          SO1->Label, SO2->Label);
6333       if (!SO1->VisX0.Applied || !SO2->VisX0.Applied) {
6334          if (!SUMA_ComputeVisX(SO1, SO2, sv, "VisX0",1)) {
6335             SUMA_S_Err("Failed to compute or apply overlap avoidance xform");
6336             SUMA_RETURN(NOPE);
6337          }
6338       }
6339    }
6340 
6341    SUMA_LH("Setting remix flag");
6342    /*set the Color Remix flag */
6343    if (!SUMA_SetShownLocalRemixFlag (sv)) {
6344       fprintf (SUMA_STDERR,
6345                "Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n", FuncName);
6346       SUMA_RETURN (NOPE);
6347    }
6348 
6349    /* Get those DOs that are surfaces or graphs*/
6350    MembSOs = SUMA_ViewState_Membs(&(sv->VSv[nxtstateID]), ttv, &N_MembSOs);
6351 
6352    if (!MembSOs || N_MembSOs==0) {
6353       SUMA_S_Errv("No members found for state %s, what gives?\n",
6354                  sv->VSv[nxtstateID].Name);
6355       SUMA_RETURN(NOPE);
6356    }
6357    /* if no coloroverlay exists, link to MapReference surface, if possible */
6358    SUMA_LHv("Have %d memb[SD]Os\n", N_MembSOs);
6359    for (i=0; i<N_MembSOs; ++i) {
6360       switch (dov[MembSOs[i]].ObjectType) {
6361          case SO_type:
6362       /* next surface being checked */
6363       SO_nxt = (SUMA_SurfaceObject *)(dov[MembSOs[i]].OP);
6364 
6365       /* Get the Mapping Reference surface, that's the precursor*/
6366       if (!SO_nxt->LocalDomainParentID) {
6367          prec_ID = -1;
6368       }else {
6369          prec_ID = SUMA_findSO_inDOv(  SO_nxt->LocalDomainParentID,
6370                                        SUMAg_DOv, SUMAg_N_DOv);
6371       }
6372       if (prec_ID < 0) {
6373          /* no precursors found, notify user */
6374          fprintf(SUMA_STDERR,
6375                   "\n\aWarning %s: "
6376                   "No precursors found for surface %d.\n"
6377                   "Colors, selected nodes and facesets will "
6378                   "not reflect those in previous state.\n.",
6379                   FuncName, MembSOs[i]);
6380          continue;
6381       }
6382 
6383       SO_prec = (SUMA_SurfaceObject *)(dov[prec_ID].OP);
6384 
6385       /* check for risk of node inconsistencies */
6386 
6387       if (SO_prec->N_Node >= SO_nxt->N_Node ) {/* > or equal number of nodes*/
6388          /* matching number of nodes */
6389          if (!SUMA_GetOverlaysFromParent(SO_nxt,SO_prec)) {
6390             SUMA_SL_Err("Failed to get overlays from parents");
6391             SUMA_RETURN(NOPE);
6392          }
6393 
6394          if (SO_prec->N_Node > SO_nxt->N_Node) {/* More in prec */
6395             /* just warn */
6396             fprintf(SUMA_STDERR,
6397                      "Warning %s: More nodes (%d) in precursor surface. \n"
6398                      "Assuming upcoming surface is a subset of precursor.\n",
6399                      FuncName, SO_prec->N_Node - SO_nxt->N_Node);
6400          }/* More in prec */
6401 
6402          /* link the selected nodes and facesets, if possible */
6403          /*fprintf(SUMA_STDERR,
6404                   "%s: Linking selected nodes  ...\n",
6405                   FuncName);*/
6406          /* check for risk of node inconsistencies */
6407          if (SO_prec->N_Node == SO_nxt->N_Node) {
6408             SO_nxt->SelectedNode = SO_prec->SelectedNode;
6409          } else { /*more nodes in precursor, make sure selected node is OK */
6410          if (SO_prec->SelectedNode < SO_nxt->N_Node) {
6411             SO_nxt->SelectedNode = SO_prec->SelectedNode;
6412          } else { /* this node does not exist in the upcoming thing */
6413             fprintf(SUMA_STDERR,
6414                      "\n\aWarning %s: "
6415                      "Slected node in precursor state does not exist "
6416                      "in current state.\n"
6417                      "Selected Node is left at previous setting in "
6418                      "this view state.\n", FuncName);
6419             }
6420          }
6421 
6422       } /* > or equal number of nodes */ else { /* less in prec */
6423          fprintf(SUMA_STDERR,
6424                   "\n\aWarning %s: More nodes (%d) in upcoming surface. "
6425                   "Colors, selected nodes and facesets are not carried "
6426                   "through from precursor.\n",
6427                   FuncName, SO_nxt->N_Node - SO_prec->N_Node);
6428       }
6429 
6430             break;
6431          case GRAPH_LINK_type:
6432             /* nothing needed */
6433             break;
6434          default:
6435             SUMA_S_Err("Should not be here");
6436             break;
6437       }
6438 
6439    }
6440 
6441 
6442    /* Bind the cross hair to a reasonable surface, if possible */
6443    if (iDO_isSO(sv->Ch->adoID)) {
6444       if (LocalHead)
6445          fprintf( SUMA_STDERR,
6446                   "Local Debug %s: Linking Cross Hair via adoID...\n",
6447                    FuncName);
6448       j = SUMA_MapRefRelative (sv->Ch->adoID,
6449                                MembSOs,
6450                                N_MembSOs, dov);
6451       if (LocalHead) fprintf( SUMA_STDERR,
6452                               "Local Debug %s: "
6453                               "Cross Hair's  New adoID = %d\n",
6454                               FuncName, j );
6455 
6456       /* set the XYZ of the cross hair based on the
6457          coordinates of the upcoming surface, if possible */
6458       if (j >= 0) {
6459          SO_nxt = (SUMA_SurfaceObject *)(dov[j].OP);
6460          ND = SO_nxt->NodeDim;
6461          id = ND * sv->Ch->datumID;
6462          if (sv->Ch->datumID >= 0) {
6463             if (LocalHead) fprintf( SUMA_STDERR,
6464                                     "Local Debug %s: Using datumID for link.\n",
6465                                     FuncName);
6466             sv->Ch->c[0] = SO_nxt->NodeList[id];
6467             sv->Ch->c[1] = SO_nxt->NodeList[id+1];
6468             sv->Ch->c[2] = SO_nxt->NodeList[id+2];
6469          } else {
6470             /* no node associated with cross hair, use XYZ */
6471             if (LocalHead) fprintf( SUMA_STDERR,
6472                                     "Local Debug %s: Using XYZ for link.\n",
6473                                     FuncName);
6474             SO_prec = (SUMA_SurfaceObject *)(dov[sv->Ch->adoID].OP);
6475             /* go from XYZ to XYZmap on current surface
6476                then from XYZmap to XYZ on new surface */
6477             I_C = -1;
6478             XYZmap = SUMA_XYZ_XYZmap (sv->Ch->c, SO_prec, dov, N_dov, &I_C, 1);
6479             if (XYZmap == NULL) {
6480                fprintf( SUMA_STDERR,
6481                         "Error %s: Failed in SUMA_XYZ_XYZmap\n",
6482                         FuncName);
6483             }else {
6484                XYZ = SUMA_XYZmap_XYZ (XYZmap, SO_nxt, dov, N_dov, &I_C, 1);
6485                if (XYZ == NULL) {
6486                   fprintf( SUMA_STDERR,
6487                            "Error %s: Failed in SUMA_XYZmap_XYZ\n",
6488                            FuncName);
6489                } else {
6490                   sv->Ch->c[0] = XYZ[0];
6491                   sv->Ch->c[1] = XYZ[1];
6492                   sv->Ch->c[2] = XYZ[2];
6493                }
6494 
6495             }
6496             if (XYZ) SUMA_free(XYZ);
6497             if (XYZmap) SUMA_free(XYZmap);
6498          }
6499 
6500          /* if the surface controller is open, update it */
6501          if (SUMA_isADO_Cont_Realized((SUMA_ALL_DO *)SO_nxt))   {
6502             SUMA_Init_SurfCont_SurfParam((SUMA_ALL_DO *)SO_nxt);
6503          }
6504 
6505       } else {
6506          fprintf( SUMA_STDERR,
6507                   "%s: No relatives between states. "
6508                   "CrossHair location will not correspond between states\n",
6509                   FuncName);
6510       }
6511       sv->Ch->adoID = j;
6512       if (LocalHead)
6513          fprintf(SUMA_STDERR,
6514                   "Local Debug %s: Linking Cross Hair Via datumID Done.\n",
6515                   FuncName);
6516    }
6517 
6518 
6519 
6520    if (sv->FOV[sv->iState] == sv->FOV_original || sv->FOV[sv->iState] < 0) {
6521       sv->FOV[sv->iState] = SUMA_sv_auto_fov(sv);
6522    }
6523    if (sv->FreezeZoomXstates)
6524       sv->FOV[sv->iState] = SUMA_sv_auto_fov(sv)*zfac;
6525 
6526    /* set the focus ID to the first surface/object in the next view */
6527    sv->Focus_DO_ID = MembSOs[0];
6528 
6529    SUMA_ifree(MembSOs);
6530 
6531    /* Now update the cross hair info if needed for the surface in focus */
6532    if (sv->Ch->adoID >= 0 && (SOtmp = SUMA_SV_Focus_SO(sv)))   {
6533       if (SUMA_isADO_Cont_Realized((SUMA_ALL_DO *)SOtmp)) {
6534          SUMA_Init_SurfCont_CrossHair((SUMA_ALL_DO *)SOtmp);
6535       }
6536    }
6537 
6538    if ((SOtmp = SUMA_SV_Focus_SO(sv)) && LocalHead) {
6539       fprintf( SUMA_STDERR,
6540                "%s: Setting new Focus ID to surface %s\n",
6541                FuncName, SOtmp->Label);
6542    }
6543 
6544    /* decide what the best state is */
6545    sv->StdView = SUMA_BestStandardView (sv,dov, N_dov);
6546    if (LocalHead) fprintf( SUMA_STDOUT,
6547                            "%s: Standard View Now %d\n",
6548                            FuncName, sv->StdView);
6549    if (sv->StdView == SUMA_N_STANDARD_VIEWS) {
6550       fprintf( SUMA_STDERR,
6551                "Error %s: Could not determine the best standard view. "
6552                "Choosing default SUMA_3D\n",
6553                FuncName);
6554       sv->StdView = SUMA_3D;
6555    }
6556 
6557    /* modify the rotation center */
6558    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
6559       fprintf (SUMA_STDERR,
6560                "Error %s: Failed to update center of rotation",
6561                FuncName);
6562       SUMA_RETURN (NOPE);
6563    }
6564 
6565    /* set the viewing points */
6566    if (!SUMA_UpdateViewPoint(sv, dov, N_dov, 0)) {
6567       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
6568       SUMA_RETURN (NOPE);
6569    }
6570 
6571    /* Change the defaults of the eye axis to fit standard EyeAxis */
6572    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
6573 
6574    if (EyeAxis_ID < 0) {
6575       fprintf(SUMA_STDERR,"Error %s: No Eye Axis. %d\n", FuncName, EyeAxis_ID);
6576    } else {
6577       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
6578       SUMA_EyeAxisStandard (EyeAxis, sv);
6579    }
6580 
6581    /* do the axis setup */
6582    SUMA_WorldAxisStandard (sv->WAx, sv);
6583 
6584    /* do the light business */
6585    if (SOtmp && !SUMA_SetViewerLightsForSO( sv, SOtmp )) {
6586       SUMA_S_Warn("Failed to set viewer lights.\n"
6587                   "Use 'F' key to flip lights in SUMA if necessary.");
6588    }
6589 
6590    /* Home call baby */
6591    if (!list) list = SUMA_CreateList();
6592    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
6593    if (!SUMA_Engine (&list)) {
6594       fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
6595    }
6596 
6597    SUMA_RETURN (YUP);
6598 }
6599 
6600 /*!
6601    Call this function whenever you have new geometry in the viewer
6602    This happens when you switch states or when you modify the coordinates
6603    of a surface
6604    The succession of function calls is replicated in parts elsewhere in the code
6605    like in the SwitchState function
6606 */
SUMA_NewGeometryInViewer(SUMA_DO * dov,int N_dov,SUMA_SurfaceViewer * sv)6607 SUMA_Boolean SUMA_NewGeometryInViewer (SUMA_DO *dov, int N_dov,
6608                                        SUMA_SurfaceViewer *sv)
6609 {
6610    static char FuncName[]={"SUMA_NewGeometryInViewer"};
6611    SUMA_Axis *EyeAxis;
6612    int EyeAxis_ID, I_C, OverInd, ND, id;
6613    char CommString[100];
6614    SUMA_EngineData ED;
6615    int  i, j, jmax, prec_ID;
6616    SUMA_SurfaceObject *SO_nxt, *SO_prec;
6617    SUMA_Boolean LocalHead = NOPE;
6618 
6619    SUMA_ENTRY;
6620 
6621    /* decide what the best std view is */
6622    sv->StdView = SUMA_BestStandardView (sv,dov, N_dov);
6623    if (LocalHead)
6624       fprintf(SUMA_STDOUT,"%s: Standard View Now %d\n", FuncName, sv->StdView);
6625    if (sv->StdView == SUMA_N_STANDARD_VIEWS) {
6626       fprintf(SUMA_STDERR,
6627                "Error %s: Could not determine the best standard view."
6628                " Choosing default SUMA_3D\n", FuncName);
6629       sv->StdView = SUMA_3D;
6630    }
6631 
6632    /* modify the rotation center */
6633    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
6634       SUMA_S_Err("Failed to update center of rotation");
6635       SUMA_RETURN (NOPE);
6636    }
6637 
6638    /* set the viewing points */
6639    if (!SUMA_UpdateViewPoint(sv, dov, N_dov, 0)) {
6640       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
6641       SUMA_RETURN (NOPE);
6642    }
6643 
6644 
6645    /* Change the defaults of the eye axis to fit standard EyeAxis */
6646    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
6647 
6648    if (EyeAxis_ID < 0) {
6649       fprintf(SUMA_STDERR,"Error %s: No Eye Axis. %d\n", FuncName, EyeAxis_ID);
6650    } else {
6651       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
6652       SUMA_EyeAxisStandard (EyeAxis, sv);
6653    }
6654 
6655    /* Need to update where you're looking at*/
6656    glMatrixMode(GL_MODELVIEW);
6657    glLoadIdentity();
6658    gluLookAt ( sv->GVS[sv->StdView].ViewFrom[0],
6659                sv->GVS[sv->StdView].ViewFrom[1],
6660                sv->GVS[sv->StdView].ViewFrom[2],
6661                sv->GVS[sv->StdView].ViewCenter[0],
6662                sv->GVS[sv->StdView].ViewCenter[1],
6663                sv->GVS[sv->StdView].ViewCenter[2],
6664                sv->GVS[sv->StdView].ViewCamUp[0],
6665                sv->GVS[sv->StdView].ViewCamUp[1],
6666                sv->GVS[sv->StdView].ViewCamUp[2]);
6667 
6668    /* do the axis setup */
6669    SUMA_WorldAxisStandard (sv->WAx, sv);
6670 
6671    /* You still need to call SUMA_display via SUMA_postRedisplay but that is done after this function returns */
6672 
6673    SUMA_RETURN (YUP);
6674 }
6675 
6676 /*!
6677 \brief ans = SUMA_OpenGLStateReset (dov, N_dov, sv);
6678 Used when going from one surface viewer to another. The OpenGL state variables
6679 need to be reset when moving from one viewer to the next. Otherwise you risk having
6680 unpredictable results the first time you do something in one viewer after you'd been
6681 in another.
6682 This function is a stripped down version of SUMA_SwitchState and should
6683 be followed by a call to SUMA_postRedisplay for all the changes to take effect.
6684 
6685 Note that SUMA_postRedisplay may not be good enough because it posts a display request which may not execute immediately. SUMA_handleRedisplay would be the harsher, but more effective method.
6686 
6687 Do not try executing all the commands in SUMA_display that affect the modelview
6688 matrix and the projection matrix without calling for a display the changes will not take effect.
6689 
6690 \param dov (SUMA_DO *) Pointer to vector of displayable objects, typically SUMAg_DOv
6691 \param N_dov (int) number of elements in dov, typically SUMAg_N_DOv
6692 \param sv (SUMA_SurfaceViewer *) viewer making the request.
6693 \return YUP/NOPE Good/Bad
6694 \sa SUMA_NewGeometryInViewer
6695 
6696 */
SUMA_OpenGLStateReset(SUMA_DO * dov,int N_dov,SUMA_SurfaceViewer * sv)6697 SUMA_Boolean SUMA_OpenGLStateReset (SUMA_DO *dov, int N_dov,
6698                                     SUMA_SurfaceViewer *sv)
6699 {
6700    static char FuncName[]={"SUMA_OpenGLStateReset"};
6701    SUMA_Axis *EyeAxis;
6702    int EyeAxis_ID, I_C, OverInd, ND, id;
6703    char CommString[100];
6704    SUMA_EngineData ED;
6705    int  i, j, jmax, prec_ID;
6706    SUMA_SurfaceObject *SO_nxt, *SO_prec;
6707    SUMA_Boolean LocalHead = NOPE;
6708 
6709    SUMA_ENTRY;
6710 
6711    #if 0
6712    /* modify the rotation center */
6713    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
6714       fprintf (SUMA_STDERR,
6715                "Error %s: Failed to update center of rotation", FuncName);
6716       SUMA_RETURN (NOPE);
6717    }
6718 
6719    /* set the viewing points */
6720    if (!SUMA_UpdateViewPoint(sv, dov, N_dov, 0)) {
6721       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
6722       SUMA_RETURN (NOPE);
6723    }
6724    #endif
6725 
6726    /* This is all that is needed, the others above do not need to
6727       be updated at this stage*/
6728 
6729    /* Change the defaults of the eye axis to fit standard EyeAxis */
6730    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
6731 
6732    if (EyeAxis_ID < 0) {
6733       /* This happens when only loading objects that are not surfaces.
6734          the eye axis for such monsters is created later, so return
6735          quietly */
6736       SUMA_LH("No Eye Axis. dealing with non SOs I take it?");
6737    } else {
6738       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
6739       SUMA_EyeAxisStandard (EyeAxis, sv);
6740    }
6741 
6742 
6743    #if 0
6744    /* force an axis drawing to set the projection matrix correctly */
6745    SUMA_SET_GL_PROJECTION(sv, sv->ortho);
6746    #endif
6747 
6748    /* You still need to call SUMA_display via SUMA_postRedisplay but that is done after this function returns */
6749 
6750    SUMA_RETURN (YUP);
6751 }
6752 
6753 
6754 /*!
6755    EyeAxisID = SUMA_GetEyeAxis (sv, dov);
6756    gets the ID (indices into dov) of the Eye Axis in sv
6757    \param sv (SUMA_SurfaceViewer *) the surface viewer structure
6758    \param dov (SUMA_DO *) the Displayable Objects vector (accessible to sv)
6759    \param Ax (SUMA_Axis *) a pointer to the Eye Axis structure (NULL if error )
6760    \ret EyeAxisID (int) the index into dov of the Eye Axis
6761       if an error is encountered, including more than one Eye Axis, a -1 is returned
6762 */
SUMA_GetEyeAxis(SUMA_SurfaceViewer * sv,SUMA_DO * dov)6763 int SUMA_GetEyeAxis (SUMA_SurfaceViewer *sv, SUMA_DO *dov)
6764 {
6765    static char FuncName[]={"SUMA_GetEyeAxis"};
6766    int i, k = -1, cnt = 0;
6767    SUMA_Axis *AO;
6768 
6769    SUMA_ENTRY;
6770 
6771    for (i=0; i< sv->N_DO; ++i) {
6772       if (dov[sv->RegistDO[i].dov_ind].ObjectType == AO_type) {
6773          AO = (SUMA_Axis *)(dov[sv->RegistDO[i].dov_ind].OP);
6774          if (strcmp(AO->Label, "Eye Axis") == 0) {
6775             k = sv->RegistDO[i].dov_ind;
6776             ++cnt;
6777          }
6778       }
6779    }
6780    if (cnt > 1) {
6781       fprintf (SUMA_STDERR,
6782                "Error %s: Found more than one Eye Axis. \n", FuncName);
6783       SUMA_RETURN (-1);
6784    }
6785 
6786    SUMA_RETURN (k);
6787 }
6788 
6789 /*!
6790    transform current XYZ to XYZmap
6791    The XYZ on an auxilliary surface are of no relevance to the volume.
6792    They must be transformed to mappable XYZ (in mm, RAI, in alignment
6793    with the Parent Volume)
6794    XYZmap = SUMA_XYZ_XYZmap (XYZ, SO, dov, N_dov, I_C, LDP_only);
6795 
6796    \param XYZ (float *) XYZ triplet in SO's native coordinate space
6797    \param SO (SUMA_SurfaceObject *SO) obvious, ain't it
6798    \param dov (SUMA_DO*) vector containing all displayable objects
6799    \param N_dov (int) number of elements in dov
6800    \param I_C (int *) (pre allocated) pointer to the index of the closest
6801                (or representative) node in SO to the XYZ location.
6802                If you do not have it, make sure *I_C = -1.
6803                If you do so, the function will search for nodes contained in
6804                a box mm wide and centered on XYZ.
6805                If nodes are found in the box the I_C is set to the
6806                index of the closest node and XYZmap contains the coordinates
6807                of I_C in the SO->LocalDomainParentID surface.
6808    \param LDP_only (int) if 1, then XYZmap is only the same as XYZ when SO
6809                                is itself the LDP.
6810                          if 0, XYZmap = XYZ is SO is LDP, or if SO is
6811                                anatomically correct.
6812    \ret XYZmap (float *) Mappable XYZ coordinates. NULL in case of trouble.
6813 
6814 */
6815 
SUMA_XYZ_XYZmap(float * XYZ,SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_dov,int * I_C,int LDP_only)6816 float * SUMA_XYZ_XYZmap (float *XYZ, SUMA_SurfaceObject *SO,
6817                          SUMA_DO* dov, int N_dov, int *I_C, int LDP_only)
6818 {/* SUMA_XYZ_XYZmap */
6819    static char FuncName[]={"SUMA_XYZ_XYZmap"};
6820    float *XYZmap;
6821    int iclosest, id, ND;
6822    SUMA_SurfaceObject *SOmap;
6823    int SOmapID;
6824    SUMA_Boolean LocalHead = NOPE;
6825 
6826    SUMA_ENTRY;
6827 
6828    /* allocate for return */
6829    XYZmap = (float *)SUMA_calloc (3, sizeof(float));
6830    if (XYZmap == NULL) {
6831       fprintf(SUMA_STDERR,
6832                "Error %s: Could not allocate for XYZmap.\n", FuncName);
6833       SUMA_RETURN (NULL);
6834    }
6835 
6836    /* if surface is a local domain parent, do the obivious */
6837    if (SUMA_isLocalDomainParent(SO)){
6838       /*SUMA_LH("Surface is a local domain parent. XYZmap = XYZ.\n"); */
6839       SUMA_COPY_VEC (XYZ, XYZmap, 3, float, float);
6840       SUMA_RETURN (XYZmap);
6841    }
6842 
6843    if (!LDP_only && SO->AnatCorrect){ /* Aug. 22 2012 */
6844       /*SUMA_LH("Surface is anatomocally correct. XYZmap = XYZ.\n"); */
6845       SUMA_COPY_VEC (XYZ, XYZmap, 3, float, float);
6846       SUMA_RETURN (XYZmap);
6847    }
6848 
6849    /* if surface is not a local domain parent and not anatomically correct,
6850    do the deed */
6851    if (!SUMA_ismappable(SO)){
6852       SUMA_S_Warn("Surface is NOT mappable, returning NULL.");
6853       SUMA_free(XYZmap);
6854       SUMA_RETURN (NULL);
6855    }
6856 
6857    /* surface is mappable, things will get more complicated */
6858 
6859    /* find the closest node in SO */
6860    if (*I_C < 0) { /* user has not specified closest node ID*/
6861       /* must find closest node on my own */
6862          {
6863             SUMA_ISINBOX IB;
6864             float Bd[3], distance;
6865             int ii;
6866 
6867             /* set the search box dimensions */
6868             Bd[0] = Bd[1] = Bd[2] = SUMA_XYZ_XFORM_BOXDIM_MM;
6869             IB = SUMA_isinbox (SO->NodeList, SO->N_Node, XYZ, Bd,  YUP);
6870             SUMA_S_Notev("%d nodes (out of %d) found in box\n",
6871                          IB.nIsIn, SO->N_Node);
6872 
6873             if (IB.nIsIn) { /* found some, find the closest node */
6874                /* locate the closest node and store it's id in EngineData*/
6875                /*for (ii=0; ii<IB.nIsIn; ++ii) {
6876                   fprintf (SUMA_STDERR,"%d\t%.3f\t\t", IB.IsIn[ii], IB.d[ii]);
6877                }*/
6878                SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, distance, iclosest);
6879                iclosest = IB.IsIn[iclosest];
6880                /* get ridd of IB's vectors */
6881                if (!SUMA_Free_IsInBox (&IB)) {
6882                   fprintf(SUMA_STDERR,"Error %s: Failed to free IB\n", FuncName);
6883                }
6884 
6885             } else { /* no node is close enough */
6886                SUMA_S_Errv("No node was close enough to XYZ=[%f %f %f],"
6887                            " no linkage possible\n",
6888                            XYZ[0], XYZ[1], XYZ[2]);
6889                SUMA_free(XYZmap);
6890                SUMA_RETURN (NULL);
6891             }
6892             /* store iclosest for lazy user */
6893             *I_C = iclosest;
6894          }
6895    } else {
6896       iclosest = *I_C;
6897    }
6898 
6899    SUMA_LHv("Node identified for linking purposes is %d\n", *I_C);
6900    /* find the SO that is the Mappable cahuna */
6901    SOmapID = SUMA_findSO_inDOv(SO->LocalDomainParentID, dov, N_dov);
6902    if (SOmapID < 0) {
6903       SUMA_S_Err("Failed in SUMA_findSO_inDOv This should not happen.");
6904       SUMA_free(XYZmap);
6905       SUMA_RETURN (NULL);
6906    }
6907 
6908    SOmap = (SUMA_SurfaceObject *)(dov[SOmapID].OP);
6909    ND = SOmap->NodeDim;
6910    id = ND * iclosest;
6911    XYZmap[0]=SOmap->NodeList[id];
6912    XYZmap[1]=SOmap->NodeList[id+1];
6913    XYZmap[2]=SOmap->NodeList[id+2];
6914 
6915    /* all is done */
6916 
6917    SUMA_RETURN (XYZmap);
6918 }/* SUMA_XYZ_XYZmap */
6919 
6920 /*!
6921    transform  XYZmap to XYZ on current surface
6922 
6923    XYZ = SUMA_XYZmap_XYZ (XYZmap, SO, dov, N_dov, I_C, LDP_only);
6924 
6925    \param XYZmap (float *) XYZmap triplet in SO's MapRef coordinate space
6926    \param SO (SUMA_SurfaceObject *SO) obvious, ain't it
6927    \param dov (SUMA_DO*) vector containing all displayable objects
6928    \param N_dov (int) number of elements in dov
6929    \param I_C (int *) (pre allocated) pointer to the index of the closest
6930                   (or representative) node in SO's MapRef to the XYZmap location.
6931                   If you do not have it, make sure *I_C = -1.
6932                   If you do so, the function will search for nodes contained in
6933                   a box mm wide and centered on XYZmap.
6934                   If nodes are found in the box the I_C is set to the index of
6935                   the closest node and XYZ contains the coordinates of I_C in the
6936                   SO surface.
6937    \param LDP_only (int) if 1, XYZmap is set to XYZ only if SO is the LDP
6938                             0, XYZmap is set to XYZ is SO is LDP or AnatCorrect
6939    \ret XYZ (float *) Equivalent of XYZmap on the auxilliary surface SO.
6940                       NULL in case of trouble.
6941 
6942    \sa SUMA_XYZ_XYZmap
6943 */
6944 
SUMA_XYZmap_XYZ(float * XYZmap,SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_dov,int * I_C,int LDP_only)6945 float * SUMA_XYZmap_XYZ (float *XYZmap, SUMA_SurfaceObject *SO, SUMA_DO* dov,
6946                          int N_dov, int *I_C, int LDP_only)
6947 {/* SUMA_XYZmap_XYZ */
6948    static char FuncName[]={"SUMA_XYZmap_XYZ"};
6949    float *XYZ;
6950    int iclosest, id, ND;
6951    SUMA_SurfaceObject *SOmap;
6952    int SOmapID;
6953    SUMA_Boolean LocalHead = NOPE;
6954 
6955    SUMA_ENTRY;
6956 
6957    /* allocate for return */
6958    XYZ = (float *)SUMA_calloc (3, sizeof(float));
6959    if (XYZ == NULL) {
6960       fprintf(SUMA_STDERR,"Error %s: Could not allocate for XYZ.\n", FuncName);
6961       SUMA_RETURN (NULL);
6962    }
6963 
6964    /* if surface is not mappable, do the deed */
6965    if (!SUMA_ismappable(SO)){
6966       fprintf(SUMA_STDERR,"%s: Surface is NOT mappable, returning NULL.\n", FuncName);
6967       SUMA_free(XYZ);
6968       SUMA_RETURN (NULL);
6969    }
6970 
6971    /* if surface is a local domain parent, do the obivious */
6972    if (SUMA_isLocalDomainParent(SO)){
6973       SUMA_LH("Surface is a local domain parent. XYZ = XYZmap.\n");
6974       SUMA_COPY_VEC (XYZmap, XYZ, 3, float, float);
6975       SOmap = SO;
6976       /* do not return yet, must fix the node id too */
6977    } else if (!LDP_only && SO->AnatCorrect) {
6978       /* surface is anatomicall correct, use it */
6979       SUMA_LH("Surface is anatomically correct. XYZ = XYZmap.\n");
6980       SUMA_COPY_VEC (XYZmap, XYZ, 3, float, float);
6981       SOmap = SO;
6982       /* do not return yet, must fix the node id too */
6983    } else {
6984       /* surface is mappable, things will get more complicated */
6985       /* find the SO that is the Mappable cahuna */
6986       SOmapID = SUMA_findSO_inDOv(SO->LocalDomainParentID, dov, N_dov);
6987       if (SOmapID < 0) {
6988          SUMA_S_Err("Failed in SUMA_findSO_inDOv This should not happen.");
6989          SUMA_free(XYZ);
6990          SUMA_RETURN (NULL);
6991       }
6992       SOmap = (SUMA_SurfaceObject *)(dov[SOmapID].OP);
6993    }
6994    /* find the closest node in SO */
6995    if (*I_C < 0) { /* user has not specified closest node ID*/
6996       /* must find closest node on my own */
6997          {
6998             SUMA_ISINBOX IB;
6999             float Bd[3], distance;
7000             int ii;
7001 
7002             /* set the search box dimensions */
7003             Bd[0] = Bd[1] = Bd[2] = SUMA_XYZ_XFORM_BOXDIM_MM;
7004             IB = SUMA_isinbox (SOmap->NodeList, SOmap->N_Node, XYZmap, Bd,  YUP);
7005             SUMA_LHv("%d nodes (out of %d) found in box\n",
7006                      IB.nIsIn, SOmap->N_Node);
7007 
7008             if (IB.nIsIn) { /* found some, find the closest node */
7009                /* locate the closest node and store it's id in EngineData*/
7010                /*for (ii=0; ii<IB.nIsIn; ++ii) {
7011                   fprintf (SUMA_STDERR,"%d\t%.3f\t\t", IB.IsIn[ii], IB.d[ii]);
7012                }*/
7013                SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, distance, iclosest);
7014                iclosest = IB.IsIn[iclosest];
7015                /* get ridd of IB's vectors */
7016                if (!SUMA_Free_IsInBox (&IB)) {
7017                   fprintf(SUMA_STDERR,"Error %s: Failed to free IB\n", FuncName);
7018                }
7019 
7020             } else { /* no node is close enough */
7021                if (SO->AnatCorrect == NOPE && SO != SOmap) {
7022                               /* used to be if (SO != SOmap) only */
7023                   SUMA_SL_Warn(  "No node was close enough\n"
7024                                  "to XYZmap, no linkage possible."   );
7025                   SUMA_free(XYZ);
7026                   SUMA_RETURN (NULL);
7027                } else {
7028                   /* comes from inherrently mappable stuff, makes sense to
7029                      leave XYZ */
7030                   SUMA_SL_Warn(  "No node was close enough\n"
7031                                  "to XYZmap, linking by coordinate."   );
7032                   SUMA_COPY_VEC (XYZmap, XYZ, 3, float, float);
7033                   SUMA_RETURN (XYZ);
7034                }
7035             }
7036             /* store iclosest for lazy user */
7037             *I_C = iclosest;
7038          }
7039    } else {
7040       iclosest = *I_C;
7041    }
7042    SUMA_LHv("Node identified for linking purposes is %d\n", *I_C);
7043    ND = SO->NodeDim;
7044    id = ND * iclosest;
7045    XYZ[0]=SO->NodeList[id];
7046    XYZ[1]=SO->NodeList[id+1];
7047    XYZ[2]=SO->NodeList[id+2];
7048 
7049    /* all is done */
7050    SUMA_RETURN (XYZ);
7051 }/* SUMA_XYZmap_XYZ */
7052 
7053 /*!
7054    Prec_ID = SUMA_MapRefRelative (Cur_ID, Prec_List, N_Prec_List, dov);
7055    Returns the ID (index into dov) of the surface object in Prec_List that
7056    is related (via MapRef) to the surface object Cur_ID.
7057    This means that SOcur.LocalDomainParentID = SOprec.MapRef_icode_str or SOprec.idcode_str
7058 
7059    \param Cur_ID (int) index into dov of the current surface object
7060    \param Prec_List (int *) indices into dov of the precursor surface objects
7061    \param N_Prec_List (int) number of indices in Prec_List
7062    \param dov (SUMA_DO *) the vector of Displayable Object Structures
7063    \ret Prec_ID (int) index into dov of the surface object that is related
7064          to Cur_ID
7065 
7066 */
SUMA_MapRefRelative(int cur_id,int * prec_list,int N_prec_list,SUMA_DO * dov)7067 int SUMA_MapRefRelative (int cur_id, int *prec_list, int N_prec_list,
7068                          SUMA_DO *dov)
7069 {
7070    int i, rel_id = -1;
7071    static char FuncName[]={"SUMA_MapRefRelative"};
7072    SUMA_SurfaceObject *SOcur, *SO_prec;
7073 
7074    SUMA_ENTRY;
7075 
7076    if (!iDO_isSO(cur_id)) { /* not a surface, return */
7077       SUMA_RETURN(-1);
7078    }
7079 
7080    SOcur = (SUMA_SurfaceObject *)(dov[cur_id].OP);
7081    /* if surface has no MapRef then it cannot receive colors from precursors */
7082    if (!SUMA_ismappable(SOcur)) {
7083       SUMA_RETURN (-1);
7084    }
7085 
7086    for (i=0; i<N_prec_list; ++i) {
7087       if (iDO_isSO(prec_list[i])) {
7088          SO_prec = (SUMA_SurfaceObject *)(dov[prec_list[i]].OP);
7089 
7090          if (  SO_prec == SOcur ||
7091                strcmp(SOcur->idcode_str, SO_prec->idcode_str) == 0 ) {
7092             if (N_prec_list == 1) {
7093                /* if all you have is one surface in one state in SUMA
7094                   then you need not worry about the rest */
7095             } else {
7096                /* this can happen if you have multiple surfaces with each being
7097                   their own mappable surfaces., so it is OK too */
7098                /*
7099                   fprintf(SUMA_STDERR, "\nError %s: Flow problem.\n"
7100                                     "Did not expect identical surfaces \n"
7101                                     "in this condition (N_prec_list = %d)\n",
7102                                     FuncName, N_prec_list);
7103                SUMA_BEEP;
7104                */
7105             }
7106             /*
7107             I changed the next condition:
7108             if (  strcmp(SOcur->LocalDomainParentID,
7109                          SO_prec->LocalDomainParentID) == 0 ||
7110                strcmp(SOcur->LocalDomainParentID, SO_prec->idcode_str) == 0 )
7111             to
7112             if ( SUMA_isRelated_SO(SOcur, SO_prec, 1) )
7113             The two are the same except for the condition when the two surfaces
7114             are identical. So I put in a error message when that would happen and
7115             I'll deal with it then.
7116             ZSS Jan 08 04
7117             */
7118 
7119          }
7120 
7121          if ( SUMA_isRelated_SO(SOcur, SO_prec, 1) ) {
7122             /* Change made Jan 08 04, see note above */
7123             /* there's some relationship here, save it for return */
7124             if (rel_id < 0) {
7125                rel_id = prec_list[i];
7126             } else {
7127                fprintf (SUMA_STDERR,
7128                      "Error %s: I did not think that would occur!"
7129                      " Ignoring other relatives for now.\n", FuncName);
7130             }
7131 
7132          }
7133       }
7134    }
7135 
7136    SUMA_RETURN (rel_id);
7137 
7138 }
7139 
7140 /*!
7141    \brief creates a list of surfaces that are to be sent to AFNI
7142 */
SUMA_FormSOListToSendToAFNI(SUMA_DO * dov,int N_dov,int * N_Send)7143 int *SUMA_FormSOListToSendToAFNI(SUMA_DO *dov, int N_dov, int *N_Send)
7144 {
7145    static char FuncName[]={"SUMA_FormSOListToSendToAFNI"};
7146    int *SendList = NULL, ii, j, s, *is_listed=NULL;
7147    SUMA_SurfaceObject *SO=NULL;
7148    int no_need = 0;
7149    SUMA_SO_SIDE side=SUMA_NO_SIDE;
7150    SUMA_Boolean LocalHead = NOPE;
7151 
7152    SUMA_ENTRY;
7153 
7154    *N_Send = 0;
7155    SendList = (int *)SUMA_malloc(N_dov * sizeof(int));
7156    is_listed = (int *)SUMA_calloc(N_dov,  sizeof(int));
7157    if (!SendList || !is_listed) {
7158       SUMA_SL_Crit("Failed to allocate");
7159       SUMA_RETURN(SendList);
7160    }
7161 
7162 
7163    for (s=0;s<5; ++s) {
7164       for (ii=0; ii<N_dov; ++ii) {
7165          if (SUMA_isSO(dov[ii])) {
7166             SO = (SUMA_SurfaceObject *)(dov[ii].OP);
7167             if (SO->SentToAfni) { no_need = 1; }
7168             if (  SO->AnatCorrect && !SO->SentToAfni
7169                   && SO->VolPar ) {
7170                if (!SUMA_ExcludeFromSendToAfni(SO)) {
7171                   switch (s) {
7172                      case 0:
7173                         if (  !is_listed[ii] &&
7174                               SO->Side == SUMA_LEFT &&
7175                               SUMA_isTypicalSOforVolSurf(SO) ==  -1) {
7176                                  SendList[*N_Send] = ii;
7177                                  *N_Send = *N_Send + 1;
7178                                  is_listed[ii] = 1;}
7179                         break;
7180                      case 1:
7181                         if (  !is_listed[ii] &&
7182                               SO->Side == SUMA_LEFT &&
7183                               SUMA_isTypicalSOforVolSurf(SO) ==   1) {
7184                                  SendList[*N_Send] = ii;
7185                                  *N_Send = *N_Send + 1;
7186                                  is_listed[ii] = 1;}
7187                         break;
7188                      case 2:
7189                         if (  !is_listed[ii] &&
7190                               SO->Side == SUMA_RIGHT &&
7191                               SUMA_isTypicalSOforVolSurf(SO) == -1) {
7192                                  SendList[*N_Send] = ii;
7193                                  *N_Send = *N_Send + 1;
7194                                  is_listed[ii] = 1;}
7195                         break;
7196                      case 3:
7197                         if (  !is_listed[ii] &&
7198                               SO->Side == SUMA_RIGHT &&
7199                               SUMA_isTypicalSOforVolSurf(SO) ==  1) {
7200                                  SendList[*N_Send] = ii;
7201                                  *N_Send = *N_Send + 1;
7202                                  is_listed[ii] = 1;}
7203                         break;
7204                      default:
7205                         if (  !is_listed[ii]) {
7206                            SendList[*N_Send] = ii;
7207                            *N_Send = *N_Send + 1;
7208                            is_listed[ii] = 1;}
7209                         break;
7210                   }
7211                } else {
7212                   if (s == 0) {
7213                      SUMA_S_Notev(
7214                      "State %s not sent to AFNI per exclusion in env %s\n",
7215                      SO->State, "SUMA_DoNotSendStates");
7216                   }
7217                }
7218             }
7219          }
7220       }
7221    }
7222 
7223    if (*N_Send == 0 && !no_need) {
7224       /* an indication that nothing can be sent,
7225          as opposed things have been sent already
7226          and need not be resent */
7227       *N_Send = -1;
7228    }
7229    SUMA_RETURN(SendList);
7230 
7231 }
7232 
7233 
7234 
7235 /* get the output file for plugout info */
7236 static FILE *
SUMA_drive_get_outstream()7237 SUMA_drive_get_outstream()
7238 {
7239    char *suma_outfile;
7240 
7241    /* first time in set the output stream to stdout or environment variable */
7242    if(sumaout==NULL){
7243       /* get from environment variable if set */
7244       suma_outfile = my_getenv("SUMA_OUTPLUG");
7245       if(suma_outfile!=NULL) {
7246          SUMA_drive_set_outstream(suma_outfile);
7247       }
7248    }
7249 
7250    /* if still NULL output stream, set to default of stdout */
7251    if(sumaout==NULL) sumaout = stdout;
7252 
7253    return(sumaout);
7254 }
7255 
7256 /* set the output stream to a file rather than stdout*/
7257 static int
SUMA_drive_set_outstream(char * outfile)7258 SUMA_drive_set_outstream(char *outfile)
7259 {
7260    /* if just passed a NULL, reset output to stdout */
7261    if(outfile==NULL){
7262       sumaout = stdout;
7263       return(-1);
7264    }
7265 
7266    /* check if resetting to stdout by string from plugout command */
7267    if(strcmp(outfile, "stdout")==0) {
7268       sumaout = stdout;
7269       return 0;
7270    }
7271 
7272     /* make sure this file name is a good one, and open it for append */
7273    if( THD_filename_ok(outfile) )
7274       sumaout = fopen(outfile, "a");
7275 
7276    /* something went wrong, so tell user and reset to stdout */
7277    if(sumaout==NULL){
7278       fprintf(stderr, "**** couldn't open outfile, resetting to stdout\n");
7279       sumaout = stdout;
7280       return(-1);
7281    }
7282    else {
7283     return 0;
7284    }
7285 }
7286 
7287 
7288