1 #include "SUMA_suma.h"
2 #include "SUMA_plot.h"
3 #include "SUMA_clippingPlanes.h"
4 
5 #define SUMA_ALTHELL ( (Kev.state & Mod1Mask) || \
6                        (Kev.state & Mod2Mask) ||  \
7                        (Kev.state & SUMA_APPLE_AltOptMask) )
8 
9 /*!
10    Return the code for the key that is specified in keyin
11 */
SUMA_KeyPress(char * keyin,char * keynameback)12 int SUMA_KeyPress(char *keyin, char *keynameback)
13 {
14    static char FuncName[]={"SUMA_KeyPress"};
15    int nk=0,i=0,nc=0;
16    char keyname[100];
17    char *key=NULL, c='\0';
18    SUMA_Boolean LocalHead = NOPE;
19 
20    SUMA_ENTRY;
21 
22    if (keynameback) keynameback[0]='\0';
23    keyname[0]='\0';
24 
25    if (!keyin) SUMA_RETURN(XK_VoidSymbol);
26    nc = strlen(keyin);
27    if (nc<=0) SUMA_RETURN(XK_VoidSymbol);
28 
29    key = SUMA_append_string("+",keyin);  /* add a + to simplify parsing */
30 
31    nc = strlen(key);
32    SUMA_LHv("Key now '%s'\n", key);
33 
34    /* find the last + */
35    i = nc-2; /* skip last char, might itself be + */
36    while (i >= 0 && key[i] != '+') { --i; }  ++i; /* reposition past last + */
37 
38    /* copy the rest into keyname */
39    nk=0;
40    while (i<nc && nk < 10) {
41       keyname[nk] = key[i];
42       ++i;
43       ++nk;
44    }
45    keyname[nk] = '\0';
46    if (nk > 10 || nk == 0) {
47       SUMA_S_Errv("What kind of key is %s!!!\n", key);
48       SUMA_RETURN(XK_VoidSymbol);
49    }
50    SUMA_LHv("Keyname now '%s'\n", keyname);
51    if (keynameback) sprintf(keynameback,"%s", keyname);
52 
53    if (nk == 1) { /* the simple case, add them as needed */
54       c = keyname[0];
55       SUMA_LHv("c now '%c'\n", c);
56       switch(c) {
57          case '0':
58             SUMA_RETURN(XK_0);
59          case '1':
60             SUMA_RETURN(XK_1);
61          case '2':
62             SUMA_RETURN(XK_2);
63          case '3':
64             SUMA_RETURN(XK_3);
65          case '4':
66             SUMA_RETURN(XK_4);
67          case '5':
68             SUMA_RETURN(XK_5);
69          case '6':
70             SUMA_RETURN(XK_6);
71          case '7':
72             SUMA_RETURN(XK_7);
73          case '8':
74             SUMA_RETURN(XK_8);
75          case '9':
76             SUMA_RETURN(XK_9);
77          case 'a':
78             SUMA_RETURN(XK_a);
79          case 'A':
80             SUMA_RETURN(XK_A);
81          case 'b':
82             SUMA_RETURN(XK_b);
83          case 'B':
84             SUMA_RETURN(XK_B);
85          case 'C':
86             SUMA_RETURN(XK_C);
87          case 'c':
88             SUMA_RETURN(XK_c);
89          case 'd':
90             SUMA_RETURN(XK_d);
91          case 'D':
92             SUMA_RETURN(XK_D);
93          case 'f':
94             SUMA_RETURN(XK_f);
95          case 'F':
96             SUMA_RETURN(XK_F);
97          case 'g':
98             SUMA_RETURN(XK_g);
99          case 'G':
100             SUMA_RETURN(XK_G);
101          case 'h':
102             SUMA_RETURN(XK_h);
103          case 'H':
104             SUMA_RETURN(XK_H);
105          case 'j':
106             SUMA_RETURN(XK_j);
107          case 'J':
108             SUMA_RETURN(XK_J);
109          case 'l':
110             SUMA_RETURN(XK_l);
111          case 'L':
112             SUMA_RETURN(XK_L);
113          case 'm':
114             SUMA_RETURN(XK_m);
115          case 'M':
116             SUMA_RETURN(XK_M);
117          case 'n':
118             SUMA_RETURN(XK_n);
119          case 'N':
120             SUMA_RETURN(XK_N);
121          case 'o':
122             SUMA_RETURN(XK_o);
123          case 'O':
124             SUMA_RETURN(XK_O);
125          case 'p':
126             SUMA_RETURN(XK_p);
127          case 'P':
128             SUMA_RETURN(XK_P);
129          case 'r':
130             SUMA_RETURN(XK_r);
131          case 'R':
132             SUMA_RETURN(XK_R);
133          case 's':
134             SUMA_RETURN(XK_s);
135          case 'S':
136             SUMA_RETURN(XK_S);
137          case 't':
138             SUMA_RETURN(XK_t);
139          case 'T':
140             SUMA_RETURN(XK_T);
141          case 'u':
142             SUMA_RETURN(XK_u);
143          case 'U':
144             SUMA_RETURN(XK_U);
145          case 'w':
146             SUMA_RETURN(XK_w);
147          case 'W':
148             SUMA_RETURN(XK_W);
149          case 'z':
150             SUMA_RETURN(XK_z);
151          case 'Z':
152             SUMA_RETURN(XK_Z);
153          case '[':
154             SUMA_RETURN(XK_bracketleft);
155          case ']':
156             SUMA_RETURN(XK_bracketright);
157          case '.':
158             if (keynameback) sprintf(keynameback,"period");
159             SUMA_RETURN(XK_period);
160          case -15:
161             if (keynameback) sprintf(keynameback,"home");
162             SUMA_RETURN(XK_Home);
163          case ' ':
164             if (keynameback) sprintf(keynameback,"space");
165             SUMA_RETURN(XK_space);
166          case 27:
167             if (keynameback) sprintf(keynameback,"escape");
168             SUMA_RETURN(XK_Escape);
169          case '+':
170             SUMA_RETURN(XK_plus);
171          case '-':
172             SUMA_RETURN(XK_minus);
173          case '=':
174             SUMA_RETURN(XK_equal);
175          case '/':
176             SUMA_RETURN(XK_slash);
177          case '*':
178             SUMA_RETURN(XK_asterisk);
179          case '@':
180             SUMA_RETURN(XK_at);
181          case '(':
182             SUMA_RETURN(XK_parenleft);
183          case ',':
184             if (keynameback) sprintf(keynameback,"comma");
185             SUMA_RETURN(XK_comma);
186          default:
187             SUMA_S_Errv("Key '%c' not yet supported, complain to author.\n", c);
188             SUMA_RETURN(XK_VoidSymbol);
189       }
190    } else {
191       if (SUMA_iswordsame_ci(keyname,"up") == 1) SUMA_RETURN(XK_Up);
192       if (SUMA_iswordsame_ci(keyname,"down") == 1) SUMA_RETURN(XK_Down);
193       if (SUMA_iswordsame_ci(keyname,"left") == 1) SUMA_RETURN(XK_Left);
194       if (SUMA_iswordsame_ci(keyname,"right") == 1) SUMA_RETURN(XK_Right);
195       if (SUMA_iswordsame_ci(keyname,"space") == 1) SUMA_RETURN(XK_space);
196       if (SUMA_iswordsame_ci(keyname,"period") == 1) SUMA_RETURN(XK_period);
197       if (SUMA_iswordsame_ci(keyname,"comma") == 1) SUMA_RETURN(XK_comma);
198       if (SUMA_iswordsame_ci(keyname,"escape") == 1) SUMA_RETURN(XK_Escape);
199       if (SUMA_iswordsame_ci(keyname,"home") == 1) SUMA_RETURN(XK_Home);
200       if (SUMA_iswordsame_ci(keyname,"+") == 1) SUMA_RETURN(XK_plus);
201       if (SUMA_iswordsame_ci(keyname,"-") == 1) SUMA_RETURN(XK_minus);
202       if (SUMA_iswordsame_ci(keyname,"=") == 1) SUMA_RETURN(XK_equal);
203       if (SUMA_iswordsame_ci(keyname,"f1") == 1) SUMA_RETURN(XK_F1);
204       if (SUMA_iswordsame_ci(keyname,"f2") == 1) SUMA_RETURN(XK_F2);
205       if (SUMA_iswordsame_ci(keyname,"f3") == 1) SUMA_RETURN(XK_F3);
206       if (SUMA_iswordsame_ci(keyname,"f4") == 1) SUMA_RETURN(XK_F4);
207       if (SUMA_iswordsame_ci(keyname,"f5") == 1) SUMA_RETURN(XK_F5);
208       if (SUMA_iswordsame_ci(keyname,"f6") == 1) SUMA_RETURN(XK_F6);
209       if (SUMA_iswordsame_ci(keyname,"f7") == 1) SUMA_RETURN(XK_F7);
210       if (SUMA_iswordsame_ci(keyname,"f8") == 1) SUMA_RETURN(XK_F8);
211       if (SUMA_iswordsame_ci(keyname,"f9") == 1) SUMA_RETURN(XK_F9);
212       if (SUMA_iswordsame_ci(keyname,"f10") == 1) SUMA_RETURN(XK_F10);
213       if (SUMA_iswordsame_ci(keyname,"f11") == 1) SUMA_RETURN(XK_F11);
214       if (SUMA_iswordsame_ci(keyname,"f12") == 1) SUMA_RETURN(XK_F12);
215       if (SUMA_iswordsame_ci(keyname,"f13") == 1) SUMA_RETURN(XK_F13);
216 
217       SUMA_S_Errv("Key '%s' not yet supported, complain to author.\n", keyname);
218       SUMA_RETURN(XK_VoidSymbol);
219    }
220    SUMA_RETURN(XK_VoidSymbol);
221 }
222 
223 #define SUMA_KEY_COMMON {  \
224    if (!sv || !key) {   \
225       SUMA_S_Err("Null input");  \
226       SUMA_RETURN(0);  \
227    }  \
228    if (!(nc = strlen(key))) {    \
229       SUMA_S_Err("Empty key");   \
230       SUMA_RETURN(0);   \
231    }  \
232       \
233    SUMA_LHv("Have %s, nc=%d\n", key, nc); \
234    if ((k = SUMA_KeyPress(key, keyname)) == XK_VoidSymbol) {   \
235       SUMA_S_Errv("KeyPress for %s could not be obtained.\n", key);  \
236       SUMA_RETURN(0);  \
237    }  \
238    SUMA_LHv("Have keyname = %s\n", keyname); \
239    if (SUMA_iswordsame_ci(keyname,tk) != 1) {   \
240       SUMA_S_Errv("Expecting %s (or lower case version), got %s\n", \
241                   tk, keyname );  \
242       SUMA_RETURN(0);   \
243    }  \
244 }
245 
246 #define SUMA_KEY_SWITCH {  \
247    /* Check for key switching */ \
248    if (sv->State && strstr(sv->State, "GMATRIX")==sv->State) {  \
249       if (SUMA_SHIFT_KEY(key)) { \
250          strncpy(skeyi, key, 63); skeyi[64]='\0';  \
251          SUMA_wordswap_ci(skeyi, "shift", "", skey);  \
252       } else   \
253          snprintf(skey,63,"shift%s",key); \
254       key = skey; \
255    }  \
256 }
257 
258 
259 #if 0 /* a template to use for various keys , replace CHAR by upper case char and cHaR by lower case*/
260 int SUMA_CHAR_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
261 {
262    static char FuncName[]={"SUMA_CHAR_Key"};
263    char tk[]={"CHAR"}, keyname[100];
264    int k, nc;
265    SUMA_Boolean LocalHead = NOPE;
266 
267    SUMA_ENTRY;
268 
269    SUMA_KEY_COMMON;
270 
271    /* do the work */
272    switch (k) {
273       case XK_CHAR:
274          break;
275       case XK_cHaR:
276          break;
277       default:
278          SUMA_S_Err("Il ne faut pas ci dessous");
279          SUMA_RETURN(0);
280          break;
281    }
282 
283    SUMA_RETURN(1);
284 }
285 #endif
286 
SUMA_parenleft_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,Widget w,XtPointer clientData,XtPointer callData)287 int SUMA_parenleft_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode,
288     Widget w, XtPointer clientData, XtPointer callData)
289 {
290    static char FuncName[]={"SUMA_parenleft_Key"};
291    char tk[]={"("}, keyname[100];
292    int k, nc, i;
293    char stmp[200];
294    SUMA_Boolean LocalHead = NOPE;
295    GLfloat *glar_ColorList = NULL;
296 
297    SUMA_ENTRY;
298 
299    // fprintf(stderr, "%s\n", FuncName);
300 
301    SUMA_KEY_COMMON;
302 
303    // do the work
304    switch (k) {
305       case XK_parenleft:
306         if (SUMAg_CF->Dev) {
307            SUMA_SurfaceObject *SO;
308            SUMA_COLOR_MAP *CM;
309            SUMA_SCALE_TO_MAP_OPT * OptScl;
310            int MapType;
311            SUMA_COLOR_SCALED_VECT * SV;
312            float IntRange[2], *Vsort;
313            float * attr_sm;
314            float *Cx = NULL;
315 
316            fprintf(SUMA_STDOUT, "%s: Calculating convexity ...\n", FuncName);
317            if ((SO = SUMA_SV_Focus_SO(sv))) {
318               Cx = (float *)SUMA_GetCx(SO->idcode_str,
319                                        SUMAg_CF->DsetList, 0);
320               if (Cx) {
321                  SUMA_S_Err("Cx must be null prior to new assignment");
322                  break;
323               }
324               Cx = SUMA_Convexity   ( SO->NodeList, SO->N_Node,
325                                       SO->NodeNormList, SO->FN, NULL);
326               if (Cx == NULL) {
327                     fprintf(stderr,"Error %s: Failed in SUMA_Convexity\n",
328                                    FuncName);
329                     break;
330               }
331               /* smooth estimate twice */
332               attr_sm = SUMA_SmoothAttr_Neighb (Cx, SO->N_Node, NULL,
333                                                 SO->FN, 1, NULL, 1);
334               if (attr_sm == NULL) {
335                     fprintf(stderr,
336                             "Error %s: Failed in SUMA_SmoothAttr_Neighb\n",
337                             FuncName);
338                     break;
339               }
340               Cx = SUMA_SmoothAttr_Neighb (attr_sm, SO->N_Node, Cx,
341                                            SO->FN, 1, NULL, 1);
342               if (attr_sm) SUMA_free(attr_sm);
343 
344               fprintf( SUMA_STDOUT,
345                        "%s: Use SUMA_ScaleToMap to colorize Conv.txt "
346                        "and display it on surface.\n", FuncName);
347               CM = SUMA_FindNamedColMap ("ngray20");
348               if (CM == NULL) {
349                  fprintf (SUMA_STDERR,
350                           "Error %s: Could not get standard colormap.\n",
351                           FuncName);
352                  exit (1);
353               }
354 
355               /* get the options for creating the scaled color mapping */
356               OptScl = SUMA_ScaleToMapOptInit();
357               if (!OptScl) {
358                  SUMA_S_Err("Could not get scaling option structure.");
359                  exit (1);
360               }
361 
362               /* work the options a bit */
363               OptScl->ApplyClip = YUP;
364               IntRange[0] = 5; IntRange[1] = 95; /* percentile clip range*/
365               Vsort = SUMA_PercRange (Cx, NULL, SO->N_Node,
366                                       IntRange, IntRange, NULL);
367               OptScl->IntRange[0] = IntRange[0];
368               OptScl->IntRange[1] = IntRange[1];
369 
370               OptScl->BrightFact = 0.4;
371 
372               /* map the values in Cx to the colormap */
373                  /* allocate space for the result */
374                  SV = SUMA_Create_ColorScaledVect(SO->N_Node, 0);
375                  if (!SV) {
376                     fprintf (SUMA_STDERR,
377                              "Error %s: Could not allocate for SV.\n",
378                              FuncName);
379                     exit(1);
380                  }
381 
382                  /* finally ! */
383                  /*fprintf ( SUMA_STDERR,"%s: 1st color in map %f %f %f\n",
384                              FuncName,
385                              CM->M[0][0], CM->M[0][1],CM->M[0][2]);*/
386                  if (!SUMA_ScaleToMap (Cx, SO->N_Node, Vsort[0],
387                                       Vsort[SO->N_Node-1], CM, OptScl, SV)) {
388                     fprintf (SUMA_STDERR,
389                              "Error %s: Failed in SUMA_ScaleToMap.\n",
390                              FuncName);
391                     exit(1);
392                  }
393 
394                  /* Now place SV in the color array */
395                  glar_ColorList = SUMA_GetColorList (sv, SO->idcode_str);
396                  if (!glar_ColorList) {
397                     SUMA_S_Err("NULL glar_ColorList. BAD.");
398                     break;
399                  }
400                  SUMA_RGBvec_2_GLCOLAR4(SV->cV, glar_ColorList, SO->N_Node);
401 
402                  /* free */
403                  if (Vsort) SUMA_free(Vsort);
404                   if (OptScl) SUMA_free(OptScl);
405                  if (SV) SUMA_Free_ColorScaledVect (SV);
406                  if (Cx) {
407                     SUMA_free(Cx);
408                     Cx = NULL;
409                  }
410 
411               fprintf(SUMA_STDOUT, "%s: Convexity mapping done ...\n",
412                                    FuncName);
413               SUMA_postRedisplay(w, clientData, callData);
414            }
415         }
416         break;
417         default:
418          SUMA_S_Err("Il ne faut pas etre la");
419          SUMA_RETURN(0);
420          break;
421     }
422 
423    SUMA_RETURN(1);
424 }
425 
SUMA_at_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)426 int SUMA_at_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
427 {
428    static char FuncName[]={"SUMA_at_Key"};
429    char tk[]={"@"}, keyname[100];
430    int k, nc, i;
431    char stmp[200];
432    SUMA_Boolean LocalHead = NOPE;
433 
434    SUMA_ENTRY;
435 
436    // fprintf(stderr, "%s\n", FuncName);
437 
438    SUMA_KEY_COMMON;
439 
440    // do the work
441    switch (k) {
442       case XK_at:
443         if (SUMAg_CF->Dev) {
444            SUMA_SurfaceObject *SO=NULL;
445            /* calculate the curvature */
446            fprintf(SUMA_STDOUT,
447               "%s: Calculating surface curvature ...\n", FuncName);
448            if ((SO = SUMA_SV_Focus_SO(sv))){
449               if (!SO->PolyArea) {
450                  fprintf(SUMA_STDOUT,
451                           "%s: Computing required mesh area.\n", FuncName);
452                  if (!SUMA_SurfaceMetrics (SO, "PolyArea", NULL)) {
453                     fprintf (SUMA_STDERR,
454                              "Error %s: Failed in SUMA_SurfaceMetrics.\n",
455                              FuncName);
456                     break;
457                  }
458               }
459               SO->SC = SUMA_Surface_Curvature (SO->NodeList, SO->N_Node,
460                           SO->NodeNormList, SO->PolyArea,
461                           SO->N_FaceSet, SO->FN, SO->EL, "Curvs_c.txt", 1);
462               if (SO->SC == NULL) {
463                     fprintf( stderr,
464                              "Error %s: Failed in SUMA_Surface_Curvature\n",
465                              FuncName);
466                     break;
467                  }
468            }
469         }
470         break;
471         default:
472          SUMA_S_Err("Il ne faut pas etre la");
473          SUMA_RETURN(0);
474          break;
475     }
476 
477    SUMA_RETURN(1);
478 }
479 
SUMA_asterisk_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)480 int SUMA_asterisk_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
481 {
482    static char FuncName[]={"SUMA_asterisk_Key"};
483    char tk[]={"*"}, keyname[100];
484    int k, nc, i;
485    char stmp[200];
486    SUMA_Boolean LocalHead = NOPE;
487 
488    SUMA_ENTRY;
489 
490    // fprintf(stderr, "%s\n", FuncName);
491 
492    SUMA_KEY_COMMON;
493 
494    // do the work
495    switch (k) {
496       case XK_slash:
497          case XK_asterisk:
498         {
499            char stmp[100];
500            sprintf(stmp, "%d", SUMAg_CF->X->NumFinalSmoothing);
501            SUMAg_CF->X->N_FinalSmooth_prmpt =
502               SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
503                                 "Final color smoothing iterations",
504                                 stmp,
505                                 sv->X->TOPLEVEL, YUP,
506                                 SUMA_APPLY_BUTTON,
507                                 SUMA_SetNumFinalSmoothing, (void *)sv,
508                                 NULL, NULL,
509                                 NULL, NULL,
510                                 SUMA_CleanNumString, (void*)1,
511                                 SUMAg_CF->X->N_FinalSmooth_prmpt);
512 
513            SUMAg_CF->X->N_FinalSmooth_prmpt =
514                  SUMA_CreatePromptDialog("Final color smoothing iterations",
515                                          SUMAg_CF->X->N_FinalSmooth_prmpt);
516         }
517         break;
518         default:
519          SUMA_S_Err("Il ne faut pas etre la");
520          SUMA_RETURN(0);
521          break;
522     }
523 
524    SUMA_RETURN(1);
525 }
526 
SUMA_slash_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)527 int SUMA_slash_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
528 {
529    static char FuncName[]={"SUMA_slash_Key"};
530    char tk[]={"/"}, keyname[100];
531    int k, nc, i;
532    char stmp[200];
533    SUMA_Boolean LocalHead = NOPE;
534 
535    SUMA_ENTRY;
536 
537    // fprintf(stderr, "%s\n", FuncName);
538 
539    SUMA_KEY_COMMON;
540 
541    // do the work
542    switch (k) {
543       case XK_slash:
544             if (!list) list = SUMA_CreateList();
545             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
546             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FOVreset, SES_Suma, sv);
547             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
548             if (!SUMA_Engine (&list)) {
549                fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
550             }
551         break;
552         default:
553          SUMA_S_Err("Il ne faut pas etre la");
554          SUMA_RETURN(0);
555          break;
556    }
557 
558    SUMA_RETURN(1);
559 }
560 
SUMA_home_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)561 int SUMA_home_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
562 {
563    static char FuncName[]={"SUMA_home_Key"};
564    char tk[]={"home"}, keyname[100];
565    int k, nc, i;
566    char stmp[200];
567    SUMA_Boolean LocalHead = NOPE;
568 
569    SUMA_ENTRY;
570 
571    // fprintf(stderr, "%s\n", FuncName);
572 
573    SUMA_KEY_COMMON;
574 
575    // do the work
576    switch (k) {
577       case XK_Home:
578         if (!list) list = SUMA_CreateList();
579         SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
580         SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FOVreset, SES_Suma, sv);
581         SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
582         if (!SUMA_Engine (&list)) {
583            fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
584         }
585         break;
586         default:
587          SUMA_S_Err("Il ne faut pas etre la");
588          SUMA_RETURN(0);
589          break;
590    }
591 
592    SUMA_RETURN(1);
593 }
594 
SUMA_plus_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)595 int SUMA_plus_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
596 {
597    static char FuncName[]={"SUMA_plus_Key"};
598    char tk[]={"+"}, keyname[100];
599    int k, nc;
600    char stmp[200];
601    SUMA_Boolean LocalHead = NOPE;
602 
603    SUMA_ENTRY;
604 
605    // fprintf(stderr, "%s\n", FuncName);
606 
607    SUMA_KEY_COMMON;
608 
609    /* do the work */
610    switch (k) {
611       case XK_plus:
612             if (clippingPlaneMode && scrollInc < 999999){
613                 scrollInc *= 2.0;
614                 tiltInc *= 2.0;
615                 sv->clippingPlaneIncrement = scrollInc;
616                 SUMA_UpdateViewerTitle(sv);
617             }
618          break;
619       default:
620          SUMA_S_Err("Il ne faut pas etre la");
621          SUMA_RETURN(0);
622          break;
623    }
624 
625    SUMA_RETURN(1);
626 }
627 
SUMA_minus_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)628 int SUMA_minus_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
629 {
630    static char FuncName[]={"SUMA_minus_Key"};
631    char tk[]={"-"}, keyname[100];
632    int k, nc;
633    char stmp[200];
634    SUMA_Boolean LocalHead = NOPE;
635 
636    SUMA_ENTRY;
637 
638    // fprintf(stderr, "%s\n", FuncName);
639 
640    SUMA_KEY_COMMON;
641 
642    /* do the work */
643    switch (k) {
644       case XK_minus:
645         if (clippingPlaneMode){
646             scrollInc /= 2.0;
647             tiltInc /= 2.0;
648             sv->clippingPlaneIncrement = scrollInc;
649             SUMA_UpdateViewerTitle(sv);
650         }
651          break;
652       default:
653          SUMA_S_Err("Il ne faut pas etre la");
654          SUMA_RETURN(0);
655          break;
656    }
657 
658    SUMA_RETURN(1);
659 }
660 
SUMA_equal_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)661 int SUMA_equal_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
662 {
663    static char FuncName[]={"SUMA_equal_Key"};
664    char tk[]={"="}, keyname[100];
665    int k, nc;
666    char stmp[200];
667    SUMA_Boolean LocalHead = NOPE;
668 
669    SUMA_ENTRY;
670 
671    SUMA_KEY_COMMON;
672 
673    /* do the work */
674    switch (k) {
675       case XK_equal:
676         if (clippingPlaneMode){
677             scrollInc = 1.0;
678             tiltInc = 1.0;
679             sv->clippingPlaneIncrement = scrollInc;
680             SUMA_UpdateViewerTitle(sv);
681         }
682          break;
683       default:
684          SUMA_S_Err("Il ne faut pas etre la");
685          SUMA_RETURN(0);
686          break;
687    }
688 
689    SUMA_RETURN(1);
690 }
691 
692 
693 static int Nwarn_bracket = 0;
694 
SUMA_bracketleft_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)695 int SUMA_bracketleft_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
696 {
697    static char FuncName[]={"SUMA_bracketleft_Key"};
698    char tk[]={"["}, keyname[100];
699    int k, nc;
700    char stmp[200];
701    SUMA_Boolean LocalHead = NOPE;
702 
703    SUMA_ENTRY;
704 
705    // fprintf(stderr, "%s\n", FuncName);
706 
707    SUMA_KEY_COMMON;
708 
709    /* do the work */
710    switch (k) {
711       case XK_bracketleft:
712          /* getting rid of some warnings that happen with normal use */
713          Nwarn_bracket = 1; /* warning always in terminal, no message to window */
714          /* toggle showing left hemispheres */
715          sv->ShowLeft = !sv->ShowLeft;
716          /* do the axis setup */
717          SUMA_WorldAxisStandard (sv->WAx, sv);
718          SUMA_UpdateViewerTitle(sv);
719          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
720          if (sv->ShowLeft) {
721             sprintf(stmp,"Showing Left side%s",
722                Nwarn_bracket  ?
723       "":"\nFurther notices for '[' or ']' keys will be echoed in the shell");
724          } else {
725             sprintf(stmp,"Hiding Left side%s",
726                Nwarn_bracket > 1 ?
727       "":"\nFurther notices for '[' or ']' keys will be echoed in the shell");
728          }
729          if (!Nwarn_bracket && callmode &&
730                strcmp(callmode, "interactive") == 0) {
731             SUMA_SLP_Note("%s",stmp);
732          } else { SUMA_S_Note("%s",stmp); }
733 /*         ++Nwarn_bracket;*/
734          break;
735       default:
736          SUMA_S_Err("Il ne faut pas etre la");
737          SUMA_RETURN(0);
738          break;
739    }
740 
741    SUMA_RETURN(1);
742 }
743 
SUMA_bracketright_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)744 int SUMA_bracketright_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
745 {
746    static char FuncName[]={"SUMA_bracketright_Key"};
747    char tk[]={"]"}, keyname[100];
748    int k, nc;
749    char stmp[200];
750    SUMA_Boolean LocalHead = NOPE;
751 
752    SUMA_ENTRY;
753 
754    // fprintf(stderr, "%s\n", FuncName);
755 
756    SUMA_KEY_COMMON;
757 
758    /* do the work */
759    switch (k) {
760       case XK_bracketright:
761          /* getting rid of some warnings that happen with normal use */
762          Nwarn_bracket = 1; /* warning always in terminal, no message to window */
763          /* toggle showing left hemispheres */
764          sv->ShowRight = !sv->ShowRight;
765          /* do the axis setup */
766          SUMA_WorldAxisStandard (sv->WAx, sv);
767          SUMA_UpdateViewerTitle(sv);
768          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
769          if (sv->ShowRight) {
770             sprintf(stmp,"Showing Right side%s",
771                Nwarn_bracket ?
772             "":"\nFurther notices for '[' or ']' key will be in the shell");
773          } else {
774             sprintf(stmp,"Hiding right side%s",
775                Nwarn_bracket  ?
776             "":"\nFurther notices for '[' or ']' key will be in the shell");
777          }
778          if (!Nwarn_bracket && callmode &&
779                strcmp(callmode, "interactive") == 0) {
780             SUMA_SLP_Note("%s",stmp);
781          } else { SUMA_S_Note("%s",stmp); }
782 /*         ++Nwarn_bracket;*/
783          break;
784       default:
785          SUMA_S_Err("Il ne faut pas etre la");
786          SUMA_RETURN(0);
787          break;
788    }
789 
790    SUMA_RETURN(1);
791 }
792 
SUMA_escape_key(SUMA_SurfaceViewer * sv,char * key,char * callmode,Widget w,XtPointer clientData,XtPointer callData)793 int SUMA_escape_key(SUMA_SurfaceViewer *sv, char *key, char *callmode,
794     Widget w, XtPointer clientData, XtPointer callData)
795 {
796    static char FuncName[]={"SUMA_escape_key"};
797    char tk[]={"escape"}, keyname[100];
798    int k, nc;
799    int nxtstateID=-1, curstateID = -1;
800    int origState = -1, dov_ID = -1;
801    SUMA_SurfaceObject *SO = NULL, *SOmap = NULL;
802    SUMA_Boolean LocalHead = NOPE;
803 
804    SUMA_ENTRY;
805 
806    fprintf(stderr, "%s\n", FuncName);
807 
808 
809    SUMA_KEY_COMMON;
810 
811    origState = sv->iState;
812 
813    /* do the work */
814    switch (k) {
815       case XK_Escape:// there's more:
816                   // XK_BackSpace XK_Tab XK_Linefeed XK_Return XK_Delete
817             // control mask and escape is grabbed by gnome window manager ....
818             if (SUMA_SHIFT_KEY(key)){// kill all
819 
820                 fprintf(stderr, "Shift key \n", FuncName);
821                if( SUMAg_CF->X->WarnClose) {
822                   if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
823                            "Close All Viewers?", SUMA_YES,
824                            SWP_DONT_CARE) != SUMA_YES) {
825                      break;
826                   }
827                }
828                XtCloseDisplay( SUMAg_CF->X->DPY_controller1 ) ;
829                exit(0);
830             }else {
831                  fprintf(stderr, "No shift key \n", FuncName);
832               if( SUMAg_CF->X->WarnClose) {
833                   #ifdef DARWIN
834                      if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
835                                  "Close This Viewer?\n"
836                                  "OS-X users: If answering YES,\n"
837                                  "this prompt should not lie \n"
838                                  "over viewer to be closed.\n"
839                                  "Blame Bill Gates for this bug.",
840                                   SUMA_YES, SWP_TOP_RIGHT) != SUMA_YES) {
841                         break;
842                      }
843                   #else
844                      if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
845                                  "Close This Viewer?", SUMA_YES,
846                                  SWP_DONT_CARE) != SUMA_YES) {
847                         break;
848                      }
849                   #endif
850                }
851                SUMA_ButtClose_pushed (w, clientData, callData);
852             }
853         break;
854         default:
855          SUMA_S_Err("Il ne faut pas etre la");
856          SUMA_RETURN(0);
857          break;
858     }
859 
860    SUMA_RETURN(1);
861 }
862 
SUMA_space_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)863 int SUMA_space_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
864 {
865    static char FuncName[]={"SUMA_space_Key"};
866    char tk[]={"SPACE"}, keyname[100];
867    int k, nc;
868    int nxtstateID=-1, curstateID = -1;
869    int origState = -1, dov_ID = -1;
870    SUMA_SurfaceObject *SO = NULL, *SOmap = NULL;
871    SUMA_Boolean LocalHead = NOPE;
872 
873    SUMA_ENTRY;
874 
875    // fprintf(stderr, "%s\n", FuncName);
876 
877 
878    SUMA_KEY_COMMON;
879 
880    origState = sv->iState;
881 
882    /* do the work */
883    switch (k) {
884       case XK_space:
885          /* toggle between state containing mapping reference
886             of SO in focus and other view */
887 
888          /* make sure switching is OK */
889          curstateID = SUMA_WhichState(sv->State, sv, sv->CurGroupName);
890          if ((SO = SUMA_SV_Focus_SO(sv))) { /* have something to work with */
891             if (SUMA_isLocalDomainParent (SO)) {
892                /* get the last non mappable state in SV */
893                if (sv->LastNonMapStateID < 0) {
894                                        /* not recorded, complain and quit */
895                   fprintf(SUMA_STDERR,
896                           "Warning %s: Nothing defined to toggle with yet.\n",
897                           FuncName);
898                   break;
899                }
900 
901                if (LocalHead)
902                   fprintf (SUMA_STDERR,
903                            "%s: surface is inherrently mappable, "
904                            "switching to last non mappable state %d.\n",
905                            FuncName, sv->LastNonMapStateID);
906 
907                if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
908                                       sv->LastNonMapStateID, sv->CurGroupName)) {
909                   fprintf( SUMA_STDERR,
910                            "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
911                   break;
912                }
913 
914             } else if (!((SO->LocalDomainParentID) )) {
915                 fprintf(stderr, "Warning SUMA_space_Key: No default parent for surface object!\n");
916             } else {/* that's a non mappable, go to state containing reference */
917                if (LocalHead)
918                   fprintf (SUMA_STDERR,
919                            "%s: surface is not inherrently mappable, "
920                            "searching for mapping reference and its state.\n",
921                            FuncName);
922 
923                /* find SO that is mappable reference & get its state ID*/
924                fprintf(stderr, "SO=%p\n", SO);
925                fprintf(stderr, "SO->LocalDomainParentID=%s\n", SO->LocalDomainParentID);
926                fprintf(stderr, "SUMAg_DOv=%p\n", SUMAg_DOv);
927                fprintf(stderr, "SUMAg_N_DOv=%d\n", SUMAg_N_DOv);
928                dov_ID = SUMA_findSO_inDOv(SO->LocalDomainParentID, SUMAg_DOv,
929                                           SUMAg_N_DOv);
930                fprintf(stderr, "Okk 2\n");
931                SOmap = (SUMA_SurfaceObject *)SUMAg_DOv[dov_ID].OP;
932                nxtstateID = SUMA_WhichState(SOmap->State, sv, sv->CurGroupName);
933 
934                if (nxtstateID < 0) {
935                   fprintf (SUMA_STDERR,
936                            "%s: Failed in SUMA_findSO_inDOv "
937                            "This should not happen.\n", FuncName);
938                   break;
939                }
940 
941                if (LocalHead)
942                   fprintf (SUMA_STDERR,
943                            "%s: Found mapping reference in viewer state %d.\n",
944                            FuncName, nxtstateID);
945 
946                /* store this location */
947                sv->LastNonMapStateID = curstateID;
948 
949                /* go there */
950                if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
951                                        nxtstateID, sv->CurGroupName)) {
952                   fprintf( SUMA_STDERR,
953                            "Error %s: Failed in SUMA_SwitchState.\n",
954                            FuncName);
955                   break;
956                }
957             }
958 
959             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
960          } else {
961             SUMA_LH("No surfaces in this state, space bar ignored");
962          }
963          break;
964       default:
965          SUMA_S_Err("Il ne faut pas etre la");
966          SUMA_RETURN(0);
967          break;
968    }
969 
970    SUMA_RETURN(1);
971 }
972 
SUMA_comma_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)973 int SUMA_comma_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
974 {
975    static char FuncName[]={"SUMA_comma_Key"};
976    char tk[]={"COMMA"}, keyname[100], stmp[256];
977    int k, nc, ii;
978    int nxtstateID=-1, curstateID = -1;
979    int origState = -1;
980    char *note=NULL;
981    DList *list=NULL;
982    SUMA_Boolean LocalHead = NOPE;
983 
984    SUMA_ENTRY;
985 
986    // fprintf(stderr, "%s\n", FuncName);
987 
988    SUMA_KEY_COMMON;
989 
990    origState = sv->iState;
991 
992    /* do the work */
993    switch (k) {
994       case XK_comma:
995          /* switch state, back one */
996          if (sv->N_VSv < 2) break;
997 
998          curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
999          if (curstateID < 0) {
1000             SUMA_SL_Err("Current State not found.\n"
1001                         "Should not happen here.");
1002             SUMA_RETURN(0);
1003          }
1004 
1005          if (SUMAg_N_SVv > 1) {
1006             ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
1007             if (ii >= 0) {
1008                sprintf (stmp, "You cannot switch states while other viewers\n"
1009                               "(like viewer %c) in momentum mode.\n", ii+65);
1010                SUMA_RegisterMessage (SUMAg_CF->MessageList,
1011                                      stmp, FuncName, SMT_Error, SMA_LogAndPopup);
1012                SUMA_RETURN(0);
1013             }
1014          }
1015 
1016          do {
1017             if (LocalHead && nxtstateID > -1) {
1018                note = SUMA_append_string("Skipping state ",sv->State);
1019                note = SUMA_append_replace_string(note,
1020                                              ".\nNo surfaces visible.", "", 1);
1021                SUMA_SLP_Note("%s",note);
1022                SUMA_free(note);   note = NULL;
1023             }
1024 
1025             /*fprintf(SUMA_STDERR,"%s: Current viewing state is %s ...\n",
1026                       FuncName, sv->State);*/
1027             /* toggle to the next view state */
1028             nxtstateID = SUMA_PrevState(sv);
1029             if (nxtstateID == curstateID) break;
1030             if (nxtstateID < 0) {
1031                fprintf(SUMA_STDERR,
1032                        "Error %s: Failed in SUMA_PrevState.\n", FuncName);
1033                break;
1034             }
1035             fprintf( SUMA_STDERR,"%s: Switching from %s to %s viewing state.\n",
1036                      FuncName, sv->State, sv->VSv[nxtstateID].Name);
1037 
1038             if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
1039                                     nxtstateID, sv->CurGroupName)) {
1040                fprintf( SUMA_STDERR,
1041                         "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
1042                break;
1043             }
1044 
1045             /* find out if there are any surfaces that will be rendered */
1046 
1047          } while (!SUMA_Selectable_ADOs (sv, SUMAg_DOv, NULL) &&
1048                    sv->iState != origState);
1049 
1050          /* register a call to redisplay
1051             (you also need to copy the color data,
1052              in case the next surface is of the same family)*/
1053          if (!list) list = SUMA_CreateList();
1054          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1055          if (!SUMA_Engine (&list)) {
1056             fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1057          }
1058 
1059          /* update titles */
1060          SUMA_UpdateViewerTitle(sv);
1061          break;
1062       default:
1063          SUMA_S_Err("Il ne faut pas etre la");
1064          SUMA_RETURN(0);
1065          break;
1066    }
1067 
1068    SUMA_RETURN(1);
1069 }
1070 
SUMA_period_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1071 int SUMA_period_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1072 {
1073    static char FuncName[]={"SUMA_period_Key"};
1074    char tk[]={"PERIOD"}, keyname[100], stmp[256];
1075    int k, nc, ii;
1076    int nxtstateID=-1, curstateID = -1;
1077    int origState = -1;
1078    char *note=NULL;
1079    DList *list=NULL;
1080    SUMA_Boolean LocalHead = NOPE;
1081 
1082    SUMA_ENTRY;
1083 
1084    // fprintf(stderr, "%s\n", FuncName);
1085 
1086    SUMA_KEY_COMMON;
1087 
1088    origState = sv->iState;
1089 
1090    /* do the work */
1091    switch (k) {
1092       case XK_period:
1093          /* switch state, forward one */
1094          if (sv->N_VSv < 2) break;
1095 
1096          curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
1097          if (curstateID < 0) {
1098             SUMA_SL_Err("Current State not found.\n"
1099                         "Should not happen here.");
1100             SUMA_RETURN(0);
1101          }
1102 
1103          if (SUMAg_N_SVv > 1) {
1104             ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
1105             if (ii >= 0) {
1106                sprintf (stmp, "You cannot switch states while other viewers\n"
1107                               "(like viewer %c) are in momentum mode.\n", ii+65);
1108                SUMA_RegisterMessage (SUMAg_CF->MessageList,
1109                                      stmp, FuncName, SMT_Error, SMA_LogAndPopup);
1110                SUMA_RETURN(0);
1111             }
1112          }
1113 
1114          do {
1115             if (LocalHead && nxtstateID > -1) {
1116                note = SUMA_append_string("Skipping state ",sv->State);
1117                note = SUMA_append_replace_string(note,
1118                                           ".\nNo surfaces visible.", "", 1);
1119                SUMA_SLP_Note("%s",note);
1120                SUMA_free(note);   note = NULL;
1121             }
1122 
1123             if (LocalHead)
1124                fprintf(SUMA_STDERR,"%s: Current viewing state is %s ...\n",
1125                                     FuncName, sv->State);
1126 
1127             /* toggle to the next view state */
1128             nxtstateID = SUMA_NextState(sv);
1129             if (nxtstateID == curstateID) break;
1130             if (nxtstateID < 0) {
1131                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_NextState.\n",
1132                                     FuncName);
1133                break;
1134             }
1135 
1136             fprintf( SUMA_STDERR,
1137                      "%s: Switching from %s to %s viewing state.\n",
1138                      FuncName, sv->State, sv->VSv[nxtstateID].Name);
1139 
1140             if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
1141                                     nxtstateID, sv->CurGroupName)) {
1142                fprintf( SUMA_STDERR,
1143                         "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
1144                break;
1145             }
1146             SUMA_SET_AS_NEEDED_2D_VIEW_ANGLE(sv);
1147 
1148          } while (!SUMA_Selectable_ADOs(sv, SUMAg_DOv, NULL) &&
1149                    sv->iState != origState);
1150          /* register a call to redisplay
1151          (you also need to copy the color data, in case the next surface
1152           is of the same family)*/
1153          if (!list) list = SUMA_CreateList();
1154          SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
1155                                              SES_Suma, sv);
1156          if (!SUMA_Engine (&list)) {
1157             fprintf(stderr, "Error %s: SUMA_Engine call failed.\n",
1158                              FuncName);
1159          }
1160 
1161          /* update titles */
1162          SUMA_UpdateViewerTitle(sv);
1163          break;
1164       default:
1165          SUMA_S_Err("Il ne faut pas etre la");
1166          SUMA_RETURN(0);
1167          break;
1168    }
1169 
1170    SUMA_RETURN(1);
1171 }
1172 
SUMA_F1_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1173 int SUMA_F1_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1174 {
1175    static char FuncName[]={"SUMA_F1_Key"};
1176    char tk[]={"F1"}, keyname[100];
1177    int k, nc;
1178    SUMA_Boolean LocalHead = NOPE;
1179 
1180    SUMA_ENTRY;
1181 
1182    // fprintf(stderr, "%s\n", FuncName);
1183 
1184    SUMA_KEY_COMMON;
1185 
1186    /* do the work */
1187    switch (k) {
1188       case XK_F1:
1189          sv->ShowEyeAxis = !sv->ShowEyeAxis;
1190          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1191          break;
1192       default:
1193          SUMA_S_Err("Il ne faut pas etre la");
1194          SUMA_RETURN(0);
1195          break;
1196    }
1197 
1198    SUMA_RETURN(1);
1199 }
1200 
SUMA_F2_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1201 int SUMA_F2_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1202 {
1203    static char FuncName[]={"SUMA_F2_Key"};
1204    char tk[]={"F2"}, keyname[100];
1205    int k, nc;
1206    SUMA_Boolean LocalHead = NOPE;
1207 
1208    SUMA_ENTRY;
1209 
1210    // fprintf(stderr, "%s\n", FuncName);
1211 
1212    SUMA_KEY_COMMON;
1213 
1214    /* do the work */
1215    switch (k) {
1216       case XK_F2:
1217          {
1218             int *do_id, n_do_id;
1219             ++sv->ShowWorldAxis;
1220             sv->ShowWorldAxis = sv->ShowWorldAxis % SUMA_N_WAX_OPTIONS;
1221             sv->ShowMeshAxis = 0;
1222                /* used to be = !sv->ShowMeshAxis; ,
1223                   Turned off Oct 15 04 , in favor or WorldAxis */
1224             do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv, SO_type, &n_do_id);
1225             if (n_do_id) {
1226                while (n_do_id) {
1227                  ((SUMA_SurfaceObject *)
1228                      SUMAg_DOv[do_id[n_do_id-1]].OP)->ShowMeshAxis =
1229                            sv->ShowMeshAxis;
1230                   --n_do_id;
1231                }
1232                SUMA_free(do_id);
1233             }
1234          }
1235          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1236          break;
1237       default:
1238          SUMA_S_Err("Il ne faut pas etre la haut");
1239          SUMA_RETURN(0);
1240          break;
1241    }
1242 
1243    SUMA_RETURN(1);
1244 }
1245 
SUMA_F3_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1246 int SUMA_F3_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1247 {
1248    static char FuncName[]={"SUMA_F3_Key"};
1249    char tk[]={"F3"}, keyname[100];
1250    int k, nc;
1251    SUMA_EngineData *ED = NULL;
1252    DList *list = NULL;
1253    SUMA_Boolean LocalHead = NOPE;
1254 
1255    SUMA_ENTRY;
1256 
1257    // fprintf(stderr, "%s\n", FuncName);
1258 
1259    SUMA_KEY_COMMON;
1260 
1261    /* do the work */
1262    switch (k) {
1263       case XK_F3:
1264          if (!list) list = SUMA_CreateList();
1265          SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_ToggleCrossHair,
1266                                              SES_Suma, sv);
1267          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1268          if (!SUMA_Engine (&list)) {
1269                fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1270          }
1271          break;
1272       default:
1273          SUMA_S_Err("Il ne faut pas etre over here");
1274          SUMA_RETURN(0);
1275          break;
1276    }
1277 
1278    SUMA_RETURN(1);
1279 }
1280 
SUMA_F4_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1281 int SUMA_F4_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1282 {
1283    static char FuncName[]={"SUMA_F4_Key"};
1284    char tk[]={"F4"}, keyname[100];
1285    int k, nc;
1286    SUMA_EngineData *ED = NULL;
1287    DList *list = NULL;
1288    DListElmt *NextElm= NULL;
1289    SUMA_Boolean LocalHead = NOPE;
1290 
1291    SUMA_ENTRY;
1292 
1293    // fprintf(stderr, "%s\n", FuncName);
1294 
1295    SUMA_KEY_COMMON;
1296 
1297    /* do the work */
1298    switch (k) {
1299       case XK_F4:
1300          if (!list) list = SUMA_CreateList();
1301          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleShowSelectedNode,
1302                                              SES_Suma, sv);
1303          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1304          if (!SUMA_Engine (&list)) {
1305                fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1306          }
1307          break;
1308       default:
1309          SUMA_S_Err("Il ne faut pas etre over dort");
1310          SUMA_RETURN(0);
1311          break;
1312    }
1313 
1314    SUMA_RETURN(1);
1315 }
1316 
SUMA_F5_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1317 int SUMA_F5_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1318 {
1319    static char FuncName[]={"SUMA_F5_Key"};
1320    char tk[]={"F5"}, keyname[100];
1321    int k, nc;
1322    SUMA_EngineData *ED = NULL;
1323    DList *list = NULL;
1324    DListElmt *NextElm= NULL;
1325    SUMA_Boolean LocalHead = NOPE;
1326 
1327    SUMA_ENTRY;
1328 
1329    // fprintf(stderr, "%s\n", FuncName);
1330 
1331    SUMA_KEY_COMMON;
1332 
1333    /* do the work */
1334    switch (k) {
1335       case XK_F5:
1336          if (!list) list = SUMA_CreateList();
1337          SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_ToggleShowSelectedFaceSet,
1338                                              SES_Suma, sv);
1339          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1340          if (!SUMA_Engine (&list)) {
1341                fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1342          }
1343          break;
1344       default:
1345          SUMA_S_Err("Il ne faut pas etre over dort");
1346          SUMA_RETURN(0);
1347          break;
1348    }
1349 
1350    SUMA_RETURN(1);
1351 }
1352 
SUMA_F6_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1353 int SUMA_F6_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1354 {
1355    static char FuncName[]={"SUMA_F6_Key"};
1356    char tk[]={"F6"}, keyname[100];
1357    int k, nc;
1358    SUMA_EngineData *ED = NULL;
1359    DList *list = NULL;
1360    DListElmt *NextElm= NULL;
1361    SUMA_Boolean LocalHead = NOPE;
1362 
1363    SUMA_ENTRY;
1364 
1365    // fprintf(stderr, "%s\n", FuncName);
1366 
1367    SUMA_KEY_COMMON;
1368 
1369    /* do the work */
1370    switch (k) {
1371       case XK_F6:
1372          sv->clear_color[0] = 1 - sv->clear_color[0];
1373          sv->clear_color[1] = 1 - sv->clear_color[1];
1374          sv->clear_color[2] = 1 - sv->clear_color[2];
1375 
1376          SUMA_UpdateCrossHairNodeLabelField(sv);
1377          if (!list) list = SUMA_CreateList();
1378          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1379          if (!SUMA_Engine (&list)) {
1380                fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1381          }
1382          break;
1383       default:
1384          SUMA_S_Err("Il ne faut pas etre over dere");
1385          SUMA_RETURN(0);
1386          break;
1387    }
1388 
1389    SUMA_RETURN(1);
1390 }
SUMA_F7_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1391 int SUMA_F7_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1392 {
1393    static char FuncName[]={"SUMA_F7_Key"};
1394    char tk[]={"F7"}, keyname[100];
1395    int k, nc;
1396    SUMA_EngineData *ED = NULL;
1397    DList *list = NULL;
1398    DListElmt *NextElm= NULL;
1399    SUMA_Boolean LocalHead = NOPE;
1400 
1401    SUMA_ENTRY;
1402 
1403    // fprintf(stderr, "%s\n", FuncName);
1404 
1405    SUMA_KEY_COMMON;
1406 
1407    /* do the work */
1408    switch (k) {
1409       case XK_F7:
1410          ++SUMAg_CF->ColMixMode;
1411          if (SUMAg_CF->ColMixMode >= SUMA_MAX_MODES) {
1412             SUMAg_CF->ColMixMode = SUMA_ORIG_MIX_MODE;
1413          }
1414          {
1415             char stmp[200];
1416             sprintf(stmp,"Using %s color mixing mode.",
1417                      SUMA_ColMixModeString(SUMAg_CF->ColMixMode));
1418             if (callmode && strcmp(callmode, "interactive") == 0) {
1419                   SUMA_SLP_Note("%s",stmp); }
1420             else { SUMA_S_Note("%s",stmp); }
1421          }
1422 
1423          SUMA_SetAllRemixFlag (SUMAg_SVv, SUMAg_N_SVv);
1424 
1425          if (!list) list = SUMA_CreateList();
1426          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible,
1427                                             SES_Suma, NULL);
1428          if (!SUMA_Engine (&list)) {
1429                fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1430          }
1431          break;
1432       default:
1433          SUMA_S_Err("Il ne faut pas etre over yonder");
1434          SUMA_RETURN(0);
1435          break;
1436    }
1437 
1438    SUMA_RETURN(1);
1439 }
1440 
SUMA_F8_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1441 int SUMA_F8_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1442 {
1443    static char FuncName[]={"SUMA_F8_Key"};
1444    char tk[]={"F8"}, keyname[100];
1445    int k, nc;
1446    SUMA_EngineData *ED = NULL;
1447    DList *list = NULL;
1448    DListElmt *NextElm= NULL;
1449    SUMA_Boolean LocalHead = NOPE;
1450 
1451    SUMA_ENTRY;
1452 
1453    // fprintf(stderr, "%s\n", FuncName);
1454 
1455    SUMA_KEY_COMMON;
1456 
1457    /* do the work */
1458    switch (k) {
1459       case XK_F8:
1460          sv->ortho = !sv->ortho;
1461          {
1462             static int inote = 0;
1463             char stmp[200];
1464             if (sv->ortho) {
1465                sprintf(stmp,"Using orthographic projection viewing");
1466                sv->FOV[sv->iState] = sv->FOV[sv->iState] / 2.0;
1467             } else {
1468                sprintf(stmp,"Using perspective viewing");
1469                sv->FOV[sv->iState] = sv->FOV[sv->iState] * 2.0;
1470             }
1471             ++inote;
1472             if (callmode && strcmp(callmode, "interactive") == 0 && inote < 3) {
1473                   SUMA_SLP_Note("%s",stmp); }
1474             else { SUMA_S_Note("%s",stmp); }
1475          }
1476 
1477          SUMA_SET_GL_PROJECTION(sv, sv->ortho);
1478          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1479          break;
1480       default:
1481          SUMA_S_Err("Il ne faut pas etre over yonder");
1482          SUMA_RETURN(0);
1483          break;
1484    }
1485 
1486    SUMA_RETURN(1);
1487 }
1488 
SUMA_F9_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1489 int SUMA_F9_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1490 {
1491    static char FuncName[]={"SUMA_F9_Key"};
1492    char tk[]={"F9"}, keyname[100];
1493    int k, nc;
1494    SUMA_EngineData *ED = NULL;
1495    DList *list = NULL;
1496    DListElmt *NextElm= NULL;
1497    static int inote = 0;
1498    SUMA_Boolean LocalHead = NOPE;
1499 
1500    SUMA_ENTRY;
1501 
1502    // fprintf(stderr, "%s\n", FuncName);
1503 
1504    SUMA_KEY_COMMON;
1505 
1506    /* do the work */
1507    switch (k) {
1508       case XK_F9:
1509          sv->ShowLabelAtXhair = !sv->ShowLabelAtXhair;
1510          SUMA_UpdateCrossHairNodeLabelField(sv);
1511          {
1512             char stmp[200];
1513             if (sv->ShowLabelAtXhair) {
1514                sprintf(stmp,"Showing Label At Xhair");
1515             } else {
1516                sprintf(stmp,"Hiding Label At Xhair");
1517             }
1518             if (callmode && strcmp(callmode, "interactive") == 0 && inote < 2) {
1519                SUMA_SLP_Note("%s",stmp); ++inote;}
1520             else { SUMA_S_Note("%s",stmp); }
1521          }
1522          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1523          break;
1524       default:
1525          SUMA_S_Err("Il ne faut pas etre hawn");
1526          SUMA_RETURN(0);
1527          break;
1528    }
1529 
1530    SUMA_RETURN(1);
1531 }
1532 
SUMA_F10_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)1533 int SUMA_F10_Key(SUMA_SurfaceViewer *sv,char *key, char *callmode, char *strgval)
1534 {
1535    static char FuncName[]={"SUMA_F10_Key"};
1536    char tk[]={"F10"}, keyname[100];
1537    int k, nc;
1538    SUMA_EngineData *ED = NULL;
1539    DList *list = NULL;
1540    DListElmt *NextElm= NULL;
1541    static int inote = 0;
1542    SUMA_Boolean LocalHead = NOPE;
1543 
1544    SUMA_ENTRY;
1545 
1546    // fprintf(stderr, "%s\n", FuncName);
1547 
1548    SUMA_KEY_COMMON;
1549 
1550    /* do the work */
1551    switch (k) {
1552       case XK_F10:
1553          if (sv->PryAx == 2) sv->PryAx = 3;
1554          else if (sv->PryAx == 3) sv->PryAx = 2;
1555          else {
1556             SUMA_S_Err("Bad PryAx of %d. Reverting to 3", sv->PryAx);
1557             sv->PryAx = 3;
1558          }
1559          {
1560             char stmp[200];
1561             if (sv->PryAx == 3) {
1562                sprintf(stmp,"Prying about Z axis");
1563             } else {
1564                sprintf(stmp,"Prying about Y axis");
1565             }
1566             if (callmode && strcmp(callmode, "interactive") == 0 && inote < 2) {
1567                SUMA_SLP_Note("%s",stmp); ++inote;}
1568             else { SUMA_S_Note("%s",stmp); }
1569          }
1570          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1571          break;
1572       default:
1573          SUMA_S_Err("Il ne faut pas etre la dessous");
1574          SUMA_RETURN(0);
1575          break;
1576    }
1577 
1578    SUMA_RETURN(1);
1579 }
1580 
SUMA_F11_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)1581 int SUMA_F11_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode,
1582                  char *strgval)
1583 {
1584    static char FuncName[]={"SUMA_F11_Key"};
1585    char tk[]={"F11"}, keyname[100];
1586    int k, nc;
1587    SUMA_EngineData *ED = NULL;
1588    DList *list = NULL;
1589    DListElmt *NextElm= NULL;
1590    static int inote = 0;
1591    SUMA_Boolean LocalHead = NOPE;
1592 
1593    SUMA_ENTRY;
1594 
1595    // fprintf(stderr, "%s\n", FuncName);
1596 
1597    SUMA_KEY_COMMON;
1598 
1599    /* do the work */
1600    switch (k) {
1601       case XK_F11: {
1602          if ( (callmode && strcmp(callmode, "interactive") == 0) ||
1603              !strgval /* why not? this way the
1604                         Driver can pop the interactive window */) {
1605             sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialogStruct(
1606                                  SUMA_OK_APPLY_CLEAR_CANCEL,
1607                             "Set Object Display Order:\n"
1608                             "(e.g. VSG for: Volume, Surface, Graph)):",
1609                                  "VSG",
1610                                  sv->X->TOPLEVEL, YUP,
1611                                  SUMA_APPLY_BUTTON,
1612                                  SUMA_SV_SetRenderOrder, (void *)sv,
1613                                  NULL, NULL,
1614                                  NULL, NULL,
1615                                  SUMA_VerifyRenderOrder, NULL,
1616                                  sv->X->SetRenderOrder_prmpt);
1617 
1618             sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialog(
1619                               sv->X->Title, sv->X->SetRenderOrder_prmpt);
1620          } else {
1621             if (!strgval) {
1622                SUMA_S_Err("Have NULL string");
1623                SUMA_RETURN(0);
1624             }
1625             SUMA_SV_SetRenderOrder(strgval, (void *)sv);
1626          }
1627          break; }
1628       default:
1629          SUMA_S_Err("Il ne faut pas etre hawn");
1630          SUMA_RETURN(0);
1631          break;
1632    }
1633 
1634    SUMA_RETURN(1);
1635 }
1636 
SUMA_F12_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1637 int SUMA_F12_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1638 {
1639    static char FuncName[]={"SUMA_F12_Key"};
1640    char tk[]={"F12"}, keyname[100];
1641    int k, nc;
1642    SUMA_EngineData *ED = NULL;
1643    DList *list = NULL;
1644    DListElmt *NextElm= NULL;
1645    static int inote = 0;
1646    SUMA_Boolean LocalHead = NOPE;
1647 
1648    SUMA_ENTRY;
1649 
1650    // fprintf(stderr, "%s\n", FuncName);
1651 
1652    SUMA_KEY_COMMON;
1653 
1654    /* do the work */
1655    switch (k) {
1656       case XK_F12:
1657          {
1658             /* time display speed */
1659             int i, nd = 20, N_vis, *Vis_IDs=NULL, NodeTot, FaceTot;
1660             GLfloat buf;
1661             float delta_t;
1662             SUMA_SurfaceObject *SO=NULL;
1663             struct  timeval tti;
1664             char stmp[500], fnameout[]={"__SUMA.speedtest.txt"};
1665             SUMA_STRING *SS = NULL;
1666             FILE *fout=NULL;
1667 
1668             if (callmode && !strcmp(callmode, "drivesuma")) {
1669                fout = fopen(fnameout,"w");
1670             }
1671             SS = SUMA_StringAppend (NULL, NULL);
1672 
1673             buf = sv->light0_position[2];
1674             if (callmode && strcmp(callmode, "interactive") == 0) {
1675                SUMA_SLP_Note ("Timing Display speed\n"
1676                               "(20 displays): \n");
1677             } else {
1678                SUMA_S_Note("Timing Display speed\n"
1679                            "(20 displays): \n");
1680             }
1681             if (fout) fprintf(fout, "Timing Display speed (20 displays):\n");
1682 
1683             SUMA_etime (&tti, 0);
1684             for (i=0; i< nd-1; ++i) {
1685                fprintf (SUMA_STDOUT,"%d\t", i); fflush (SUMA_STDOUT);
1686                sv->light0_position[2] *= -1;
1687                glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
1688                /* direct call to display */
1689                SUMA_display(sv, SUMAg_DOv);
1690                /* wait for display */
1691                glFinish();
1692             }
1693             fprintf (SUMA_STDOUT,"\n");
1694             delta_t = SUMA_etime (&tti, 1);
1695             sv->light0_position[2] = buf;
1696             glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
1697             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1698             sprintf (stmp,
1699                      "Elapsed time: %f seconds.\n%.2f displays/second.\n",
1700                      delta_t, nd/delta_t);
1701             SS = SUMA_StringAppend (SS, stmp);
1702 
1703             /* Estimate how many nodes and triangles were rendered */
1704             Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
1705             N_vis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs, 0);
1706             NodeTot = 0;
1707             FaceTot = 0;
1708             for (i=0; i<N_vis;++i) {
1709                SO = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[i]].OP;
1710                FaceTot += SO->N_FaceSet;
1711                NodeTot += SO->N_Node;
1712             }
1713             if (N_vis) {
1714                sprintf (stmp, "In Polymode %d, rendered \n"
1715                               "%.2f Ktri/sec %.2f Kpnt/sec.\n",
1716                   sv->PolyMode,
1717                   (float)FaceTot / 1000.0 / delta_t  ,
1718                   (float)NodeTot / 1000.0 / delta_t );
1719                SS = SUMA_StringAppend (SS, stmp);
1720             }
1721 
1722             if (callmode && strcmp(callmode, "interactive") == 0) {
1723                SUMA_SLP_Note("%s",SS->s);
1724             } else {
1725                SUMA_S_Note("%s",SS->s);
1726             }
1727 
1728             if (fout) {
1729                fprintf(fout, "%s\n", SS->s);
1730                SUMA_S_Note("Timing results written to file: %s", fnameout);
1731                fclose(fout);
1732             }
1733 
1734             if (Vis_IDs) SUMA_free(Vis_IDs);
1735             SUMA_free(SS->s);
1736             SUMA_free(SS);
1737          }
1738          break;
1739       default:
1740          SUMA_S_Err("Il ne faut pas etre hawn");
1741          SUMA_RETURN(0);
1742          break;
1743    }
1744 
1745    SUMA_RETURN(1);
1746 }
1747 
SUMA_F13_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1748 int SUMA_F13_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1749 {
1750    static char FuncName[]={"SUMA_F13_Key"};
1751    char tk[]={"F13"}, keyname[100];
1752    int k, nc;
1753    SUMA_EngineData *ED = NULL;
1754    DList *list = NULL;
1755    DListElmt *NextElm= NULL;
1756    static int inote = 0;
1757    SUMA_Boolean LocalHead = NOPE;
1758 
1759    SUMA_ENTRY;
1760 
1761    // fprintf(stderr, "%s\n", FuncName);
1762 
1763    SUMA_KEY_COMMON;
1764 
1765    /* do the work */
1766    switch (k) {
1767       case XK_F13:
1768         {
1769             if (SUMAg_CF->Dev) {
1770                DList *striplist=NULL;
1771                float Eq[4];
1772                int *Vis_IDs, N_vis;
1773                SUMA_SurfaceObject *SO=NULL;
1774                Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
1775                N_vis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs, 0);
1776                if (N_vis) {
1777                   SO = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[0]].OP;
1778                   /* Axial plane */
1779                   Eq[0] = Eq[1] = 0.0; Eq[2] = 1.0; Eq[3] = -SO->Center[2];
1780                   SUMA_S_Warnv("Kill me!\nEq:[%f %f %f %f], step: %f\n",
1781                                  Eq[0], Eq[1], Eq[2], Eq[3], SO->EL->AvgLe);
1782                   striplist = SUMA_SliceAlongPlane(SO, Eq, SO->EL->AvgLe);
1783                   SUMA_display_edge_striplist(striplist, &(SUMAg_SVv[0]), SO,
1784                                              "ShowConnectedPoints");
1785                   SUMA_FREE_DLIST(striplist);
1786                }
1787                if (Vis_IDs) SUMA_free(Vis_IDs);
1788             }
1789         }
1790         break;
1791         default:
1792          SUMA_S_Err("Il ne faut pas etre la");
1793          SUMA_RETURN(0);
1794          break;
1795     }
1796 
1797    SUMA_RETURN(1);
1798 }
1799 
1800 
SUMA_Numeral_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1801 int SUMA_Numeral_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1802 {
1803    static char FuncName[]={"SUMA_Numeral_Key"};
1804    char tk[]={"0"}, keyname[100];
1805    int k, nc, i, isv;
1806    SUMA_EngineData *ED = NULL;
1807    DList *list = NULL;
1808    DListElmt *NextElm= NULL;
1809    SUMA_Boolean LocalHead = NOPE;
1810    Widget w = NULL;
1811    XKeyEvent Kev;
1812    static  previouslySelectedPlane;
1813 
1814    SUMA_ENTRY;
1815 
1816    SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
1817 
1818    k = SUMA_KeyPress(key, NULL);
1819 
1820    // Verbose output
1821    if (clippingPlaneMode && SUMAg_CF->clippingPlaneVerbose){
1822        switch (k){
1823            case 0x0030:
1824                fprintf(stderr, "### Reset clipping planes\n");
1825                break;
1826            case 0x0037:
1827                fprintf(stderr, "### Toggle all active clipping planes on/off\n");
1828                break;
1829            case 0x0038:
1830            case 0x0039:
1831                fprintf(stderr, "WARNING: No clipping plane %d\n", k-0x0030);
1832                break;
1833            default:
1834                fprintf(stderr, "### %s clipping plane %d\n",
1835                 (SUMA_CTRL_KEY(key))? "Select" : "Toggle", k-0x0030);
1836        }
1837    }
1838 
1839    /* do the work */
1840    switch (k) {
1841     case XK_0:
1842         if (clippingPlaneMode){
1843             clipPlaneTransform(0,0,0,0,0, 0, 1);
1844             resetClippingPlanes = 1;
1845             for (i=0; i<SUMAg_CF->N_ClipPlanes; ++i){
1846                 active[i] = (i>0);
1847                 clipPlaneTransform(0,0,0,0,i, 1, 0);
1848             }
1849             clipPlaneTransform(0,0,0,0,0, 0, 0);     // Select clipping plane 1
1850             lightenActiveClipPlaneSquare(0);        // Lighten plane 1 to show it's selected
1851 
1852             // Required to lighten plane mode in DriveSuma mode but not in interactive mode
1853             clipPlaneTransform(0,0,0,0,0, 0, 0);     // Select clipping plane 1
1854             lightenActiveClipPlaneSquare(0);        // Lighten plane 1 to show it's selected
1855         }
1856      break;
1857     case XK_1:
1858         if (clippingPlaneMode){
1859             if (SUMA_CTRL_KEY(key)){
1860                 clipPlaneTransform(0,0,0,0,0, 0, 0);     // Select clipping plane 1
1861                 lightenActiveClipPlaneSquare(0);
1862                 darkenInactiveClipPlaneSquares(0);
1863             } else if (SUMAg_CF->N_ClipPlanes>=1){    // Toggle plane 1 off/on
1864                 clipPlaneTransform(0,0,0,0,0, 1, 0);
1865                 previouslyActive[0] = active[0];
1866                 clipPlaneTransform(0,0,0,0,0, 0, 0);
1867                 lightenActiveClipPlaneSquare(0);
1868                 darkenInactiveClipPlaneSquares(0);
1869             }
1870             activeClipPlanes = activeClippingPlanes();
1871             locallySelectedPlane = 0;
1872         }
1873         break;
1874     case XK_2:
1875         if (clippingPlaneMode){
1876             if (SUMA_CTRL_KEY(key)){    // Select clipping plane 2
1877                 clipPlaneTransform(0,0,0,0,1, 0, 0);
1878                 lightenActiveClipPlaneSquare(1);
1879                 darkenInactiveClipPlaneSquares(1);
1880             } else {        // Toggle plane 2 off/on
1881                 clipPlaneTransform(0,0,0,0,1, 1, 0);
1882                 previouslyActive[1] = active[1];
1883                 clipPlaneTransform(0,0,0,0,1, 0, 0);
1884                 lightenActiveClipPlaneSquare(1);
1885                 darkenInactiveClipPlaneSquares(1);
1886             }
1887             activeClipPlanes = activeClippingPlanes();
1888             locallySelectedPlane = 1;
1889         }
1890      break;
1891     case XK_3:
1892             if (clippingPlaneMode){
1893                 if (SUMA_CTRL_KEY(key)){    // Select clipping plane 3
1894                     clipPlaneTransform(0,0,0,0,2, 0, 0);
1895                     lightenActiveClipPlaneSquare(2);
1896                     darkenInactiveClipPlaneSquares(2);
1897                 } else {        // Toggle plane 3 off/on
1898                     clipPlaneTransform(0,0,0,0,2, 1, 0);
1899                     previouslyActive[2] = active[2];
1900                     clipPlaneTransform(0,0,0,0,2, 0, 0);
1901                     lightenActiveClipPlaneSquare(2);
1902                     darkenInactiveClipPlaneSquares(2);
1903                 }
1904                 activeClipPlanes = activeClippingPlanes();
1905                 locallySelectedPlane = 2;
1906             }
1907      break;
1908     case XK_4:
1909             if (clippingPlaneMode){
1910                 if (SUMA_CTRL_KEY(key)){
1911                     clipPlaneTransform(0,0,0,0,3, 0, 0);
1912                     lightenActiveClipPlaneSquare(3);
1913                     darkenInactiveClipPlaneSquares(3);
1914                 } else {        // Toggle plane 4 off/on
1915                     clipPlaneTransform(0,0,0,0,3, 1, 0);
1916                     previouslyActive[3] = active[3];
1917                     clipPlaneTransform(0,0,0,0,3, 0, 0);
1918                     lightenActiveClipPlaneSquare(3);
1919                     darkenInactiveClipPlaneSquares(3);
1920                 }
1921                 activeClipPlanes = activeClippingPlanes();
1922                 locallySelectedPlane = 3;
1923             }
1924      break;
1925     case XK_5:
1926             if (clippingPlaneMode){
1927                 if (SUMA_CTRL_KEY(key)){    // Select clipping plane 5
1928                     clipPlaneTransform(0,0,0,0,4, 0, 0);
1929                     lightenActiveClipPlaneSquare(4);
1930                     darkenInactiveClipPlaneSquares(4);
1931                 } else {        // Toggle plane 4 off/on
1932                     clipPlaneTransform(0,0,0,0,4, 1, 0);
1933                     previouslyActive[4] = active[4];
1934                     clipPlaneTransform(0,0,0,0,4, 0, 0);
1935                     lightenActiveClipPlaneSquare(4);
1936                     darkenInactiveClipPlaneSquares(4);
1937                 }
1938                 activeClipPlanes = activeClippingPlanes();
1939                 locallySelectedPlane = 4;
1940             }
1941      break;
1942     case XK_6:
1943             if (clippingPlaneMode){
1944                 if (SUMA_CTRL_KEY(key)){    // Select clipping plane 6
1945                     clipPlaneTransform(0,0,0,0,5, 0, 0);
1946                     lightenActiveClipPlaneSquare(5);
1947                     darkenInactiveClipPlaneSquares(5);
1948                 } else {        // Toggle plane 6 off/on
1949                     clipPlaneTransform(0,0,0,0,5, 1, 0);
1950                     previouslyActive[5] = active[5];
1951                     clipPlaneTransform(0,0,0,0,5, 0, 0);
1952                     lightenActiveClipPlaneSquare(5);
1953                     darkenInactiveClipPlaneSquares(5);
1954                 }
1955                 activeClipPlanes = activeClippingPlanes();
1956                 locallySelectedPlane = 5;
1957             }
1958      break;
1959     case XK_7:
1960             if (clippingPlaneMode){
1961                 if (SUMA_CTRL_KEY(key)){
1962                     // Place-holder for ctrl-7
1963                 } else {
1964                     activeClipPlanes = activeClippingPlanes();
1965                     if (activeClipPlanes>0){
1966                         previouslySelectedPlane = selectedPlane;
1967                         for (i=0; i<SUMAg_CF->N_ClipPlanes; ++i){
1968                             previouslyActive[i] = active[i];
1969                             active[i] = 1;
1970                             clipPlaneTransform(0,0,0,0,i, 0, 0);
1971                             clipPlaneTransform(0,0,0,0,i, 1, 0);
1972                             clipIdentificationPlane[i]->Show = 0;
1973                         }
1974                     } else {
1975                         for (i=0; i<SUMAg_CF->N_ClipPlanes; ++i){
1976                             if (previouslyActive[i]){
1977                                 active[i] = 0;
1978                                 clipPlaneTransform(0,0,0,0,i, 1, 0);
1979                                 clipPlaneTransform(0,0,0,0,i, 0, 0);
1980                             }
1981                         }
1982                         selectedPlane = previouslySelectedPlane;
1983                         clipPlaneTransform(0,0,0,0,selectedPlane, 0, 0);
1984                     }
1985                 }
1986             }
1987      break;
1988     case XK_8:
1989             if (!clippingPlaneMode && sv->X->TOPLEVEL) {
1990                char stmp[100];
1991                sprintf(stmp, "%d", SUMAg_CF->X->NumForeSmoothing);
1992                if (!(SUMAg_CF->X->N_ForeSmooth_prmpt =
1993                   SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
1994                                        "Foreground smoothing iterations",
1995                                        stmp,
1996                                        sv->X->TOPLEVEL, YUP,
1997                                        SUMA_APPLY_BUTTON,
1998                                        SUMA_SetNumForeSmoothing, (void *)sv,
1999                                        NULL, NULL,
2000                                        NULL, NULL,
2001                                        SUMA_CleanNumString, (void*)1,
2002                                        SUMAg_CF->X->N_ForeSmooth_prmpt))){
2003                    SUMA_S_Err("Failure to create prompt dialog structure");
2004                    SUMA_RETURN(0);
2005                 }
2006 
2007                SUMAg_CF->X->N_ForeSmooth_prmpt =
2008                      SUMA_CreatePromptDialog("Foreground smoothing iterations",
2009                                              SUMAg_CF->X->N_ForeSmooth_prmpt);
2010             }
2011      break;
2012     default:
2013      SUMA_S_Err("Il ne faut pas ci dessous");
2014      SUMA_RETURN(0);
2015      break;
2016    }
2017 
2018    SUMA_RETURN(1);
2019 }
2020 
SUMA_SetShownLocalRemixFlagTemp(SUMA_SurfaceViewer * sv)2021 SUMA_Boolean SUMA_SetShownLocalRemixFlagTemp (SUMA_SurfaceViewer *sv)
2022 {
2023    static char FuncName[]={"SUMA_SetShownLocalRemixFlag"};
2024    int k;
2025 
2026    SUMA_ENTRY;
2027 
2028    // for (k=1; k < sv->N_ColList; ++k)
2029    for (k=0; k < sv->N_ColList; ++k) /*
2030     if (!strstr(sv->ColList[k]->idcode_str, "ClipSquare") &&
2031         !strstr(sv->ColList[k]->idcode_str, "axisObject")) */{
2032         /**/
2033         fprintf(stderr, "sv->ColList[k]->idcode_str = %s\n", sv->ColList[k]->idcode_str);
2034         /**/
2035       sv->ColList[k]->Remix = YUP;
2036    }
2037 
2038    SUMA_RETURN (YUP);
2039 }
2040 
2041 
SUMA_A_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2042 int SUMA_A_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2043 {
2044    static char FuncName[]={"SUMA_A_Key"};
2045    char tk[]={"A"}, keyname[100];
2046    int k, nc;
2047    SUMA_EngineData *ED = NULL;
2048    DList *list = NULL;
2049    DListElmt *NextElm= NULL;
2050    SUMA_Boolean LocalHead = NOPE;
2051    XKeyEvent Kev;
2052    Widget w = NULL;
2053 
2054    SUMA_ENTRY;
2055 
2056    SUMA_KEY_COMMON;
2057 
2058    /* do the work */
2059    switch (k) {
2060       case XK_A:
2061          if ((SUMA_CTRL_KEY(key))){
2062 
2063          } else {
2064 
2065          }
2066          break;
2067       case XK_a:
2068         if (clippingPlaneMode){
2069                 if (!axisObject) makeAxisObject(w, sv);
2070                 axisObject->ShowMeshAxis = !(axisObject->ShowMeshAxis);
2071                 /*
2072                 clipIdentificationPlane[0]->ShowMeshAxis =
2073                         !(clipIdentificationPlane[0]->ShowMeshAxis);
2074                         */
2075                 SUMA_postRedisplay(w, NULL, NULL);  // Refresh window
2076                } else  {
2077              /* toggle background attenuation */
2078              if (sv->Back_Modfact) {
2079                 fprintf (SUMA_STDOUT,
2080                          "%s: Modulation by background intensity OFF.\n", FuncName);
2081                 sv->Back_Modfact = 0;
2082              } else {
2083                 fprintf (SUMA_STDOUT,
2084                          "%s: Modulation by background intensity ON.\n", FuncName);
2085                 sv->Back_Modfact = SUMA_BACKGROUND_MODULATION_FACTOR;
2086              }
2087 
2088              if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
2089                     fprintf(stderr, "### SUMA_A_Key: sv->N_ColList = %d\n", sv->N_ColList);
2090 
2091              /* set the remix flag */
2092              if (!SUMA_SetShownLocalRemixFlagTemp (sv)) {
2093              // if (!SUMA_SetShownLocalRemixFlag (sv)) {
2094                 fprintf (SUMA_STDERR,
2095                          "Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n",
2096                          FuncName);
2097                 break;
2098              }
2099 
2100              SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2101          }
2102          break;
2103       default:
2104          SUMA_S_Err("Il ne faut pas ci dessous");
2105          SUMA_RETURN(0);
2106          break;
2107    }
2108 
2109    SUMA_RETURN(1);
2110 }
2111 
SUMA_B_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2112 int SUMA_B_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2113 {
2114    static char FuncName[]={"SUMA_B_Key"};
2115    char tk[]={"B"}, keyname[100];
2116    int k, nc;
2117    SUMA_EngineData *ED = NULL;
2118    DList *list = NULL;
2119    DListElmt *NextElm= NULL;
2120    SUMA_Boolean LocalHead = NOPE;
2121 
2122    SUMA_ENTRY;
2123 
2124    fprintf(stderr, "key = %s\n", key);
2125 
2126    SUMA_KEY_COMMON;
2127 
2128    /* do the work */
2129    switch (k) {
2130       case XK_B:
2131          if ((SUMA_CTRL_KEY(key))){
2132             if (SUMAg_CF->Dev ) {
2133                sv->Blend_Mode = (sv->Blend_Mode+1)%SUMA_N_BLEND_MODES;
2134                switch (sv->Blend_Mode) {
2135                   case SUMA_NO_BLEND:
2136                      glDisable(GL_BLEND);
2137                      if (callmode && strcmp(callmode, "interactive") == 0) {
2138                            SUMA_SLP_Note ("Blending  disabled."); }
2139                      else { SUMA_S_Note ("Blending  disabled."); }
2140                      break;
2141                   case SUMA_BLEND1:
2142                      glEnable (GL_BLEND);
2143                      glBlendFunc(GL_ONE,GL_SRC_ALPHA);
2144                      if (callmode && strcmp(callmode, "interactive") == 0) {
2145                               SUMA_SLP_Note ("Blending mode1."); }
2146                      else { SUMA_S_Note ("Blending  mode1."); }
2147                      break;
2148                   case SUMA_BLEND2:
2149                      glEnable (GL_BLEND);
2150                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2151                      if (callmode && strcmp(callmode, "interactive") == 0) {
2152                            SUMA_SLP_Note ("Blending mode2.");}
2153                      else { SUMA_S_Note ("Blending  mode2."); }
2154                      break;
2155                   default:
2156                      SUMA_SL_Err ("Should not be here");
2157                      break;
2158                }
2159                SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2160             }
2161          } else {
2162             sv->BF_Cull = (sv->BF_Cull+1)%3;
2163             if (callmode && strcmp(callmode, "interactive") == 0) {
2164                   SUMA_CullOption(sv, "Apply");}
2165             else { SUMA_CullOption(sv, "Restore");}
2166             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2167          }
2168          break;
2169       case XK_b:
2170          /* Show/hide the background */
2171          if (!list) list = SUMA_CreateList();
2172          ED = SUMA_InitializeEngineListData (SE_ToggleBackground);
2173          if (!SUMA_RegisterEngineListCommand (  list, ED,
2174                                                 SEF_Empty, NULL,
2175                                                 SES_Suma, (void *)sv, NOPE,
2176                                                 SEI_Head, NULL)) {
2177             fprintf (SUMA_STDERR,
2178                   "Error %s: Failed to register command.\n", FuncName);
2179          }
2180 
2181          ED = SUMA_InitializeEngineListData (SE_Redisplay);
2182          if (!SUMA_RegisterEngineListCommand (  list, ED,
2183                                                 SEF_Empty, NULL,
2184                                                 SES_Suma, (void *)sv, NOPE,
2185                                                 SEI_Head, NULL)) {
2186             fprintf (SUMA_STDERR,
2187                   "Error %s: Failed to register command.\n", FuncName);
2188          }
2189 
2190          if (!SUMA_Engine (&list)) {
2191             fprintf(SUMA_STDERR, "Error SUMA_input: SUMA_Engine call failed.\n");
2192          }
2193          break;
2194       default:
2195          SUMA_S_Err("Il ne faut pas ci dessous");
2196          SUMA_RETURN(0);
2197          break;
2198    }
2199 
2200    SUMA_RETURN(1);
2201 }
2202 
2203 
SUMA_C_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2204 int SUMA_C_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2205 {
2206    static char FuncName[]={"SUMA_C_Key"};
2207    char tk[]={"C"}, keyname[100];
2208    int k, nc, planeIndex=0, locallySelectedPlane=0, isv;
2209    SUMA_EngineData *ED = NULL;
2210    DList *list = NULL;
2211    DListElmt *NextElm= NULL;
2212    SUMA_Boolean LocalHead = NOPE;
2213    Widget w = NULL;
2214 
2215    SUMA_ENTRY;
2216 
2217    SUMA_KEY_COMMON;
2218 
2219    /* do the work */
2220    switch (k) {
2221      case XK_C:
2222 
2223         if ((SUMA_ALT_KEY(key) || SUMA_APPLE_KEY(key))){
2224 
2225             if (clippingPlaneMode){
2226 
2227                 if (resetClippingPlanes){
2228                     SUMAg_CF->N_ClipPlanes = 1;
2229                     resetClippingPlanes=0;
2230                 }
2231                 // This sets up a new clip plane (independent of the dialog box.  If called with
2232                 //  the dialog box, two clipping planes result.)  The new plane is automatically
2233                 //  assigned a label which is its 1-based index
2234                 if ((SUMA_CTRL_KEY(key))){ // Ctrl-Shift-alt-C (clip plane box
2235 
2236                     for (planeIndex=0; planeIndex<6; ++planeIndex){
2237                         sprintf(SUMAg_CF->ClipPlanesLabels[SUMAg_CF->N_ClipPlanes], "%d", SUMAg_CF->N_ClipPlanes+1);
2238                         clipPlaneTransform(0,0,0,0,SUMAg_CF->N_ClipPlanes, 0, 0);
2239                     }
2240                 }
2241                 activeClipPlanes = activeClippingPlanes();
2242             }
2243         } else if (SUMA_CTRL_KEY(key)){
2244             if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
2245                 fprintf(stderr, "### SUMA_C_Key: toggleClippingPlaneMode\n");
2246             toggleClippingPlaneMode(sv, w, &locallySelectedPlane);
2247             if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
2248                 fprintf(stderr, "### axisObject = %d\n", axisObject);
2249             if (!axisObject) makeAxisObject(w, sv);
2250         }else if (clippingPlaneMode) {
2251 
2252             SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
2253 
2254             // Toggle clip plane identification mode
2255             clipPlaneIdentificationMode = !clipPlaneIdentificationMode;
2256 
2257             if (SUMAg_CF->clippingPlaneVerbose) fprintf(stderr, "### Clipping plane squares %s\n",
2258                 clipPlaneIdentificationMode? "on" : "off");
2259 
2260             for (planeIndex=0; planeIndex<SUMAg_CF->N_ClipPlanes; ++planeIndex){
2261                 if (clipPlaneIdentificationMode){
2262                     if (active[planeIndex]) clipIdentificationPlane[planeIndex]->Show = 1;
2263                 } else {
2264                     clipIdentificationPlane[planeIndex]->Show = 0;
2265                 }
2266             }
2267 
2268             SUMA_postRedisplay(w, NULL, NULL);  // Refresh window
2269         }  else if (SUMAg_CF->Dev && SUMA_CTRL_KEY(key)){
2270 
2271            SUMAg_CF->X->Clip_prmpt =
2272               SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
2273                  "Enter screen clip plane parameters (a,b,c,d)",
2274                  "A: 0,0,1,0",
2275                  sv->X->TOPLEVEL, YUP,
2276                  SUMA_APPLY_BUTTON,
2277                  SUMA_SetScreenClip, (void *)sv,
2278                  NULL, NULL,
2279                  NULL, NULL,
2280                  NULL, NULL,
2281                  SUMAg_CF->X->Clip_prmpt);
2282 
2283            SUMAg_CF->X->Clip_prmpt =
2284               SUMA_CreatePromptDialog(
2285                  "Enter screen clip plane parameters (a,b,c,d)",
2286                  SUMAg_CF->X->Clip_prmpt);
2287        }
2288         break;
2289      case XK_c:
2290         {
2291            SUMA_SurfaceObject *SO=NULL;
2292            if ((SO = SUMA_SV_Focus_SO(sv))) {
2293               if (!list) list = SUMA_CreateList();
2294               ED = SUMA_InitializeEngineListData (SE_OpenColFileSelection);
2295               if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
2296                                 SEF_vp, (void *)SO,
2297                                 SES_Suma, (void *)sv, NOPE,
2298                                 SEI_Head, NULL))) {
2299                  SUMA_S_Err("Failed to register command.");
2300               }
2301 
2302               if (!SUMA_RegisterEngineListCommand (  list, ED,
2303                                             SEF_ip, sv->X->TOPLEVEL,
2304                                             SES_Suma, (void *)sv, NOPE,
2305                                             SEI_In, NextElm)) {
2306                  SUMA_S_Err("Failed to register command.");
2307               }
2308 
2309               if (!SUMA_Engine (&list)) {
2310                  fprintf(SUMA_STDERR,
2311                           "Error %s: SUMA_Engine call failed.\n", FuncName);
2312               }
2313            }
2314         }
2315 
2316         break;
2317       default:
2318          SUMA_S_Err("Il ne faut pas ci dessous");
2319          SUMA_RETURN(0);
2320          break;
2321    }
2322 
2323    SUMA_RETURN(1);
2324 }
2325 
2326 
SUMA_D_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2327 int SUMA_D_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2328 {
2329    static char FuncName[]={"SUMA_D_Key"};
2330    SUMA_LIST_WIDGET *LW=NULL;
2331    char tk[]={"D"}, keyname[100];
2332    int k, nc, inode = 0, N_ts = 0, ChildOverInd=-1,loc[2], ii = 0;
2333    float ftop = 0.1, fbot = 0.01, fs=0.0, fstep=0.0, *fv=NULL;
2334    int normalize = 1, polort = 2;
2335    SUMA_EngineData *ED = NULL;
2336    SUMA_DSET *dot=NULL;
2337    SUMA_DSET *in_dset = NULL;
2338    SUMA_SurfaceObject *SO=NULL;
2339    SUMA_OVERLAYS *Sover=NULL, *child=NULL;
2340    SUMA_DSET *inc_dset=NULL;
2341    SUMA_SurfaceObject *SOC=NULL;
2342    DList *list = NULL;
2343    DListElmt *el= NULL;
2344    double *ts = NULL, TR=0.0;
2345    NI_group *ngr = NULL;
2346    NI_element *nel=NULL, *dotopts=NULL;
2347    SUMA_XFORM *xf=NULL;
2348    SUMA_CALLBACK *cb=NULL;
2349    char stmp[SUMA_MAX_NAME_LENGTH]={""};
2350    SUMA_Boolean LocalHead = NOPE;
2351 
2352    SUMA_ENTRY;
2353 
2354    // fprintf(stderr, "%s\n", FuncName);
2355 
2356    SUMA_KEY_COMMON;
2357 
2358    /* do the work */
2359    switch (k) {
2360       case XK_D:
2361          if ((SUMA_CTRL_KEY(key))){
2362          } else {
2363             SUMA_LH("The dotthing");
2364             /* DO the dot thing */
2365             if (!(SO = SUMA_SV_Focus_SO(sv))) {
2366                if (callmode && strcmp(callmode, "interactive") == 0) {
2367                   SUMA_SLP_Err("No surface in focus.\nCannot dot.");
2368                } else {
2369                   SUMA_S_Err("No surface in focus.\nCannot dot.");
2370                }
2371                SUMA_RETURN(0);
2372             }
2373             if (  !SO || !SO->SurfCont ||
2374                   !SO->SurfCont->curColPlane ||
2375                   !SO->SurfCont->curColPlane->dset_link) {
2376                SUMA_SL_Err("Nothing to dot");
2377                SUMA_RETURN(0);
2378             }
2379             Sover = SO->SurfCont->curColPlane;
2380             in_dset = SO->SurfCont->curColPlane->dset_link;
2381             inode = SO->SelectedNode;
2382             if (inode < 0) {
2383                if (callmode && strcmp(callmode, "interactive") == 0) {
2384                   SUMA_SLP_Warn("No selected node.\nNothing to dot.");
2385                }else{
2386                   SUMA_S_Warn("No selected node.\nNothing to dot.");
2387                }
2388                SUMA_RETURN(1);
2389             }
2390             if (SDSET_VECNUM(in_dset) < 3) {
2391                if (callmode && strcmp(callmode, "interactive") == 0) {
2392                   SUMA_SLP_Warn( "Need more than 3 values per node.\n"
2393                                  "Nothing to dot.");
2394                }else{
2395                   SUMA_S_Warn("Need more than 3 values per node.\n"
2396                               "Nothing to dot.");
2397                }
2398                SUMA_RETURN(1);
2399             }
2400 
2401 
2402             if ((xf = SUMA_Find_XformByParent("Dot", SDSET_ID(in_dset), NULL))) {
2403                /* xform exists already, just flip toggle of all callbacks
2404                   that claim it as a creator*/
2405                SUMA_SetXformActive(xf, -1*xf->active, 0);
2406 
2407                if (callmode && strcmp(callmode, "interactive") == 0) {
2408                   if (xf->active > 0) {
2409                      SUMA_SLP_Note("Dot product callback active");
2410                   } else {
2411                      SUMA_SLP_Note("Dot product callback inactive");
2412                   }
2413                }else {
2414                   if (xf->active > 0) {
2415                      SUMA_S_Note("Dot product callback active");
2416                   } else {
2417                      SUMA_S_Note("Dot product callback inactive");
2418                   }
2419                }
2420 
2421                SUMA_RETURN(1);
2422             } else { /* New Xform */
2423                /* We need to add a dot product transform to
2424                   the dataset */
2425                SUMA_LH("Afresh: Adding Dot Xform");
2426                xf = SUMA_NewXform("Dot",
2427                                   SDSET_ID(in_dset), SO->LocalDomainParentID);
2428 
2429                /* Any matching contralateral dset and a matching surface ?*/
2430                inc_dset = SUMA_Contralateral_dset(in_dset, SO, &SOC);
2431                if (inc_dset) {
2432                   SUMA_LHv("Found contralateral dset %s (%s)\n",
2433                                SDSET_LABEL(inc_dset), SDSET_FILENAME(inc_dset));
2434                   if (!(SUMA_AddXformParent(xf,
2435                               SDSET_ID(inc_dset), SOC->LocalDomainParentID))) {
2436                      SUMA_S_Err("Failed to add parent");
2437                      SUMA_RETURN(0);
2438                   }
2439                }  else {
2440                   SUMA_S_Note("No contralateral dset ");
2441                }
2442                /* Initialize dot product options. You'll have to redo this
2443                   unfortunately below... */
2444                if (!(SUMA_is_TimeSeries_dset(in_dset, &TR))) {
2445                   TR = 0.0;
2446                }
2447                SUMA_SPECT_AXIS(TR, SDSET_VECNUM(in_dset), fs, ftop, fstep);
2448                dotopts = SUMA_set_dotopts(NULL, SDSET_VECNUM(in_dset),
2449                                            0.1, fbot,
2450                                            normalize, 1,
2451                                            polort, NULL);
2452 
2453 
2454                SUMA_LH("Get dot product time series");
2455 
2456                if (!(fv = (float*)SUMA_GetDsetAllNodeValsInCols2(in_dset,
2457                                        NULL, 0,
2458                                        inode, SO->N_Node-1,
2459                                        &N_ts,
2460                                        SUMA_float))) {
2461                   SUMA_S_Err("Failed to extract time series.");
2462                   SUMA_RETURN(0);
2463                }
2464                if (!(ts = SUMA_DotPreProcessTimeSeries(fv,  N_ts,
2465                                              (float)TR, dotopts))) {
2466                   SUMA_S_Err("Failed to preprocess time series.");
2467                   SUMA_RETURN(0);
2468                }
2469                SUMA_free(fv); fv=NULL;
2470 
2471                for (ii=0; ii<xf->N_parents; ++ii) {
2472                   dot = NULL; /* You'll need a new dset with each pass */
2473                   if (!SUMA_is_ID_4_DSET(xf->parents[ii], &in_dset)) {
2474                            /* This is a convoluted way to get in_dset,
2475                               since in_dset is known from a few lines above.
2476                               But it is meant to demo how to work with
2477                               multiple parents in xf in general */
2478                      SUMA_S_Err("You've really done it this time!");
2479                      SUMA_RETURN(0);
2480                   }
2481                   if (!SUMA_is_ID_4_SO(xf->parents_domain[ii], &SO)) {
2482                            /* This is a convoluted way to get SO...*/
2483                      SUMA_S_Err("You've really really done it this time!");
2484                      SUMA_RETURN(0);
2485                   }
2486                   SUMA_LHv("Creating dot for %d/%d %s\n",
2487                            ii, xf->N_parents, SDSET_FILENAME(in_dset));
2488                   if (!(SUMA_dot_product(in_dset, ts,
2489                                  &dot,
2490                                  dotopts))) {
2491                      SUMA_S_Err("Failed to create dot product");
2492                      SUMA_RETURN(0);
2493                   }
2494 
2495                   /* Assign domain parent fields  */
2496                   NI_set_attribute(dot->ngr,"domain_parent_idcode",
2497                                    NI_get_attribute(in_dset->ngr,
2498                                                     "domain_parent_idcode"));
2499                   NI_set_attribute(dot->ngr,"geometry_parent_idcode",
2500                                    NI_get_attribute(in_dset->ngr,
2501                                                     "geometry_parent_idcode"));
2502 
2503                   SUMA_LHv( "Insert (%s/%s)in DsetList\n",
2504                             SDSET_LABEL(dot), SDSET_ID(dot) );
2505                                                    /* no replacement allowed
2506                                                    I don't think it's necessary*/
2507                   if (!SUMA_InsertDsetPointer (&dot, SUMAg_CF->DsetList, 0)) {
2508                      SUMA_S_Errv("Failed to insert pointer for %s\n",
2509                                  SDSET_LABEL(dot));
2510                      SUMA_RETURN(0);
2511                   }
2512 
2513                   /* Add child to Xform */
2514                   if (!SUMA_AddXformChild(xf,SDSET_ID(dot))) {
2515                      SUMA_S_Err("Failed to add child");
2516                      SUMA_RETURN(0);
2517                   }
2518 
2519                   SUMA_LH("Create its overlay (child)");
2520                   if (!(SDSET_LABEL(dot))) SUMA_LabelDset(dot,NULL);
2521                   sprintf(stmp, "overlay.%s", SDSET_ID(dot));
2522                   child = SUMA_CreateOverlayPointer (
2523                                           stmp, dot, SO->idcode_str, NULL);
2524                   if (!child) {
2525                      fprintf (SUMA_STDERR,
2526                               "Error %s: Failed in CreateOverlayPointer.\n" ,
2527                               FuncName);
2528                      SUMA_RETURN (0);
2529                   }
2530                   SUMA_LH("Add overlay to SO");
2531                   /* Add this plane to SO->Overlays */
2532                   if (!SUMA_AddNewPlane ( (SUMA_ALL_DO *)SO, child,
2533                                           SUMAg_DOv, SUMAg_N_DOv, 0)) {
2534                      SUMA_SL_Crit("Failed in SUMA_AddNewPlane");
2535                      SUMA_FreeOverlayPointer(child);
2536                      SUMA_RETURN (0);
2537                   }
2538 
2539                   ChildOverInd = SO->N_Overlays-1;
2540                   /* set the opacity, index column and the range */
2541                   child->GlobalOpacity = YUP;
2542                   child->ShowMode = SW_SurfCont_DsetViewCol;
2543                   child->OptScl->BrightFact = 0.8;
2544 
2545                   child->OptScl->find = 0;
2546                   child->OptScl->tind = 0;
2547                   child->OptScl->bind = 0;
2548                   child->OptScl->UseThr = 1; /* turn on threshold use */
2549                   child->SymIrange = 1;   /* Use symmetric range */
2550                   child->OptScl->AutoIntRange = 0; /* Do not update range */
2551 
2552                   /* Leave it to the -0.5, 0.5 range below, it works better
2553                      SUMA_GetDsetColRange(dot, 0, child->OptScl->IntRange, loc);
2554                       */
2555 
2556                   SO->SurfCont->curColPlane = child;
2557 
2558                   /* update the Dset frame */
2559                   if (ChildOverInd >= 0)
2560                      SUMA_InitializeColPlaneShell((SUMA_ALL_DO *)SO,
2561                                        SO->Overlays[ChildOverInd]);
2562                   SUMA_UPDATE_ALL_NODE_GUI_FIELDS((SUMA_ALL_DO *)SO);
2563                   child->OptScl->IntRange[0] = -0.5;  /* set the range */
2564                   child->OptScl->IntRange[1] = 0.5;
2565                   SUMA_INSERT_CELL_VALUE(SO->SurfCont->SetRangeTable, 1, 1,
2566                                           child->OptScl->IntRange[0]);
2567                   SUMA_INSERT_CELL_VALUE(SO->SurfCont->SetRangeTable, 1, 2,
2568                                           child->OptScl->IntRange[1]);
2569 
2570                   SUMA_LH("Colorize plane");
2571                   SUMA_ColorizePlane(child);
2572 
2573                   /* remix-redisplay  for surface */
2574                   if (!SUMA_Remixedisplay ((SUMA_ALL_DO*)SO)) {
2575                      SUMA_RETURN(0);
2576                   }
2577 
2578                   SUMA_LH("Refreshing Dset list");
2579                   /*update the list widget if open */
2580                   LW = SO->SurfCont->SwitchDsetlst;
2581                   if (LW) {
2582                      if (!LW->isShaded) SUMA_RefreshDsetList ((SUMA_ALL_DO *)SO);
2583                   }
2584 
2585                   if (LocalHead)
2586                      fprintf (SUMA_STDERR,
2587                               "%s: Updating Dset frame, OverInd=%d\n",
2588                               FuncName, ChildOverInd);
2589 
2590                } /* For each parent */
2591 
2592                /* done with ts */
2593                SUMA_free(ts); ts = NULL;
2594 
2595                /* add the dotoptions to the transform options group */
2596                NI_add_to_group(xf->XformOpts, dotopts);
2597 
2598                /* activate xform */
2599                SUMA_SetXformActive(xf, 1, 0);
2600 
2601 
2602                SUMA_LH("Add Callback ");
2603                /* generic parts */
2604                cb = SUMA_NewCallback(  "SUMA_dot_product_CB",
2605                                        SUMA_NEW_NODE_ACTIVATE_EVENT,
2606                                        SUMA_dot_product_CB,
2607                                        xf->children[0],
2608                                        xf->parents_domain[0],
2609                                        xf->idcode_str);
2610 
2611 
2612                /* add extra children */
2613                for (ii=1; ii<xf->N_children; ++ii) {
2614                   if (!SUMA_AddCallbackParent(cb, xf->children[ii],
2615                                               xf->parents_domain[ii])) {
2616                      SUMA_S_Err("Failed to add parent");
2617                      SUMA_RETURN(0);
2618                   }
2619                }
2620 
2621                /* fill the callback function's input parameters */
2622                /* The time series datasets */
2623                nel = NI_new_data_element("AFNI_atr", 1);
2624                NI_set_attribute(nel, "atr_name", "ts_dsets_idcode");
2625                NI_add_column_stride(nel, NI_STRING, NULL,1);
2626                for (ii=0; ii<xf->N_parents; ++ii) {
2627                   if (!SUMA_AddColAtt_CompString( nel, ii,
2628                                              xf->parents[ii], SUMA_NI_CSS, 0)){
2629                      SUMA_S_Err("Failed to add ts_dsets_idcode");
2630                      SUMA_RETURN(0);
2631                   }
2632                }
2633                NI_add_to_group(cb->FunctionInput, nel);
2634 
2635                /* the output datasets */
2636                nel = NI_new_data_element("AFNI_atr", 1);
2637                NI_set_attribute(nel, "atr_name", "dot_dsets_idcode");
2638                NI_add_column_stride(nel, NI_STRING, NULL,1);
2639                for (ii=0; ii<xf->N_children; ++ii) {
2640                   if (!SUMA_AddColAtt_CompString( nel, ii,
2641                                              xf->children[ii], SUMA_NI_CSS, 0)){
2642                      SUMA_S_Err("Failed to add dot_dsets_idcode");
2643                      SUMA_RETURN(0);
2644                   }
2645                }
2646                NI_add_to_group(cb->FunctionInput, nel);
2647 
2648                /* Node is from surface SO, but there is no point
2649                in setting this now because the computations
2650                have been done already. Set all sources for
2651                getting the time series to nothing, for the
2652                record.*/
2653                /* ts can be specified via node selection events and parents */
2654                SUMA_FlushCallbackEventParameters (cb);
2655 
2656                /* or ts can be explicitly set
2657                   again, the existence of ts_vec is not necessary,
2658                   but to illustrate options ...*/
2659                nel = NI_new_data_element("callback.data",0);
2660                NI_set_attribute(nel, "data_type", "ts_vec");
2661                NI_add_to_group(cb->FunctionInput, nel);
2662 
2663                /* set callback to be active, but not pending */
2664                cb->active = 1;
2665                SUMA_SetCallbackPending(cb, 0, SES_Empty);
2666                if (callmode && strcmp(callmode, "interactive") == 0) {
2667                   SUMA_SLP_Note("Dot product callback active");                                  } else {
2668                   SUMA_S_Note("Dot product callback active");
2669                }
2670 
2671                if (LocalHead) {
2672                   SUMA_Show_Xforms(SUMAg_CF->xforms, SUMA_STDERR, 1);
2673                   SUMA_Show_Callbacks(SUMAg_CF->callbacks, SUMA_STDERR, 1);
2674                }
2675 
2676                /* initialize interface (no callbacks willget triggered)*/
2677                SUMA_InitializeXformInterface (xf);
2678 
2679             } /* New Xform */
2680 
2681          }
2682          break;
2683       case XK_d:
2684          if ((SUMA_CTRL_KEY(key))){
2685             /* Interactively it is handled by the mnemonic
2686               But if it gets here, the Driver may be driving it */
2687             /* opens draw ROI controller */
2688             if (!SUMA_OpenDrawROIController(NULL)) {
2689                SUMA_S_Err("Failed to open controller");
2690             }
2691          } else {
2692             if (SUMAg_CF->Dev ) {
2693                SUMA_Show_DOv(SUMAg_DOv, SUMAg_N_DOv, stdout);
2694             }
2695          }
2696 
2697 
2698          break;
2699       default:
2700          SUMA_S_Err("Il ne faut pas ci dessous");
2701          SUMA_RETURN(0);
2702          break;
2703    }
2704 
2705    SUMA_RETURN(1);
2706 }
2707 
SUMA_F_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2708 int SUMA_F_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2709 {
2710    static char FuncName[]={"SUMA_F_Key"};
2711    char tk[]={"F"}, keyname[100];
2712    int k=0, nc=-1;
2713    int inode = -1;
2714    SUMA_DSET *Dset = NULL;
2715    SUMA_ALL_DO *ado=NULL;
2716    SUMA_OVERLAYS *Sover=NULL;
2717    SUMA_X_SurfCont *SurfCont=NULL;
2718    char stmp[100]={"\0"};
2719    SUMA_Boolean LocalHead = NOPE;
2720    // static DList *list = NULL;
2721 
2722    SUMA_ENTRY;
2723 
2724    SUMA_KEY_COMMON;
2725 
2726    /* do the work */
2727    switch (k) {
2728      case XK_F:
2729         /* flip light position */
2730         if (!list) list = SUMA_CreateList();
2731         SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FlipLight0Pos,
2732                                             SES_Suma, sv);
2733         SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
2734 
2735         if (!SUMA_Engine (&list)) {
2736            fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
2737         }
2738         break;
2739 
2740      case XK_f:
2741         if (clippingPlaneMode && (SUMA_CTRL_KEY(key))){
2742             clipPlaneTransform(0,0,0,1,-1, 0, 0);  // PDL: Flip clipping plane
2743         } else {
2744             /* Show/hide the foreground */
2745             if (!list) list = SUMA_CreateList();
2746             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleForeground,
2747                                                 SES_Suma, sv);
2748             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
2749 
2750             if (!SUMA_Engine (&list)) {
2751                fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
2752             }
2753         }
2754         break;
2755    }
2756    SUMA_RETURN(1);
2757 }
2758 
SUMA_G_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2759 int SUMA_G_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2760 {
2761    static char FuncName[]={"SUMA_G_Key"};
2762    char tk[]={"G"}, keyname[100];
2763    int k=0, nc=-1;
2764    int inode = -1;
2765    SUMA_DSET *Dset = NULL;
2766    SUMA_ALL_DO *ado=NULL;
2767    SUMA_OVERLAYS *Sover=NULL;
2768    SUMA_X_SurfCont *SurfCont=NULL;
2769    char stmp[100]={"\0"};
2770    SUMA_Boolean LocalHead = NOPE;
2771 
2772    SUMA_ENTRY;
2773 
2774    SUMA_KEY_COMMON;
2775 
2776    if (!(ado = SUMA_SV_Focus_ADO(sv))) {
2777       if (callmode && strcmp(callmode, "interactive") == 0) {
2778          SUMA_SLP_Err("No surface in focus.\nCannot graph.");
2779       } else {
2780          SUMA_S_Err("No surface in focus.\nCannot graph.");
2781       }
2782       SUMA_RETURN(0);
2783    }
2784    if (  !ado || !(SurfCont = SUMA_ADO_Cont(ado)) ||
2785          !(Sover = SUMA_ADO_CurColPlane(ado)) ||
2786          !(Dset = Sover->dset_link)) {
2787       SUMA_SL_Err("Nothing to graph");
2788       SUMA_RETURN(0);
2789    }
2790    inode = SUMA_ADO_SelectedDatum(ado, NULL, NULL);
2791    if (inode < 0) {
2792       if (callmode && strcmp(callmode, "interactive") == 0) {
2793          SUMA_SLP_Warn("No selected node.\nNothing to graph.");
2794       }else{
2795          SUMA_S_Warn("No selected node.\nNothing to graph.");
2796       }
2797       SUMA_RETURN(1);
2798    }
2799    if (SDSET_VECNUM(Dset) < 2) {
2800       if (callmode && strcmp(callmode, "interactive") == 0) {
2801          SUMA_SLP_Warn("One or no value per node.\nNothing to graph.");
2802       }else{
2803          SUMA_S_Warn("One or no value per node.\nNothing to graph.");
2804       }
2805       SUMA_RETURN(1);
2806    }
2807    /* do the work */
2808    switch (k) {
2809       case XK_g:
2810          if ((SUMA_CTRL_KEY(key))) {
2811          } else {
2812             SUMA_OverlayGraphAtNode(Sover, ado, inode);
2813          }
2814          break;
2815       case XK_G:
2816          if (SUMAg_CF->Dev ) {
2817             #ifdef SUMA_USE_AFNI_GRAPH
2818                /* an attempt at using AFNI's graphing interface */
2819                SUMA_Afni_Graph(Sover, SO);
2820             #endif
2821          }
2822          break;
2823       default:
2824          SUMA_S_Err("Il ne faut pas etre ici");
2825          SUMA_RETURN(0);
2826          break;
2827    }
2828    SUMA_RETURN(1);
2829 }
2830 
SUMA_H_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2831 int SUMA_H_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2832 {
2833    static char FuncName[]={"SUMA_H_Key"};
2834    char tk[]={"H"}, keyname[100];
2835    int k=0, nc=-1;
2836    int inode = -1;
2837    SUMA_DSET *Dset = NULL;
2838    SUMA_ALL_DO *ado=NULL;
2839    SUMA_OVERLAYS *Sover=NULL;
2840    SUMA_X_SurfCont *SurfCont=NULL;
2841    char stmp[100]={"\0"};
2842    SUMA_Boolean LocalHead = NOPE;
2843 
2844    SUMA_ENTRY;
2845 
2846    SUMA_KEY_COMMON;
2847 
2848     switch (k) {
2849      case XK_H:
2850            sv->X->HighlightBox_prmpt =
2851               SUMA_CreatePromptDialogStruct(SUMA_OK_APPLY_CLEAR_CANCEL,
2852                                          "Enter XYZ of box's center\n"
2853                                          "followed by it's size (6 values)",
2854                                          "",
2855                                          sv->X->TOPLEVEL, YUP,
2856                                          SUMA_APPLY_BUTTON,
2857                                          SUMA_HighlightBox, (void *)sv,
2858                                          NULL, NULL,
2859                                          NULL, NULL,
2860                                          SUMA_CleanNumString, (void*)6,
2861                                          sv->X->HighlightBox_prmpt);
2862 
2863            sv->X->HighlightBox_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
2864                                                   sv->X->HighlightBox_prmpt);
2865 
2866         break;
2867 
2868      case XK_h:
2869         if (SUMA_CTRL_KEY(key)){
2870           if (!list) list = SUMA_CreateList();
2871           SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Help, SES_Suma, NULL);
2872           if (!SUMA_Engine (&list)) {
2873               fprintf( stderr,
2874                        "Error %s: SUMA_Engine call failed.\n", FuncName);
2875           }
2876         }else{
2877            if (SUMAg_CF->Dev) {
2878               SUMA_SLP_Note("Please use ctrl+h for help.\n"
2879                             "h alone will be reassigned\n"
2880                             "in future versions.");
2881            }
2882         }
2883         break;
2884     }
2885    SUMA_RETURN(1);
2886 }
2887 
SUMA_J_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)2888 int SUMA_J_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode, char *strgval)
2889 {
2890    static char FuncName[]={"SUMA_J_Key"};
2891    char tk[]={"J"}, keyname[100];
2892    int k=0, nc=-1;
2893    int inode = -1;
2894    SUMA_DSET *Dset = NULL;
2895    SUMA_ALL_DO *ado=NULL;
2896    SUMA_OVERLAYS *Sover=NULL;
2897    char stmp[100]={"\0"};
2898    SUMA_Boolean LocalHead = NOPE;
2899 
2900    SUMA_ENTRY;
2901 
2902    // fprintf(stderr, "%s\n", FuncName);
2903 
2904    SUMA_KEY_COMMON;
2905 
2906 
2907    if (!(ado = SUMA_SV_Focus_ADO(sv))) {
2908       if (callmode && strcmp(callmode, "interactive") == 0) {
2909          SUMA_SLP_Err("No object in focus.\nCannot Jump.");
2910       } else {
2911          SUMA_S_Err("No object in focus.\nCannot Jump.");
2912       }
2913       SUMA_RETURN(0);
2914    }
2915    /* do the work */
2916    switch (k) {
2917       case XK_j:
2918         if ( (callmode && strcmp(callmode, "interactive") == 0) ||
2919              !strgval /* why not? this way the
2920                         Driver can pop the interactive window */) {
2921             if (SUMA_CTRL_KEY(key)){
2922                  sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialogStruct(
2923                                  SUMA_OK_APPLY_CLEAR_CANCEL,
2924                                  "Enter XYZ to send the cross hair to:",
2925                                  "",
2926                                  sv->X->TOPLEVEL, YUP,
2927                                  SUMA_APPLY_BUTTON,
2928                                  SUMA_JumpXYZ, (void *)sv,
2929                                  NULL, NULL,
2930                                  NULL, NULL,
2931                                  SUMA_CleanNumString, (void*)3,
2932                                  sv->X->JumpXYZ_prmpt);
2933                   sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialog(
2934                                     sv->X->Title, sv->X->JumpXYZ_prmpt);
2935 
2936              } else if (SUMA_AALT_KEY(key)){
2937                   sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialogStruct(
2938                                  SUMA_OK_APPLY_CLEAR_CANCEL,
2939                      "Enter index of focus node\n"
2940                      "Prepend/append L/R for hemiisphere selection\n"
2941                      "Cross hair's XYZ will not be affected:",
2942                                  "",
2943                                  sv->X->TOPLEVEL, YUP,
2944                                  SUMA_APPLY_BUTTON,
2945                                  SUMA_JumpFocusNode, (void *)sv,
2946                                  NULL, NULL,
2947                                  NULL, NULL,
2948                                  SUMA_CleanNumStringSide, (void*)1,                                                    sv->X->JumpFocusNode_prmpt);
2949 
2950                   sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialog(
2951                                     sv->X->Title, sv->X->JumpFocusNode_prmpt);
2952 
2953              } else {
2954                   sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialogStruct(
2955                                  SUMA_OK_APPLY_CLEAR_CANCEL,
2956                             "Enter index of node to send the cross hair to:\n"
2957                             "(prepend/append L/R for specifying hemisphere):",
2958                                  "",
2959                                  sv->X->TOPLEVEL, YUP,
2960                                  SUMA_APPLY_BUTTON,
2961                                  SUMA_JumpIndex, (void *)sv,
2962                                  NULL, NULL,
2963                                  NULL, NULL,
2964                                  SUMA_CleanNumStringSide, (void*)1,
2965                                  sv->X->JumpIndex_prmpt);
2966 
2967                   sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialog(
2968                                     sv->X->Title, sv->X->JumpIndex_prmpt);
2969              }
2970          } else {
2971             if (!strgval) {
2972                SUMA_S_Err("Have NULL string");
2973                SUMA_RETURN(0);
2974             }
2975             if (SUMA_CTRL_KEY(key)){
2976                SUMA_JumpXYZ(strgval, (void *)sv);
2977             } else if (SUMA_AALT_KEY(key)){
2978                SUMA_JumpFocusNode(strgval, (void *)sv);
2979             } else {
2980                SUMA_JumpIndex(strgval, (void *)sv);
2981             }
2982          }
2983 
2984          break;
2985       case XK_J:
2986          if ( (callmode && strcmp(callmode, "interactive") == 0) ||
2987                !strgval) {
2988             sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialogStruct (
2989                      SUMA_OK_APPLY_CLEAR_CANCEL,
2990                      "Enter index of FaceSet\nto highlight (this viewer only):",
2991                      "",
2992                      sv->X->TOPLEVEL, YUP,
2993                      SUMA_APPLY_BUTTON,
2994                      SUMA_JumpFocusFace, (void *)sv,
2995                      NULL, NULL,
2996                      NULL, NULL,
2997                      SUMA_CleanNumString, (void*)1,
2998                      sv->X->JumpFocusFace_prmpt);
2999 
3000             sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialog(
3001                      sv->X->Title, sv->X->JumpFocusFace_prmpt);
3002          } else {
3003             if (!strgval) {
3004                SUMA_S_Err("Have NULL string");
3005                SUMA_RETURN(0);
3006             }
3007             SUMA_JumpFocusFace( strgval, (void *)sv);
3008          }
3009          break;
3010       default:
3011          SUMA_S_Err("Il ne faut pas etre ici");
3012          SUMA_RETURN(0);
3013          break;
3014    }
3015    SUMA_RETURN(1);
3016 }
3017 
SUMA_L_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)3018 int SUMA_L_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode, char *strgval)
3019 {
3020    static char FuncName[]={"SUMA_L_Key"};
3021    char tk[]={"L"}, keyname[100];
3022    int k, nc;
3023    SUMA_EngineData *ED = NULL;
3024    DList *list = NULL;
3025    DListElmt *NextElm= NULL;
3026    SUMA_Boolean LocalHead = NOPE;
3027 
3028    SUMA_ENTRY;
3029 
3030    // fprintf(stderr, "%s\n", FuncName);
3031 
3032    SUMA_KEY_COMMON;
3033    if (strgval) {
3034       SUMA_S_Warn("strgval (%s) not implemented for L_Key yet. \n"
3035                   "Complain to author if you want it.\n", strgval);
3036    }
3037    /* do the work */
3038    switch (k) {
3039       case XK_l:
3040             if ((SUMA_CTRL_KEY(key))){
3041                #if 0 /* Not of much use */
3042                if (SUMAg_CF->Dev) {
3043                   if (!list) list = SUMA_CreateList();
3044                   ED = SUMA_InitializeEngineListData (SE_ToggleLockAllCrossHair);
3045                   if (!SUMA_RegisterEngineListCommand (  list, ED,
3046                                                    SEF_Empty, NULL,
3047                                                   SES_Suma, (void *)sv, NOPE,
3048                                                   SEI_Head, NULL )) {
3049                      fprintf( SUMA_STDERR,
3050                               "Error %s: Failed to register command\n",
3051                               FuncName);
3052                      break;
3053                   }
3054                   if (!SUMA_Engine (&list)) {
3055                      fprintf( stderr,
3056                               "Error %s: SUMA_Engine call failed.\n", FuncName);
3057                   }
3058                }
3059                #else
3060                GLfloat light0_color[] = { SUMA_LIGHT0_COLOR_INIT};
3061                   /* dim the lights */
3062                   sv->dim_spe = sv->dim_spe * 0.8;
3063                      if (sv->dim_spe < 0.1) sv->dim_spe = 1.0;
3064                   sv->dim_dif = sv->dim_dif * 0.8;
3065                      if (sv->dim_dif < 0.1) sv->dim_dif = 1.0;
3066                   sv->dim_amb = sv->dim_amb * 0.8;
3067                      if (sv->dim_amb < 0.1) sv->dim_amb = 1.0;
3068                   sv->dim_emi = sv->dim_emi * 0.8;
3069                      if (sv->dim_emi < 0.1) sv->dim_emi = 1.0;
3070                   fprintf(SUMA_STDERR,
3071                            "%s:  light dim factor now %.3f\n",
3072                            FuncName, sv->dim_spe);
3073                   /*fprintf(SUMA_STDERR,"%s:  light dim factor now %.3f\n"
3074                                         "%f %f %f %f\n",
3075                                         FuncName, sv->dim_spe,
3076                            sv->light0_color[0], sv->light0_color[1],
3077                            sv->light0_color[2], sv->light0_color[3]);
3078                                                       */
3079                   light0_color[0] = sv->light0_color[0]*sv->dim_spe;
3080                   light0_color[1] = sv->light0_color[1]*sv->dim_spe;
3081                   light0_color[2] = sv->light0_color[2]*sv->dim_spe;
3082                   light0_color[3] = sv->light0_color[3]*sv->dim_spe;
3083                   glLightfv(GL_LIGHT0, GL_SPECULAR, light0_color);
3084                   light0_color[0] = sv->light0_color[0]*sv->dim_dif;
3085                   light0_color[1] = sv->light0_color[1]*sv->dim_dif;
3086                   light0_color[2] = sv->light0_color[2]*sv->dim_dif;
3087                   light0_color[3] = sv->light0_color[3]*sv->dim_dif;
3088                   glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
3089                   light0_color[0] = sv->lmodel_ambient[0]*sv->dim_amb;
3090                   light0_color[1] = sv->lmodel_ambient[1]*sv->dim_amb;
3091                   light0_color[2] = sv->lmodel_ambient[2]*sv->dim_amb;
3092                   light0_color[3] = sv->lmodel_ambient[3]*sv->dim_amb;
3093                   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, sv->lmodel_ambient);
3094                   if (!list) list = SUMA_CreateList();
3095                   SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
3096                                                       SES_Suma, sv);
3097 
3098                   if (!SUMA_Engine (&list)) {
3099                      fprintf(stderr,
3100                              "Error SUMA_input: SUMA_Engine call failed.\n");
3101                   }
3102                #endif
3103             } else if ((SUMA_AALT_KEY(key))){ /* alt + l */
3104                /* register cross hair XYZ with ED */
3105                if (!list) list = SUMA_CreateList();
3106                ED = SUMA_InitializeEngineListData (SE_SetLookAt);
3107                if (!SUMA_RegisterEngineListCommand (  list, ED,
3108                                                 SEF_fv3, (void *)sv->Ch->c,
3109                                                 SES_Suma, (void *)sv, NOPE,
3110                                                 SEI_Head, NULL )) {
3111                   fprintf( SUMA_STDERR,
3112                            "Error %s: Failed to register command\n", FuncName);
3113                   SUMA_RETURN(0);
3114                }
3115                if (!SUMA_Engine (&list)) {
3116                   fprintf(stderr,
3117                            "Error %s: SUMA_Engine call failed.\n", FuncName);
3118                }
3119             } else {
3120                sv->X->LookAt_prmpt = SUMA_CreatePromptDialogStruct(
3121                                           SUMA_OK_APPLY_CLEAR_CANCEL,
3122                                           "X,Y,Z coordinates to look at:",
3123                                           "0,0,0",
3124                                           sv->X->TOPLEVEL, YUP,
3125                                           SUMA_APPLY_BUTTON,
3126                                           SUMA_LookAtCoordinates, (void *)sv,
3127                                           NULL, NULL,
3128                                           NULL, NULL,
3129                                           SUMA_CleanNumString, (void*)3,
3130                                           sv->X->LookAt_prmpt);
3131 
3132                sv->X->LookAt_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
3133                                                          sv->X->LookAt_prmpt);
3134 
3135             }
3136          break;
3137       case XK_L:
3138                if ((SUMA_CTRL_KEY(key))){
3139                   GLfloat light0_color[] = { SUMA_LIGHT0_COLOR_INIT};
3140                   /* brighten the lights */
3141                   sv->dim_spe = sv->dim_spe / 0.8;
3142                   if (sv->dim_spe > 1) sv->dim_spe = 0.1;
3143                   sv->dim_dif = sv->dim_dif / 0.8;
3144                      if (sv->dim_dif > 1) sv->dim_dif = 0.1;
3145                   sv->dim_amb = sv->dim_amb / 0.8;
3146                      if (sv->dim_amb > 1) sv->dim_amb = 0.1;
3147                   sv->dim_emi = sv->dim_emi / 0.8;
3148                      if (sv->dim_emi > 1) sv->dim_emi = 0.1;
3149                      fprintf(SUMA_STDERR,
3150                               "%s:  light dim factor now %.3f\n",
3151                               FuncName, sv->dim_spe);
3152                      /*fprintf(SUMA_STDERR,"%s:  light dim factor now %.3f\n"
3153                                            "%f %f %f %f\n",
3154                                            FuncName, sv->dim_spe,
3155                               sv->light0_color[0], sv->light0_color[1],
3156                               sv->light0_color[2], sv->light0_color[3]);
3157                                                          */
3158                      light0_color[0] = sv->light0_color[0]*sv->dim_spe;
3159                      light0_color[1] = sv->light0_color[1]*sv->dim_spe;
3160                      light0_color[2] = sv->light0_color[2]*sv->dim_spe;
3161                      light0_color[3] = sv->light0_color[3]*sv->dim_spe;
3162                      glLightfv(GL_LIGHT0, GL_SPECULAR, light0_color);
3163                      light0_color[0] = sv->light0_color[0]*sv->dim_dif;
3164                      light0_color[1] = sv->light0_color[1]*sv->dim_dif;
3165                      light0_color[2] = sv->light0_color[2]*sv->dim_dif;
3166                      light0_color[3] = sv->light0_color[3]*sv->dim_dif;
3167                      glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
3168                      light0_color[0] = sv->lmodel_ambient[0]*sv->dim_amb;
3169                      light0_color[1] = sv->lmodel_ambient[1]*sv->dim_amb;
3170                      light0_color[2] = sv->lmodel_ambient[2]*sv->dim_amb;
3171                      light0_color[3] = sv->lmodel_ambient[3]*sv->dim_amb;
3172                      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, sv->lmodel_ambient);
3173                      if (!list) list = SUMA_CreateList();
3174                      SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
3175                                                          SES_Suma, sv);
3176 
3177                      if (!SUMA_Engine (&list)) {
3178                         fprintf(stderr,
3179                                 "Error SUMA_input: SUMA_Engine call failed.\n");
3180                      }
3181                } else if ((SUMA_AALT_KEY(key))){
3182 
3183                } else {
3184                   SUMA_PROMPT_DIALOG_STRUCT *prmpt;
3185                   prmpt = SUMA_CreatePromptDialogStruct (
3186                                  SUMA_OK_APPLY_CLEAR_CANCEL,
3187                                  "X,Y,Z coordinates of light0:",
3188                                  "",
3189                                  sv->X->TOPLEVEL, NOPE,
3190                                  SUMA_APPLY_BUTTON,
3191                                  SUMA_SetLight0, (void *)sv,
3192                                  NULL, NULL,
3193                                  NULL, NULL,
3194                                  SUMA_CleanNumString, (void*)3,
3195                                  NULL);
3196 
3197                   prmpt = SUMA_CreatePromptDialog(sv->X->Title, prmpt);
3198                }
3199 
3200          break;
3201       default:
3202          SUMA_S_Err("Il ne faut pas etre ici");
3203          SUMA_RETURN(0);
3204          break;
3205    }
3206 
3207    SUMA_RETURN(1);
3208 }
3209 
SUMA_M_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3210 int SUMA_M_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3211 {
3212    static char FuncName[]={"SUMA_M_Key"};
3213    char tk[]={"M"}, keyname[100];
3214    int k, nc;
3215    SUMA_Boolean LocalHead = NOPE;
3216 
3217    SUMA_ENTRY;
3218 
3219    // fprintf(stderr, "%s\n", FuncName);
3220 
3221    SUMA_KEY_COMMON;
3222 
3223    /* do the work */
3224    switch (k) {
3225       case XK_m:
3226          if ((SUMA_CTRL_KEY(key))) {
3227             SUMA_SurfaceObject *SO;
3228             float fv3[3];
3229             int it;
3230             fprintf(SUMA_STDOUT, "%s: Enter shift in mm [RAI] "
3231                                  "to apply to all mappable surfaces in DOv.\n",
3232                                  FuncName);
3233             it = SUMA_ReadNumStdin (fv3, 3);
3234             if (it > 0 && it < 3) {
3235                fprintf(SUMA_STDERR,"Error %s: read %d values, expected 3.\n",
3236                                     FuncName, it);
3237                SUMA_RETURN(0);
3238             }else if (it < 0) {
3239                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n",
3240                                     FuncName);
3241                SUMA_RETURN(0);
3242             }else if (it == 0) {
3243                fprintf(SUMA_STDERR,"%s: Nothing read.\n", FuncName);
3244                SUMA_RETURN(0);
3245             }
3246 
3247             for (it = 0; it < SUMAg_N_DOv; ++it) {
3248                if (SUMA_isSO_G (SUMAg_DOv[it], sv->CurGroupName)) {
3249                   SO = (SUMA_SurfaceObject *)SUMAg_DOv[it].OP;
3250                   if (SUMA_isLocalDomainParent(SO)) {
3251                      int imax, ii;
3252                      /* add the shift */
3253                      fprintf (SUMA_STDERR,
3254                               "%s: Shifting %s by %f %f %f mm RAI.\n",
3255                               FuncName, SO->Label, fv3[0], fv3[1], fv3[2]);
3256                      ii = 0;
3257                      imax = 3 * SO->N_Node;
3258                      while (ii < imax) {
3259                         SO->NodeList[ii] += fv3[0]; ++ii;
3260                         SO->NodeList[ii] += fv3[1]; ++ii;
3261                         SO->NodeList[ii] += fv3[2]; ++ii;
3262                      }
3263                   }
3264                }
3265             }
3266 
3267             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3268          } else {
3269             sv->GVS[sv->StdView].ApplyMomentum =
3270                                  !sv->GVS[sv->StdView].ApplyMomentum;
3271             SUMA_UpdateViewerTitle(sv);
3272             if (sv->GVS[sv->StdView].ApplyMomentum) {
3273                 sv->X->MOMENTUMID = XtAppAddTimeOut(
3274                                        SUMAg_CF->X->App, 1,
3275                                        SUMA_momentum,
3276                                        (XtPointer) sv->X->GLXAREA);
3277                 /* wait till user initiates turning */
3278                sv->GVS[sv->StdView].spinDeltaX = 0;
3279                sv->GVS[sv->StdView].spinDeltaY = 0;
3280                sv->GVS[sv->StdView].translateDeltaX = 0;
3281                sv->GVS[sv->StdView].translateDeltaY = 0;
3282             } else {
3283                if (sv->X->MOMENTUMID)  {
3284                   XtRemoveTimeOut(sv->X->MOMENTUMID);
3285                   sv->X->MOMENTUMID = 0;
3286                }
3287             }
3288          }
3289          break;
3290       case XK_M:
3291          if (SUMA_CTRL_KEY(key) && (SUMA_ALT_KEY(key) || SUMA_APPLE_KEY(key)) ) {
3292             #ifdef ALLOW_MCW_MALLOC
3293             /* write memtrace results to disk */
3294             if (!mcw_malloc_enabled()) {
3295                if (callmode && strcmp(callmode, "interactive") == 0) {
3296                   SUMA_SLP_Warn("Memory tracing\n"
3297                                "is not enabled.\n"
3298                                "Use Help-->MemTrace.");
3299                } else {
3300                   SUMA_S_Warn("Memory tracing\n"
3301                                "is not enabled.\n"
3302                                "Use Help-->MemTrace.");
3303                }
3304                SUMA_RETURN(0);
3305             } else {
3306                if (callmode && strcmp(callmode, "interactive") == 0) {
3307                   SUMA_SLP_Note("Dumping memory tracing\n"
3308                                "to latest ./malldump.???\n"
3309                                "file (if possible).");
3310                } else {
3311                   SUMA_S_Note("Dumping memory tracing\n"
3312                                "to latest ./malldump.???\n"
3313                                "file (if possible).");
3314                }
3315                mcw_malloc_dump_sort(1);
3316             }
3317             #else
3318                if (callmode && strcmp(callmode, "interactive") == 0) {
3319                   SUMA_SLP_Warn("Sorry, memory tracing\n"
3320                              "was not enabled at compile.\n"
3321                              "time. You are out of luck\n"
3322                              "if using SUN.");
3323                } else {
3324                   SUMA_S_Warn("Sorry, memory tracing\n"
3325                              "was not enabled at compile.\n"
3326                              "time. You are out of luck\n"
3327                              "if using SUN.");
3328                }
3329                SUMA_RETURN(0);
3330             #endif
3331          }
3332          break;
3333       default:
3334          SUMA_S_Err("Il ne faut pas etre ici");
3335          SUMA_RETURN(0);
3336          break;
3337    }
3338 
3339    SUMA_RETURN(1);
3340 }
3341 
SUMA_N_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3342 int SUMA_N_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3343 {
3344    static char FuncName[]={"SUMA_N_Key"};
3345    char tk[]={"N"}, keyname[100];
3346    int k, nc, it;
3347    float fv15[15];
3348    SUMA_EngineData *ED = NULL;
3349    DList *list = NULL;
3350    DListElmt *NextElm= NULL;
3351    SUMA_Boolean LocalHead = NOPE;
3352 
3353    SUMA_ENTRY;
3354 
3355    // fprintf(stderr, "%s\n", FuncName);
3356 
3357    SUMA_KEY_COMMON;
3358 
3359    /* do the work */
3360    switch (k) {
3361       case XK_N:
3362          break;
3363       case XK_n:
3364          if (SUMA_CTRL_KEY(key)) {
3365             SUMA_LH("Opening a new controller...");
3366             /* open a new controller */
3367             if (!SUMA_X_SurfaceViewer_Create ()) {
3368                SUMA_S_Err("Failed in SUMA_X_SurfaceViewer_Create.");
3369                SUMA_RETURN(0);
3370             }
3371          } else {
3372             fprintf(stdout,"BAD IDEA Enter XYZ of center followed by size of Box (enter nothing to cancel):\n");
3373             it = SUMA_ReadNumStdin (fv15, 6);
3374             if (it > 0 && it < 6) {
3375                fprintf(SUMA_STDERR,"Error %s: read %d values, expected 6.\n", FuncName, it);
3376                SUMA_RETURN(0);
3377             }else if (it < 0) {
3378                fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n", FuncName);
3379                SUMA_RETURN(0);
3380             }else if (it == 0) {
3381                SUMA_RETURN(0);
3382             }
3383 
3384             fprintf (SUMA_STDOUT, "Parsed Input:\n\tCenter %f, %f, %f.\n\tBox Size %f, %f, %f\n", \
3385                fv15[0], fv15[1],fv15[2],\
3386                fv15[3], fv15[4],fv15[5]);
3387 
3388             /* register fv15 with ED */
3389             if (!list) list = SUMA_CreateList ();
3390             ED = SUMA_InitializeEngineListData (SE_GetNearestNode);
3391             if (!SUMA_RegisterEngineListCommand (  list, ED,
3392                                                    SEF_fv15, (void *)fv15,
3393                                                    SES_Suma, (void *)sv, NOPE,
3394                                                    SEI_Head, NULL )) {
3395                fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
3396                break;
3397             }
3398 
3399             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
3400             if (!SUMA_Engine (&list)) {
3401                fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
3402             }
3403          }
3404          break;
3405       default:
3406          SUMA_S_Err("Il ne faut pas etre ici");
3407          SUMA_RETURN(0);
3408          break;
3409    }
3410 
3411    SUMA_RETURN(1);
3412 }
3413 
3414 /*!
3415    Execute commands when O or o is pressed
3416 */
SUMA_O_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3417 int SUMA_O_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3418 {
3419    static char FuncName[]={"SUMA_O_Key"};
3420    char tk[]={"O"}, keyname[100];
3421    int k, nc;
3422    int N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS];
3423    SUMA_ALL_DO *ado=NULL;
3424    SUMA_SurfaceObject *SO = NULL;
3425 
3426    SUMA_Boolean LocalHead = NOPE;
3427 
3428    SUMA_ENTRY;
3429 
3430    // fprintf(stderr, "%s\n", FuncName);
3431 
3432    SUMA_KEY_COMMON;
3433 
3434    /* do the work */
3435    switch (k) {
3436       case XK_O:
3437          if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3438 
3439          } else if (SUMA_CTRL_KEY(key)) {
3440             if ((ado = SUMA_SV_Focus_ADO(sv))) {
3441                SUMA_Set_ADO_TransMode(ado, sv->TransMode,
3442                                       SUMAg_CF->TransModeStep, 1);
3443                SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3444             }
3445          } else {
3446             sv->TransMode = ((sv->TransMode-SUMAg_CF->TransModeStep) %
3447                                                       (STM_N_TransModes-2));
3448             if (sv->TransMode <= STM_ViewerDefault) sv->TransMode = STM_16;
3449 
3450             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3451          }
3452          break;
3453       case XK_o:
3454          if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3455            sv->X->SetRot_prmpt = SUMA_CreatePromptDialogStruct (
3456                   SUMA_OK_APPLY_CLEAR_CANCEL, "Center of Rotation X,Y,Z:",
3457                   "0,0,0",
3458                   sv->X->TOPLEVEL, YUP,
3459                   SUMA_APPLY_BUTTON,
3460                   SUMA_SetRotCenter, (void *)sv,
3461                   NULL, NULL,
3462                   NULL, NULL,
3463                   NULL, NULL,
3464                   sv->X->SetRot_prmpt);
3465 
3466             sv->X->SetRot_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
3467                                                           sv->X->SetRot_prmpt);
3468          } else if (SUMA_CTRL_KEY(key)) {
3469             if ((ado = SUMA_SV_Focus_ADO(sv))) {
3470                SUMA_Set_ADO_TransMode(ado, sv->TransMode,
3471                                       -SUMAg_CF->TransModeStep, 1);
3472                SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3473             }
3474          } else {
3475             sv->TransMode = ((sv->TransMode+SUMAg_CF->TransModeStep) %
3476                                                       (STM_N_TransModes-2));
3477             if (sv->TransMode <= STM_ViewerDefault) sv->TransMode = STM_0;
3478 
3479             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3480          }
3481          break;
3482       default:
3483          SUMA_S_Err("Il ne faut pas etre ici");
3484          SUMA_RETURN(0);
3485          break;
3486    }
3487 
3488    SUMA_RETURN(1);
3489 }
3490 
3491 /*!
3492    Execute commands when P or p is pressed
3493 */
SUMA_P_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3494 int SUMA_P_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3495 {
3496    static char FuncName[]={"SUMA_P_Key"};
3497    char tk[]={"P"}, keyname[100], msg[100];
3498    int k, nc;
3499    int N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS];
3500    SUMA_SurfaceObject *SO = NULL;
3501    SUMA_ALL_DO *ado=NULL;
3502    SUMA_Boolean LocalHead = NOPE;
3503 
3504    SUMA_ENTRY;
3505 
3506    // fprintf(stderr, "%s\n", FuncName);
3507 
3508    SUMA_KEY_COMMON;
3509 
3510    /* do the work */
3511    switch (k) {
3512       case XK_P:
3513          if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3514          } else if (SUMA_CTRL_KEY(key)) {
3515 
3516          } else {
3517             sv->PolyMode = SRM_Fill;
3518             N_SOlist = SUMA_RegisteredSOs(sv, SUMAg_DOv, SOlist);
3519             for (k=0; k<N_SOlist; ++k) {
3520                SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SOlist[k]].OP);
3521                SO->PolyMode = SRM_ViewerDefault;
3522                SO->Show = YUP;
3523             }
3524             SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
3525             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3526             SUMA_SLP_Note("All surfaces displayed as solids");
3527          }
3528          break;
3529       case XK_p:
3530          if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3531             sv->DO_DrawMask = ((sv->DO_DrawMask+1) % SDODM_N_DO_DrawMasks);
3532             snprintf(msg,100*sizeof(char),"DO DrawMask now set to: %s",
3533                         SUMA_DO_DrawMaskCode2Name_human(sv->DO_DrawMask));
3534             if (callmode && strcmp(callmode, "interactive") == 0) {
3535                   SUMA_SLP_Note ("%s",msg);
3536             } else { SUMA_S_Note ("%s",msg); }
3537          } else if (SUMA_CTRL_KEY(key)) {
3538             if ((ado = SUMA_SV_Focus_ADO(sv))) {
3539                SUMA_Set_ADO_RenderMode(ado, sv->PolyMode, -1, 1);
3540             }
3541          } else {
3542             sv->PolyMode = ((sv->PolyMode+1) % SRM_N_RenderModes);
3543             if (sv->PolyMode <= SRM_ViewerDefault) sv->PolyMode = SRM_Fill;
3544 
3545             SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
3546          }
3547          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3548          break;
3549       default:
3550          SUMA_S_Err("Il ne faut pas etre ici");
3551          SUMA_RETURN(0);
3552          break;
3553    }
3554 
3555    SUMA_RETURN(1);
3556 }
3557 
3558 /*!
3559    Execute commands when R or r is pressed
3560 */
SUMA_R_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3561 int SUMA_R_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3562 {
3563    static char FuncName[]={"SUMA_R_Key"};
3564    char tk[]={"R"}, keyname[100], msg[100];
3565    int k, nc, ii, jj, mm;
3566    SUMA_Boolean LocalHead = NOPE;
3567 
3568    SUMA_ENTRY;
3569 
3570    // fprintf(stderr, "%s\n", FuncName);
3571 
3572    SUMA_KEY_COMMON;
3573 
3574    /* do the work */
3575    switch (k) {
3576       case XK_r:
3577          if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3578             SUMAg_CF->SUMA_SnapshotOverSampling =
3579                   (SUMAg_CF->SUMA_SnapshotOverSampling +1)%5;
3580             if (SUMAg_CF->SUMA_SnapshotOverSampling == 0)
3581                      SUMAg_CF->SUMA_SnapshotOverSampling = 1;
3582             {
3583                sprintf(msg,"Oversampling now set to %d",
3584                            SUMAg_CF->SUMA_SnapshotOverSampling);
3585                if (callmode && strcmp(callmode, "interactive") == 0) {
3586                   SUMA_SLP_Note ("%s",msg);
3587                } else { SUMA_S_Note ("%s",msg); }
3588             }
3589          } else if (SUMA_CTRL_KEY(key)) {
3590             #if 0
3591             sv->X->SetRot_prmpt = SUMA_CreatePromptDialogStruct (
3592                   SUMA_OK_APPLY_CLEAR_CANCEL, "Center of Rotation X,Y,Z:",
3593                   "0,0,0",
3594                   sv->X->TOPLEVEL, YUP,
3595                   SUMA_APPLY_BUTTON,
3596                   SUMA_SetRotCenter, (void *)sv,
3597                   NULL, NULL,
3598                   NULL, NULL,
3599                   NULL, NULL,
3600                   sv->X->SetRot_prmpt);
3601 
3602             sv->X->SetRot_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
3603                                                           sv->X->SetRot_prmpt);
3604             #else
3605             /* save image to disk */
3606             SUMA_SnapToDisk(sv,1, 0);
3607             #endif
3608          } else {
3609             GLvoid *pixels=NULL;
3610             double rat;
3611             int oareah=-1,oareaw=-1, owindh=-1, owindw=-1;
3612             /* Control for GL_MAX_VIEWPORT_DIMS */
3613             if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3614                glGetIntegerv(GL_MAX_VIEWPORT_DIMS,&k);
3615                mm = SUMA_MAX_PAIR(
3616                      SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aHEIGHT,
3617                      SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH);
3618                if (mm > k) { /* too big, find best new dimesnions */
3619                   rat = (double)mm/(double)k;
3620                      /*window shrinking factor to allow for stitching*/
3621                   SUMA_S_Notev(  "%d/%d (H/W) Too big for oversampling\n"
3622                                  " reducing resolution by %f.\n",
3623                                  sv->X->aHEIGHT, sv->X->aWIDTH, rat);
3624                   /* store original size */
3625                   oareaw = sv->X->aWIDTH; oareah = sv->X->aHEIGHT;
3626                   owindw = sv->wWindWidth; owindh = sv->wWindHeight;
3627                   sv->X->aHEIGHT =
3628                      (int)((double)sv->X->aHEIGHT/rat)-1;
3629                   sv->X->aWIDTH =
3630                      (int)((double)sv->X->aWIDTH/rat)-1;
3631                   SUMA_SV_WindDims_From_DrawAreaDims(sv);
3632                   SUMA_WidgetResize (sv->X->TOPLEVEL ,
3633                                      sv->wWindWidth, sv->wWindHeight);
3634                   sv->rdc = SUMA_RDC_X_RESIZE;
3635                   glViewport( 0, 0,
3636                                  sv->X->aWIDTH, sv->X->aHEIGHT);
3637                   SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3638                } else {
3639                   SUMA_S_Note("Size OK");
3640                }
3641             }
3642             /* turn off checking for duplicates */
3643             for (jj=0; jj<SUMAg_CF->SUMA_SnapshotOverSampling; ++jj) {
3644                for (ii=0; ii<SUMAg_CF->SUMA_SnapshotOverSampling; ++ii) {
3645                   if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3646                      glGetIntegerv(GL_MAX_VIEWPORT_DIMS,&k);
3647                      if (ii==0 && jj == 0) {
3648                         SUMA_S_Notev(  "Resampling factor of %d\n"
3649                                     "If using this feature, the\n"
3650                                     " sequence of %d images is saved\n"
3651                                     " temporarily to disk and '2dcat'\n"
3652                                     " is then used to put the images together.\n"
3653                                     "(Have ViewPort GL_MAX_VIEWPORT_DIMS of %d\n"
3654                                     " and max dims needed of %d.)\n",
3655                            SUMAg_CF->SUMA_SnapshotOverSampling,
3656                            SUMAg_CF->SUMA_SnapshotOverSampling *
3657                               SUMAg_CF->SUMA_SnapshotOverSampling,
3658                            k,
3659                            SUMA_MAX_PAIR( SUMAg_CF->SUMA_SnapshotOverSampling *
3660                               sv->X->aHEIGHT,
3661                            SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH)  );
3662                      } else {
3663                         /* sometimes you have repeated black areas when
3664                         oversampling, allow that after very first 'tant' */
3665                         SNAP_OkDuplicates();
3666                      }
3667                      /* start from top left, move to right then go down
3668                         one row (Row Major, starting on top left ) */
3669                      glViewport(-ii*sv->X->aWIDTH,
3670                                 -(SUMAg_CF->SUMA_SnapshotOverSampling - jj - 1) *
3671                                   sv->X->aHEIGHT,
3672                                SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH,
3673                                 SUMAg_CF->SUMA_SnapshotOverSampling *
3674                                  sv->X->aHEIGHT);
3675                      SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3676                      #if 0 /* problem should be fixed by SUMA_grabRenderedPixels
3677                               Throw section out if no new problems arise.
3678                               Search for KILL_DOUBLE_RENDERING to locate
3679                               other chunks for removal
3680                                        ZSS Feb 2012 */
3681                         if (1) {
3682                            /* seems to fix an problem with snapping the older
3683                            image... at least on mac
3684                            None of glFlush(); glFinish();glXWaitGL();glXWaitX();
3685                            or NI_sleep did the trick
3686                            Perhaps the wrong buffer is being grabbed?
3687                            Check SUMA_grabPixels ...
3688                                  ZSS Feb 2012.
3689                            Yes it was,  SUMA_grabRenderedPixels does the trick.
3690                                  ZSS Feb the next morning 2012 */
3691                            SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3692                         }
3693                      #endif
3694                   } else {
3695                      #if 0 /* Search for KILL_DOUBLE_RENDERING to locate
3696                               other chunks for removal
3697                                        ZSS Feb 2012 */
3698                   /* ZSS   Nov 20 2009
3699                      If you do not redisplay here, you could strange cases of
3700                      snapping the previous frame as reported by Colm Connolly.
3701 
3702                   1. suma -spec N27_both_tlrc.spec -sv TT_N27+tlrc. &
3703                   2. press F2 five times to cycle through the various axes
3704                      from none to all and back to none.
3705                   3. press r to record
3706 
3707                   The first image recorded has axes present even though none
3708                   are present in the viewer. Pressing r again produces an
3709                   image with no axes as expected.
3710 
3711                   Actually, it seems this happens in many other cases, F1, F6,
3712                   change state, etc.
3713 
3714                   This seems to be the same problem reported by Chunmao W.
3715                   a while back.
3716                   Same happens with R option.
3717 
3718                   Problem only happens under DARWIN it seems.
3719 
3720                   I do not know why the call to SUMA_handleRedisplay does the
3721                   trick. Perhaps it is a buffer reading problem in double
3722                   buffer rendering. The fix is ugly, especially in continuous
3723                   record mode (see SUMA_display function in 'if(csv->record)'
3724                   block), but it works.
3725                   */
3726                         #ifdef DARWIN
3727                         SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3728                         #endif
3729                      #endif
3730                   }
3731                   pixels = SUMA_grabRenderedPixels(sv, 3,
3732                                        sv->X->aWIDTH, sv->X->aHEIGHT, 0);
3733                   if (pixels) {
3734                     ISQ_snapsave (sv->X->aWIDTH, -sv->X->aHEIGHT,
3735                                   (unsigned char *)pixels, sv->X->GLXAREA );
3736                     SUMA_free(pixels);
3737                   }else {
3738                      if (callmode && strcmp(callmode, "interactive") == 0) {
3739                         SUMA_SLP_Err("Failed to record image.");
3740                      } else { SUMA_S_Err("Failed to record image.");}
3741                   }
3742                }
3743             }
3744             if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3745                         /* Now return the window to its previous size */
3746                if (owindw > 0) {
3747                   sv->wWindHeight = owindh;
3748                   sv->X->aHEIGHT = oareah;
3749                   sv->wWindWidth = owindw;
3750                   sv->X->aWIDTH = oareaw;
3751                   SUMA_WidgetResize (sv->X->TOPLEVEL , owindw, owindh);
3752                }
3753                sv->rdc = SUMA_RDC_X_RESIZE;
3754                glViewport( 0, 0,
3755                            sv->X->aWIDTH, sv->X->aHEIGHT);
3756                SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3757             }
3758             if (SUMAg_CF->NoDuplicatesInRecorder) SNAP_NoDuplicates();
3759             else SNAP_OkDuplicates();
3760             if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3761                /* record the image to make life easy on user */
3762                sprintf(msg,"Writing resultant image\n"
3763                            " to HighRes_Suma_tmp.ppm ...");
3764                if (callmode && strcmp(callmode, "interactive") == 0) {
3765                   SUMA_SLP_Note ("%s",msg);
3766                } else { SUMA_S_Note ("%s",msg); }
3767                ISQ_snap_png_rng("HighRes_Photo___tmp",
3768                                 -(SUMAg_CF->SUMA_SnapshotOverSampling *
3769                                   SUMAg_CF->SUMA_SnapshotOverSampling),
3770                                 0);
3771                /* use explicit tcsh to avoid sh syntax  25 Apr 2017 [rickr] */
3772                system(  "tcsh -c 'rm -f HighRes_Suma_tmp* >& /dev/null' ; "
3773                         "2dcat -prefix HighRes_Suma_tmp HighRes_Photo___tmp* ; "
3774                         "rm -f HighRes_Photo___tmp*");
3775             }
3776          }
3777          break;
3778       case XK_R:
3779          if (SUMA_CTRL_KEY(key)) {
3780             char sbuf[256];
3781             sv->Record = !sv->Record;
3782             if (sv->Record) sv->Record = 2;
3783             if (sv->Record) {
3784                SUMA_VALIDATE_RECORD_PATH(SUMAg_CF->autorecord);
3785                snprintf(sbuf,256*sizeof(char),
3786                         "Disk Recording ON to: %s%s*",
3787                            SUMAg_CF->autorecord->Path,
3788                            SUMAg_CF->autorecord->FileName_NoExt);
3789                if (callmode && strcmp(callmode, "interactive") == 0) {
3790                   SUMA_SLP_Note ("%s",sbuf); }
3791                else { SUMA_S_Note ("%s",sbuf); }
3792             } else {
3793                snprintf(sbuf,256*sizeof(char),
3794                         "Disk Recording OFF. Results in: %s%s*",
3795                            SUMAg_CF->autorecord->Path,
3796                            SUMAg_CF->autorecord->FileName_NoExt);
3797                if (callmode && strcmp(callmode, "interactive") == 0) {
3798                   SUMA_SLP_Note ("%s",sbuf); }
3799                else { SUMA_S_Note ("%s",sbuf);}
3800             }
3801             SUMA_UpdateViewerTitle(sv);
3802          } else {
3803             sv->Record = !sv->Record;
3804             if (sv->Record) {
3805                if (callmode && strcmp(callmode, "interactive") == 0) {
3806                   SUMA_SLP_Note ("Recording ON"); }
3807                else { SUMA_S_Note ("Recording ON"); }
3808             } else {
3809                if (callmode && strcmp(callmode, "interactive") == 0) {
3810                   SUMA_SLP_Note ("Recording OFF"); }
3811                else { SUMA_S_Note ("Recording OFF");}
3812             }
3813             SUMA_UpdateViewerTitle(sv);
3814          }
3815          break;
3816       default:
3817          SUMA_S_Err("Il ne faut pas etre ici");
3818          SUMA_RETURN(0);
3819          break;
3820    }
3821 
3822    SUMA_RETURN(1);
3823 }
3824 
SUMA_S_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3825 int SUMA_S_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3826 {
3827    static char FuncName[]={"SUMA_S_Key"};
3828    char tk[]={"S"}, keyname[100];
3829    int k, nc;
3830    SUMA_EngineData *ED = NULL;
3831    DList *list = NULL;
3832    DListElmt *NextElm= NULL;
3833    SUMA_Boolean LocalHead = NOPE;
3834 
3835    SUMA_ENTRY;
3836 
3837    SUMA_KEY_COMMON;
3838 
3839    switch (k) {
3840      case XK_S:
3841         if (clippingPlaneMode){
3842             clipPlaneTransform(0, 0, -scrollInc, 0,-1, 0, 0); // Scroll outward
3843         } else if (SUMAg_CF->Dev) {
3844            int *do_id, n_do_id;
3845            do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv,
3846                                    SO_type, &n_do_id);
3847            if (n_do_id) {
3848               while (n_do_id) {
3849                  SUMA_Print_Surface_Object(
3850                     (SUMA_SurfaceObject *)SUMAg_DOv[do_id[n_do_id-1]].OP,
3851                     stdout);
3852                  --n_do_id;
3853               }
3854               SUMA_free(do_id);
3855            }
3856         }
3857         break;
3858 
3859      case XK_s:
3860         if (clippingPlaneMode){
3861             clipPlaneTransform(0, 0, scrollInc, 0,-1, 0, 0);   // Scroll inward
3862            } else if ((SUMA_ALT_KEY(key)) && (SUMA_CTRL_KEY(key)) ){    // alt-ctrl-s
3863                if (!list) list = SUMA_CreateList();
3864                ED = SUMA_InitializeEngineListData (SE_LoadSegDO);
3865                if (!SUMA_RegisterEngineListCommand (  list, ED,
3866                                           SEF_ip, sv->X->TOPLEVEL,
3867                                           SES_Suma, (void *)sv, NOPE,
3868                                           SEI_Head, NULL)) {
3869                   fprintf (SUMA_STDERR,
3870                            "Error %s: Failed to register command.\n", FuncName);
3871                }
3872                if (!SUMA_Engine (&list)) {
3873                      fprintf( SUMA_STDERR,
3874                               "Error %s: SUMA_Engine call failed.\n",
3875                               FuncName);
3876                }
3877 
3878         } else if (SUMA_ALT_KEY(key)){
3879            /* swap buttons 1 and 3 */
3880            SUMAg_CF->SwapButtons_1_3 = !SUMAg_CF->SwapButtons_1_3;
3881            if (SUMAg_CF->SwapButtons_1_3) {
3882               fprintf (SUMA_STDOUT,
3883                        "%s: Buttons 1 and 3 are swapped.\n", FuncName);
3884            } else {
3885               fprintf (SUMA_STDOUT,
3886                        "%s: Default functions for buttons 1 and 3.\n",
3887                        FuncName);
3888            }
3889         }
3890 
3891         break;
3892    }
3893 
3894    SUMA_RETURN(1);
3895 }
3896 
SUMA_T_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3897 int SUMA_T_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3898 {
3899    static char FuncName[]={"SUMA_T_Key"};
3900    char tk[]={"T"}, keyname[100];
3901    int k, nc;
3902    SUMA_EngineData *ED = NULL;
3903    DList *list = NULL;
3904    DListElmt *NextElm= NULL;
3905    SUMA_Boolean LocalHead = NOPE;
3906 
3907    SUMA_ENTRY;
3908 
3909    // fprintf(stderr, "%s\n", FuncName);
3910 
3911    SUMA_KEY_COMMON;
3912 
3913    /* do the work */
3914    switch (k) {
3915       case XK_T:
3916          if (!list) list = SUMA_CreateList();
3917             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
3918                                     SE_StartListening, SES_Suma, sv);
3919 
3920          if (!SUMA_Engine (&list)) {
3921                fprintf(SUMA_STDERR,
3922                         "Error %s: SUMA_Engine call failed.\n", FuncName);
3923          }
3924          break;
3925       case XK_t:
3926          if ((SUMA_CTRL_KEY(key))){
3927                if (callmode && strcmp(callmode, "interactive") == 0) {
3928                      SUMA_SLP_Note("Forcing a resend of Surfaces to Afni...");}
3929                else { SUMA_S_Note("Forcing a resend of Surfaces to Afni..."); }
3930                if (!list) list = SUMA_CreateList();
3931                SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
3932                         SE_SetForceAfniSurf, SES_Suma, sv);
3933 
3934                if (!SUMA_Engine (&list)) {
3935                   fprintf(SUMA_STDERR,
3936                            "Error %s: SUMA_Engine call failed.\n", FuncName);
3937                }
3938          } else {
3939             if (!list) list = SUMA_CreateList();
3940             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
3941                            SE_ToggleConnected, SES_Suma, sv);
3942 
3943             if (!SUMA_Engine (&list)) {
3944                   fprintf(SUMA_STDERR,
3945                            "Error %s: SUMA_Engine call failed.\n", FuncName);
3946             }
3947          }
3948          break;
3949       default:
3950          SUMA_S_Err("Il ne faut pas ci dessous");
3951          SUMA_RETURN(0);
3952          break;
3953    }
3954 
3955    SUMA_RETURN(1);
3956 }
3957 
3958 /*!
3959    Execute commands when U or u is pressed
3960 */
SUMA_U_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3961 int SUMA_U_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3962 {
3963    static char FuncName[]={"SUMA_U_Key"};
3964    char tk[]={"U"}, keyname[100], msg[100];
3965    int k, nc, ii, jj, mm;
3966    SUMA_Boolean LocalHead = NOPE;
3967 
3968    SUMA_ENTRY;
3969 
3970    // fprintf(stderr, "%s\n", FuncName);
3971 
3972    SUMA_KEY_COMMON;
3973 
3974    /* do the work */
3975    switch (k) {
3976       case XK_u:
3977          if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3978             SUMA_LH("Nothing here");
3979          } else if (SUMA_CTRL_KEY(key)) {
3980             SUMA_viewSumaCont(1);
3981          } else {
3982             SUMA_LH("Keeping it real");
3983          }
3984          break;
3985       case XK_U:
3986          if (SUMA_CTRL_KEY(key)) {
3987 
3988          } else {
3989 
3990          }
3991          break;
3992       default:
3993          SUMA_S_Err("Il ne faut pas etre ici non plus");
3994          SUMA_RETURN(0);
3995          break;
3996    }
3997 
3998    SUMA_RETURN(1);
3999 }
4000 
4001 
SUMA_free_Save_List_El(void * selu)4002 void SUMA_free_Save_List_El(void *selu) {
4003    SUMA_SAVE_LIST_EL *sel=(SUMA_SAVE_LIST_EL *)selu;
4004    if (sel) {
4005       if (sel->identifier) SUMA_free(sel->identifier);
4006       if (sel->prefix) SUMA_free(sel->prefix);
4007       if (sel->type) SUMA_free(sel->type);
4008       SUMA_free(sel);
4009    }
4010    return;
4011 }
4012 
SUMA_Add_to_SaveList(DList ** SLp,char * type,char * identifier,char * prefix)4013 int SUMA_Add_to_SaveList(DList **SLp, char *type,
4014                          char *identifier, char *prefix)
4015 {
4016    static char FuncName[]={"SUMA_Add_to_SaveList"};
4017    DList *SL=NULL;
4018    DListElmt *el= NULL;
4019    SUMA_SAVE_LIST_EL *sel=NULL;
4020    SUMA_Boolean LocalHead = NOPE;
4021 
4022    SUMA_ENTRY;
4023 
4024    // fprintf(stderr, "%s\n", FuncName);
4025 
4026    if (!SLp || !type || !identifier || !prefix) SUMA_RETURN(0);
4027    SL = *SLp;
4028    if (!SL) {
4029       SL = (DList*)SUMA_malloc(sizeof(DList));
4030       dlist_init(SL, SUMA_free_Save_List_El);
4031    }
4032    SUMA_LH("Searching for possible identifier >%s<",
4033             identifier?identifier:"NULL");
4034    /* first make sure identifier is not there already */
4035    el = dlist_head(SL);
4036    while (el && identifier) {
4037       if ((sel = (SUMA_SAVE_LIST_EL *)el->data)) {
4038          if (sel->identifier &&
4039              !strcmp(sel->identifier, identifier)) {
4040             /* found, replace */
4041             SUMA_free(sel->identifier);
4042             sel->identifier = SUMA_copy_string(identifier);
4043                   identifier = NULL;
4044             SUMA_free(sel->prefix);
4045             sel->prefix = SUMA_copy_string(prefix);
4046                   prefix = NULL;
4047             SUMA_free(sel->type);
4048             sel->type = SUMA_copy_string(type);
4049                   type = NULL;
4050          }
4051       }
4052       el = dlist_next(el);
4053    }
4054    if (identifier) { /* a new one, should add it */
4055       sel = (SUMA_SAVE_LIST_EL *)SUMA_calloc(1,sizeof(SUMA_SAVE_LIST_EL));
4056       sel->identifier = SUMA_copy_string(identifier);
4057       sel->prefix = SUMA_copy_string(prefix);
4058       sel->type =  SUMA_copy_string(type);
4059       dlist_ins_next(SL, dlist_tail(SL), (void *)sel);
4060    }
4061 
4062    if (LocalHead) {
4063       SUMA_Show_SaveList(SL, "SaveList now:\n");
4064    }
4065 
4066    *SLp = SL;
4067    SUMA_RETURN(1);
4068 }
4069 
SUMA_Show_SaveList(DList * SL,char * head)4070 void SUMA_Show_SaveList(DList *SL, char *head)
4071 {
4072    static char FuncName[]={"SUMA_Show_SaveList"};
4073    FILE *out=NULL;
4074    DListElmt *el= NULL;
4075    SUMA_SAVE_LIST_EL *sel=NULL;
4076    int cnt = 0;
4077 
4078    SUMA_ENTRY;
4079 
4080    // fprintf(stderr, "%s\n", FuncName);
4081 
4082    if (!out) out = stderr;
4083    if (head) { fprintf(out, "%s", head); }
4084    if (!SL) { fprintf(out,"NULL SaveList\n"); SUMA_RETURNe; }
4085 
4086    el = dlist_head(SL);
4087    cnt = 0;
4088    while (el) {
4089       if ((sel = (SUMA_SAVE_LIST_EL *)el->data)) {
4090          fprintf(out,"   %d:     id>%s<, prefix>%s<, type>%s<\n",
4091                         cnt, sel->identifier, sel->prefix, sel->type);
4092       } else {
4093          fprintf(out,"   %d:     NULL sel\n", cnt);
4094       }
4095       el = dlist_next(el);
4096       fprintf(out,"\n");
4097    }
4098 
4099    SUMA_RETURNe;
4100 }
4101 
SUMA_SaveSaveListElement(SUMA_SAVE_LIST_EL * sel)4102 int SUMA_SaveSaveListElement(SUMA_SAVE_LIST_EL *sel)
4103 {
4104    static char FuncName[]={"SUMA_SaveSaveListElement"};
4105    SUMA_DSET *dset=NULL;
4106    char *oname=NULL, *idtype=NULL;
4107    int nid=0;
4108    SUMA_ENTRY;
4109 
4110    // fprintf(stderr, "%s\n", FuncName);
4111 
4112    if (!sel || !sel->identifier || !sel->prefix || !sel->type) SUMA_RETURN(0);
4113 
4114    if (!strcmp(sel->type,"sdset")) {
4115       idtype="label:"; nid = strlen(idtype);
4116       if (!strncmp(idtype, sel->identifier, nid)) {
4117          if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
4118                                  SUMAg_CF->DsetList, "label"))) {
4119             SUMA_S_Errv("Failed to find dset labeled %s\n", sel->identifier+nid);
4120             SUMA_RETURN(0);
4121          }
4122          goto SAVEDSET;
4123       }
4124       idtype="filename:"; nid = strlen(idtype);
4125       if (!strncmp(idtype, sel->identifier, nid)) {
4126          if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
4127                                  SUMAg_CF->DsetList, "filename"))) {
4128             SUMA_S_Errv("Failed to find dset with filename %s\n",
4129                         sel->identifier+nid);
4130             SUMA_RETURN(0);
4131          }
4132          goto SAVEDSET;
4133       }
4134       idtype="self_idcode:"; nid = strlen(idtype);
4135       if (!strncmp(idtype, sel->identifier, nid)) {
4136          if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
4137                                  SUMAg_CF->DsetList, "self_idcode"))) {
4138             SUMA_S_Errv("Failed to find dset with idcode %s\n",
4139                         sel->identifier+nid);
4140             SUMA_RETURN(0);
4141          }
4142          goto SAVEDSET;
4143       }
4144       /* last hurrah */
4145       if (!(dset = SUMA_FindDset2_s(sel->identifier,
4146                                  SUMAg_CF->DsetList, NULL))) {
4147          SUMA_S_Errv("Failed to find dset with identifier %s\n",
4148                      sel->identifier);
4149          SUMA_RETURN(0);
4150       }
4151       goto SAVEDSET;
4152 
4153       SAVEDSET:
4154       if (!dset) SUMA_RETURN(0);
4155       oname = SUMA_WriteDset_PreserveID(sel->prefix, dset,
4156                                         SUMA_NO_DSET_FORMAT, 1,0);
4157       SUMA_S_Notev("Wrote: %s\n", oname);
4158       if (oname) SUMA_free(oname);
4159    } else {
4160       SUMA_S_Errv("Not setup for type %s yet\n", sel->type);
4161       SUMA_RETURN(0);
4162    }
4163    SUMA_RETURN(1);
4164 }
4165 
SUMA_W_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)4166 int SUMA_W_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
4167 {
4168    static char FuncName[]={"SUMA_W_Key"};
4169    char tk[]={"W"}, keyname[100];
4170    int k, nc;
4171    SUMA_EngineData *ED = NULL;
4172    SUMA_SurfaceObject *SO;
4173    DList *list = NULL;
4174    DListElmt *el= NULL;
4175    char *lbls=NULL;
4176    SUMA_SAVE_LIST_EL *sel=NULL;
4177    SUMA_Boolean LocalHead = NOPE;
4178 
4179    SUMA_ENTRY;
4180 
4181    // fprintf(stderr, "%s\n", FuncName);
4182 
4183    SUMA_KEY_COMMON;
4184 
4185    /* do the work */
4186    switch (k) {
4187       case XK_W:
4188          if ((SUMA_CTRL_KEY(key))){
4189             if (!SUMAg_CF->SaveList || !dlist_size(SUMAg_CF->SaveList)) {
4190                SUMA_S_Note("Nothing in SaveList");
4191                SUMA_RETURN(1);
4192             }
4193             while((el = dlist_head(SUMAg_CF->SaveList))) {
4194                sel = (SUMA_SAVE_LIST_EL *)el->data;
4195                if (sel->identifier) {
4196                   if (!(SUMA_SaveSaveListElement(sel))) {
4197                      SUMA_S_Warnv("Failed to save %s %s\n",
4198                                   sel->identifier, sel->prefix)
4199                   }
4200                }
4201                dlist_remove(SUMAg_CF->SaveList, el, (void *)(&sel));
4202             }
4203          } else {
4204             if ((SO=SUMA_SV_Focus_SO(sv))) {
4205                if (!list) list = SUMA_CreateList();
4206                ED = SUMA_InitializeEngineListData (SE_SaveSOFileSelection);
4207                if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
4208                                                 SEF_vp, (void *)SO,
4209                                                 SES_Suma, (void *)sv, NOPE,
4210                                                 SEI_Head, NULL))) {
4211                   fprintf (SUMA_STDERR,
4212                            "Error %s: Failed to register command.\n",
4213                            FuncName);
4214                }
4215 
4216                if (!SUMA_RegisterEngineListCommand (  list, ED,
4217                                           SEF_ip, sv->X->TOPLEVEL,
4218                                           SES_Suma, (void *)sv, NOPE,
4219                                           SEI_In, el)) {
4220                   fprintf (SUMA_STDERR,
4221                            "Error %s: Failed to register command.\n",
4222                            FuncName);
4223                }
4224 
4225                if (!SUMA_Engine (&list)) {
4226                   fprintf( SUMA_STDERR,
4227                            "Error %s: SUMA_Engine call failed.\n", FuncName);
4228                }
4229             }
4230          }
4231          break;
4232 
4233       case XK_w:
4234             if (clippingPlaneMode){
4235                 // Save clipping planes to file
4236                char stmp[PATH_MAX+512];
4237                char cwd[PATH_MAX], outputFileName[PATH_MAX+400];
4238                time_t t = time(NULL);
4239                struct tm tm = *localtime(&t);
4240                if (!(getcwd(cwd, sizeof(cwd)))) {
4241                    perror("Error getting current working directory");
4242                    SUMA_RETURN(0);
4243                 }
4244                 sprintf(outputFileName, "%s/clippingPlane%d%d%d-%d%d.niml.vvs",
4245                     cwd, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
4246                     tm.tm_hour, tm.tm_min);
4247                 sprintf(stmp, "%s", outputFileName);
4248                 sv->X->SetRenderOrder_prmpt = NULL;
4249                 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialogStruct(
4250                                      SUMA_OK_APPLY_CLEAR_CANCEL,
4251                                 "Please select output filename:\n"
4252                                 "(default is shown)):",
4253                                      stmp,
4254                                      sv->X->TOPLEVEL, YUP,
4255                                      SUMA_APPLY_BUTTON,
4256                                      writeClippingPlanes, (void *)sv,
4257                                      NULL, NULL,
4258                                      NULL, NULL,
4259                                      SUMA_VerifyRenderOrder, (void *)outputFileName,
4260                                      sv->X->SetRenderOrder_prmpt);
4261 
4262                 sv->X->SetRenderOrder_prmpt->VerifyFunction = NULL;
4263                 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialog(
4264                                   sv->X->Title, sv->X->SetRenderOrder_prmpt);
4265 
4266                 sv->X->SetRenderOrder_prmpt = NULL;
4267             }
4268          break;
4269       default:
4270          SUMA_S_Err("Il ne faut pas ci dessous");
4271          SUMA_RETURN(0);
4272          break;
4273    }
4274 
4275    SUMA_RETURN(1);
4276 }
4277 
4278 /*!
4279    Execute commands when Z or z is pressed
4280 */
SUMA_Z_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)4281 int SUMA_Z_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
4282 {
4283    static char FuncName[]={"SUMA_Z_Key"};
4284    char tk[]={"Z"}, keyname[100], msg[100];
4285    int k, nc, ii, jj, mm;
4286    SUMA_Boolean LocalHead = NOPE;
4287 
4288    SUMA_ENTRY;
4289 
4290    // fprintf(stderr, "%s\n", FuncName);
4291 
4292    SUMA_KEY_COMMON;
4293 
4294    /* do the work */
4295    switch (k) {
4296       case XK_Z:
4297          sv->FOV[sv->iState] /= (1+sv->KeyZoomGain);
4298          if (sv->FOV[sv->iState] < FOV_MIN) {
4299             SUMA_BEEP; sv->FOV[sv->iState] = FOV_MIN;
4300          }
4301 
4302          /* Now update the zoom compensation variable */
4303          if (sv->ZoomCompensate) {
4304             sv->ZoomCompensate = sv->FOV[sv->iState] / SUMA_sv_auto_fov(sv);
4305             if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0;
4306                /* weird stuff at zc_fac higher that 1.5 */
4307             else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;
4308          }
4309          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4310          break;
4311 
4312       case XK_z:
4313          sv->FOV[sv->iState] /= (1-sv->KeyZoomGain);
4314          if (sv->ortho) {
4315             if (sv->FOV[sv->iState] > FOV_MAX/2.0) {
4316                SUMA_BEEP; sv->FOV[sv->iState] = FOV_MAX/2.0; }
4317          } else {
4318             if (sv->FOV[sv->iState] > FOV_MAX) {
4319                SUMA_BEEP; sv->FOV[sv->iState] = FOV_MAX; }
4320          }
4321          /*fprintf(stderr,"Zoom out %f\n", sv->FOV[sv->iState]);*/
4322          /* Now update the zoom compensation variable */
4323          if (sv->ZoomCompensate) {
4324             sv->ZoomCompensate = sv->FOV[sv->iState] / SUMA_sv_auto_fov(sv);
4325             if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0;
4326                /* weird stuff at zc_fac higher that 1.5 */
4327             else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;
4328                /* weird stuff cause by integer spin variables!
4329                   Proper way to handle all this is with float position
4330                   storage and no recalculation of zc_fac except at zooming.*/
4331          }
4332          SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4333          break;
4334 
4335       default:
4336          SUMA_S_Err("Il ne faut pas etre la");
4337          SUMA_RETURN(0);
4338          break;
4339    }
4340    SUMA_RETURN(1);
4341 }
4342 
SUMA_Up_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4343 int SUMA_Up_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4344 {
4345    static char FuncName[]={"SUMA_Up_Key"};
4346    char tk[]={"Up"}, keyname[100], skey[65], skeyi[65];
4347    int k, nc, ii, inode = -1;
4348    float ArrowDeltaRot = 0.05;
4349       /* The larger the value, the bigger the rotation increment */
4350    Widget w = NULL;
4351    double dd[3] = {0.0, -1.0, 0.0}; /* up */
4352    SUMA_SurfaceObject *SO=NULL;
4353    SUMA_Boolean LocalHead = NOPE;
4354 
4355    SUMA_ENTRY;
4356 
4357    // fprintf(stderr, "%s\n", FuncName);
4358 
4359    SUMA_KEY_COMMON;
4360 
4361    SUMA_KEY_SWITCH;
4362 
4363    w = sv->X->GLXAREA;
4364    /* do the work */
4365    switch (k) {
4366       // PDL: Rotate clipping plane if available and ctrl key down
4367       case XK_Up:
4368             if (clippingPlaneMode && SUMA_ALT_KEY(key) && SUMAg_CF->N_ClipPlanes > 0){
4369                 clipPlaneTransform(tiltInc, 0, 0, 0, -1, 0, 0);
4370             } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4371                float a[3];
4372                /* Posterior view ctrl+shift+up*/
4373                /* From top view, rotate by 90 degrees about x axis */
4374                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4375                axis_to_quat(a, SUMA_PI/2, sv->GVS[sv->StdView].currentQuat);
4376                SUMA_postRedisplay(w, NULL, NULL);
4377             }else if (SUMA_SHIFT_KEY(key)) {
4378                /*fprintf (SUMA_STDERR,"%s: Shift up\n", FuncName);*/
4379                sv->GVS[sv->StdView].translateVec[1] +=
4380                 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY /
4381                 (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
4382                SUMA_postRedisplay(w, NULL, NULL);
4383             }else if (SUMA_CTRL_KEY(key)){
4384                /*fprintf (SUMA_STDERR,"%s: Control Up\n", FuncName);*/
4385                /* Top view ctrl+up*/
4386                float a[3];
4387                /* Default top view, rotate by nothing */
4388                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4389                axis_to_quat(a, 0, sv->GVS[sv->StdView].currentQuat);
4390                SUMA_postRedisplay(w, NULL, NULL);
4391             }else if (SUMA_AALT_KEY(key)) {
4392                SUMA_LH("alt down");
4393                if ((SO = SUMA_SV_Focus_SO(sv))) {
4394                   if (SO->SelectedNode < 0 ||
4395                       !SO->FN) SUMA_RETURN(1); /* nothing to do */
4396                   inode = SO->SelectedNode;
4397                   {
4398                      inode =
4399                         SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4400                      if (inode == -2) {
4401                         SUMA_S_Err("Failed in"
4402                                    " SUMA_NodeNeighborAlongScreenDirection");
4403                         SUMA_RETURN(0);
4404                      } else if (inode == -1) {
4405                         SUMA_LH("No good direction, get out");
4406                         SUMA_BEEP;
4407                         break;
4408                      } else {
4409                         SUMA_LHv("Next node should be %d\n", inode);
4410                      }
4411                   }
4412                   /* Now set the new selected node */
4413                   if (inode >= 0 && inode != SO->SelectedNode) {
4414                      char stmp[64]; /* use Jump callback,
4415                                        the easy route */
4416                      sprintf(stmp,"%d", inode);
4417                      SUMA_JumpIndex (stmp, (void *)sv);
4418                   }
4419                }
4420             } else {
4421                if (LocalHead)
4422                   fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);
4423                trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4424                   0.0, -ArrowDeltaRot, /* first point */
4425                   0.0, ArrowDeltaRot, /* ending x,y */
4426                   sv->ArrowRotationAngle);
4427                if (LocalHead) {
4428                   fprintf(stdout,"\ncurrentQuat\n");
4429                   for (ii=0; ii<4; ++ii) {
4430                      fprintf( stdout,"%f\t",
4431                               sv->GVS[sv->StdView].currentQuat[ii]);
4432                   }
4433                   fprintf(stdout,"\n");
4434                   fprintf(stdout,"\ndeltaQuat\n");
4435                   for (ii=0; ii<4; ++ii) {
4436                      fprintf(stdout,"%f\t", sv->GVS[sv->StdView].deltaQuat[ii]);
4437                   }
4438                   fprintf(stdout,"\n");
4439                }
4440                add_quats ( sv->GVS[sv->StdView].deltaQuat,
4441                            sv->GVS[sv->StdView].currentQuat,
4442                            sv->GVS[sv->StdView].currentQuat);
4443                if (LocalHead) {
4444                   fprintf(stdout,"\nnewQuat\n");
4445                   for (ii=0; ii<4; ++ii) {
4446                      fprintf( stdout,"%f\t",
4447                               sv->GVS[sv->StdView].currentQuat[ii]);
4448                   }
4449                   fprintf(stdout,"\n");
4450                }
4451                sv->GVS[sv->StdView].spinDeltaX = 0;
4452                sv->GVS[sv->StdView].spinDeltaY =
4453                                     2.0*ArrowDeltaRot*sv->X->aHEIGHT;
4454                SUMA_postRedisplay(w, NULL, NULL);
4455             }
4456 
4457             break;
4458 
4459          break;
4460       default:
4461          SUMA_S_Err("Il ne faut pas etre ici");
4462          SUMA_RETURN(0);
4463          break;
4464    }
4465 
4466    SUMA_RETURN(1);
4467 }
SUMA_Down_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4468 int SUMA_Down_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4469 {
4470    static char FuncName[]={"SUMA_Down_Key"};
4471    char tk[]={"Down"}, keyname[100], skey[65], skeyi[65];
4472    int k, nc, ii, inode=-1;
4473    float ArrowDeltaRot = 0.05;
4474          /* The larger the value, the bigger the rotation increment */
4475    Widget w = NULL;
4476    double dd[3] = {0.0, 1.0, 0.0}; /* down */
4477    SUMA_SurfaceObject *SO=NULL;
4478    SUMA_Boolean LocalHead = NOPE;
4479 
4480    SUMA_ENTRY;
4481 
4482    // fprintf(stderr, "%s\n", FuncName);
4483 
4484    SUMA_KEY_COMMON;
4485 
4486    SUMA_KEY_SWITCH;
4487 
4488    w = sv->X->GLXAREA;
4489    /* do the work */
4490    switch (k) {
4491       case XK_Down:
4492             // PDL: Rotate clipping plane if available and ctrl key down
4493       case XK_Up:
4494             if (clippingPlaneMode && SUMA_ALT_KEY(key) && SUMAg_CF->N_ClipPlanes > 0){
4495                 clipPlaneTransform(-tiltInc, 0, 0, 0, -1, 0, 0);
4496             } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4497                float a[3], cQ[4], dQ[4];
4498                /* Posterior view ctrl+shift+down*/
4499                /* From top view, first rotate by 90 degrees about x axis */
4500                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4501                axis_to_quat(a, SUMA_PI/2, cQ);
4502                /* then rotate by 180 degrees about y axis */
4503                a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
4504                axis_to_quat(a, SUMA_PI, dQ);
4505                /*add rotation */
4506                add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
4507                SUMA_postRedisplay(w, NULL, NULL);
4508             }else if (SUMA_SHIFT_KEY(key)) {
4509                /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
4510                /*sv->GVS[sv->StdView].translateVec[0] += 0;*/
4511                sv->GVS[sv->StdView].translateVec[1] -=
4512                   (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY /
4513                   (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
4514                SUMA_postRedisplay(w, NULL, NULL);
4515             }else if (SUMA_CTRL_KEY(key)){
4516                /*fprintf (SUMA_STDERR,"%s: Control down\n", FuncName);*/
4517                /* Inferior view ctrl+down*/
4518                float a[3];
4519                /* From top view, rotate by 180 degrees about y axis */
4520                a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
4521                axis_to_quat(a, SUMA_PI, sv->GVS[sv->StdView].currentQuat);
4522                SUMA_postRedisplay(w, NULL, NULL);
4523             }else if (SUMA_AALT_KEY(key)) {
4524                SUMA_LH("alt down");
4525                if ((SO = SUMA_SV_Focus_SO(sv))) {
4526                   if (SO->SelectedNode < 0 ||
4527                       !SO->FN) SUMA_RETURN(1); /* nothing to do */
4528                   inode = SO->SelectedNode;
4529                   {
4530                      inode =
4531                         SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4532                      if (inode == -2) {
4533                         SUMA_S_Err("Failed in"
4534                                    " SUMA_NodeNeighborAlongScreenDirection");
4535                         SUMA_RETURN(0);
4536                      } else if (inode == -1) {
4537                         SUMA_LH("No good direction, get out");
4538                         SUMA_BEEP;
4539                         break;
4540                      } else {
4541                         SUMA_LHv("Next node should be %d\n", inode);
4542                      }
4543                   }
4544                   /* Now set the new selected node */
4545                   if (inode >= 0 && inode != SO->SelectedNode) {
4546                      char stmp[64]; /* use Jump callback,
4547                                        the easy route */
4548                      sprintf(stmp,"%d", inode);
4549                      SUMA_JumpIndex (stmp, (void *)sv);
4550                   }
4551                }
4552             }else {
4553                /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
4554                trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4555                   0.0, ArrowDeltaRot, /* first point */
4556                   0.0, -ArrowDeltaRot, /* ending x,y */
4557                   sv->ArrowRotationAngle);
4558                /*fprintf(stdout,"\ncurrentQuat\n");
4559                  for (i=0; i<4; ++i) {
4560                   fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[i]);}
4561                  fprintf(stdout,"\n");
4562                  fprintf(stdout,"\ndeltaQuat\n");for (i=0; i<4; ++i) {
4563                   fprintf(stdout,"%f\t", sv->GVS[sv->StdView].deltaQuat[i]);}
4564                  fprintf(stdout,"\n"); */
4565                add_quats (sv->GVS[sv->StdView].deltaQuat,
4566                           sv->GVS[sv->StdView].currentQuat,
4567                           sv->GVS[sv->StdView].currentQuat);
4568                /*fprintf(stdout,"\nnewQuat\n");
4569                  for (i=0; i<4; ++i) {
4570                   fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[i]);}
4571                  fprintf(stdout,"\n");*/
4572                sv->GVS[sv->StdView].spinDeltaX = 0;
4573                sv->GVS[sv->StdView].spinDeltaY =
4574                            -2.0*ArrowDeltaRot*sv->X->aHEIGHT;
4575                SUMA_postRedisplay(w, NULL, NULL);
4576             }
4577 
4578             break;
4579 
4580          break;
4581       default:
4582          SUMA_S_Err("Il ne faut pas etre ici");
4583          SUMA_RETURN(0);
4584          break;
4585    }
4586 
4587 
4588    SUMA_RETURN(1);
4589 }
SUMA_Left_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4590 int SUMA_Left_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4591 {
4592    static char FuncName[]={"SUMA_Left_Key"};
4593    char tk[]={"Left"}, keyname[100], skey[65], skeyi[65];
4594    int k, nc, ii, jj, inode = -1, bkey = 0;
4595    float ArrowDeltaRot = 0.05;
4596       /* The larger the value, the bigger the rotation increment */
4597    Widget w = NULL;
4598    double dd[3] = {-1.0, 0.0, 0.0}; /* left */
4599    SUMA_SurfaceObject *SO=NULL;
4600    SUMA_Boolean LocalHead = NOPE;
4601 
4602    SUMA_ENTRY;
4603 
4604    // fprintf(stderr, "%s\n", FuncName);
4605 
4606    SUMA_KEY_COMMON;
4607 
4608    SUMA_KEY_SWITCH;
4609 
4610    w = sv->X->GLXAREA;
4611    /* do the work */
4612    switch (k) {
4613       case XK_Left:
4614             // PDL: Rotate clipping plane if available and ctrl key down
4615             if (clippingPlaneMode && SUMA_ALT_KEY(key)){
4616                 clipPlaneTransform(0, -tiltInc, 0, 0, -1, 0, 0);
4617             } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4618                float a[3], cQ[4];
4619                /* rotate about Z axis CCW  */
4620                a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
4621                axis_to_quat(a, -sv->ArrowRotationAngle, cQ);
4622                /*add rotation */
4623                add_quats ( cQ,
4624                            sv->GVS[sv->StdView].currentQuat,
4625                            sv->GVS[sv->StdView].currentQuat);
4626                sv->GVS[sv->StdView].spinDeltaX = 0;
4627                sv->GVS[sv->StdView].spinDeltaY = 0;
4628                SUMA_postRedisplay(w, NULL, NULL);
4629             }else if (SUMA_SHIFT_KEY(key)) {
4630                /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
4631                sv->GVS[sv->StdView].translateVec[0] -=
4632                   (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX       /
4633                   (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
4634                /*sv->GVS[sv->StdView].translateVec[1] -= 0;*/
4635                SUMA_postRedisplay(w, NULL, NULL);
4636             }else if (SUMA_CTRL_KEY(key)){
4637                float a[3], cQ[4], dQ[4];
4638                /* From top view, rotate about x 90 degrees.*/
4639                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4640                axis_to_quat(a, SUMA_PI/2.0, cQ);
4641                /* then rotate about y 90 degrees */
4642                a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
4643                axis_to_quat(a, SUMA_PI/2.0, dQ);
4644                /*add and apply rotation*/
4645                add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
4646                SUMA_postRedisplay(w, NULL, NULL);
4647             }else if (SUMA_AALT_KEY(key)) {
4648                SUMA_LH("alt down");
4649                if ((SO = SUMA_SV_Focus_SO(sv))) {
4650                   if (SO->SelectedNode < 0 ||
4651                       !SO->FN) SUMA_RETURN(1); /* nothing to do */
4652                   inode = SO->SelectedNode;
4653                   {
4654                      inode =
4655                         SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4656                      if (inode == -2) {
4657                         SUMA_S_Err("Failed in"
4658                                    " SUMA_NodeNeighborAlongScreenDirection");
4659                         SUMA_RETURN(0);
4660                      } else if (inode == -1) {
4661                         SUMA_LH("No good direction, get out");
4662                         SUMA_BEEP;
4663                         break;
4664                      } else {
4665                         SUMA_LHv("Next node should be %d\n", inode);
4666                      }
4667                   }
4668                   /* Now set the new selected node */
4669                   if (inode >= 0 && inode != SO->SelectedNode) {
4670                      char stmp[64]; /* use Jump callback,
4671                                        the easy route */
4672                      sprintf(stmp,"%d", inode);
4673                      SUMA_JumpIndex (stmp, (void *)sv);
4674                   }
4675                }
4676             }else {
4677                /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
4678                trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4679                   ArrowDeltaRot, 0.0, /* first point */
4680                   -ArrowDeltaRot, 0.0, /* ending x,y */
4681                   sv->ArrowRotationAngle);
4682                add_quats ( sv->GVS[sv->StdView].deltaQuat,
4683                            sv->GVS[sv->StdView].currentQuat,
4684                            sv->GVS[sv->StdView].currentQuat);
4685                sv->GVS[sv->StdView].spinDeltaX =
4686                               -2.0*ArrowDeltaRot*sv->X->aWIDTH;
4687                sv->GVS[sv->StdView].spinDeltaY = 0;
4688                SUMA_postRedisplay(w, NULL, NULL);
4689             }
4690 
4691             break;
4692 
4693          break;
4694       default:
4695          SUMA_S_Err("Il ne faut pas etre ici");
4696          SUMA_RETURN(0);
4697          break;
4698    }
4699 
4700 
4701    SUMA_RETURN(1);
4702 }
SUMA_Right_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4703 int SUMA_Right_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4704 {
4705    static char FuncName[]={"SUMA_Right_Key"};
4706    char tk[]={"Right"}, keyname[100], skey[65], skeyi[65];
4707    int k, nc, ii, inode=-1;
4708    float ArrowDeltaRot = 0.05;
4709          /* The larger the value, the bigger the rotation increment */
4710    Widget w = NULL;
4711    double dd[3] = {1.0, 0.0, 0.0}; /* right */
4712    SUMA_SurfaceObject *SO=NULL;
4713    SUMA_Boolean LocalHead = NOPE;
4714 
4715    SUMA_ENTRY;
4716 
4717    // fprintf(stderr, "%s\n", FuncName);
4718 
4719    SUMA_KEY_COMMON;
4720 
4721    SUMA_KEY_SWITCH;
4722 
4723    w = sv->X->GLXAREA;
4724    /* do the work */
4725    switch (k) {
4726       case XK_Right:
4727             // PDL: Rotate clipping plane if available and ctrl key down
4728             if (clippingPlaneMode && SUMA_ALT_KEY(key) && SUMAg_CF->N_ClipPlanes > 0){
4729                 clipPlaneTransform(0, tiltInc, 0, 0, -1, 0, 0);
4730             } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4731                float a[3], cQ[4];
4732                /* rotate about Z axis CCW  */
4733                a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
4734                axis_to_quat(a, sv->ArrowRotationAngle, cQ);
4735                /*add rotation */
4736                add_quats ( cQ,
4737                            sv->GVS[sv->StdView].currentQuat,
4738                            sv->GVS[sv->StdView].currentQuat);
4739                sv->GVS[sv->StdView].spinDeltaX = 0;
4740                sv->GVS[sv->StdView].spinDeltaY = 0;
4741                SUMA_postRedisplay(w, NULL, NULL);
4742             }else if (SUMA_SHIFT_KEY(key)) {
4743                /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
4744                sv->GVS[sv->StdView].translateVec[0] +=
4745                   (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX /
4746                   (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
4747                /*sv->GVS[sv->StdView].translateVec[1] -= 0;*/
4748                SUMA_postRedisplay(w,  NULL, NULL);
4749             }else if (SUMA_CTRL_KEY(key)){
4750                float a[3], cQ[4], dQ[4];
4751                /* From top view, rotate about x 90 degrees */
4752                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4753                axis_to_quat(a, SUMA_PI/2.0, cQ);
4754                /* then rotate about y -90 degrees */
4755                a[0] = 0.0; a[1] = 1.0;
4756                axis_to_quat(a, -SUMA_PI/2.0, dQ);
4757                /*add and apply rotation*/
4758                add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
4759                SUMA_postRedisplay(w, NULL, NULL);
4760             }else if (SUMA_AALT_KEY(key)) {
4761                SUMA_LH("alt down");
4762                if ((SO = SUMA_SV_Focus_SO(sv))) {
4763                   if (SO->SelectedNode < 0 ||
4764                       !SO->FN) SUMA_RETURN(1); /* nothing to do */
4765                   inode = SO->SelectedNode;
4766                   {
4767                      inode =
4768                         SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4769                      if (inode == -2) {
4770                         SUMA_S_Err("Failed in"
4771                                    " SUMA_NodeNeighborAlongScreenDirection");
4772                         SUMA_RETURN(0);
4773                      } else if (inode == -1) {
4774                         SUMA_LH("No good direction, get out");
4775                         SUMA_BEEP;
4776                         break;
4777                      } else {
4778                         SUMA_LHv("Next node should be %d\n", inode);
4779                      }
4780                   }
4781                   /* Now set the new selected node */
4782                   if (inode >= 0 && inode != SO->SelectedNode) {
4783                      char stmp[64]; /* use Jump callback,
4784                                        the easy route */
4785                      sprintf(stmp,"%d", inode);
4786                      SUMA_JumpIndex (stmp, (void *)sv);
4787                   }
4788                }
4789             }else {
4790                /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
4791                trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4792                   -ArrowDeltaRot, 0.0, /* first point */
4793                   ArrowDeltaRot, 0.0, /* ending x,y */
4794                   sv->ArrowRotationAngle);
4795                add_quats (sv->GVS[sv->StdView].deltaQuat,
4796                           sv->GVS[sv->StdView].currentQuat,
4797                           sv->GVS[sv->StdView].currentQuat);
4798                sv->GVS[sv->StdView].spinDeltaX = 2.0*ArrowDeltaRot*sv->X->aWIDTH;
4799                sv->GVS[sv->StdView].spinDeltaY = 0;
4800                SUMA_postRedisplay(w,  NULL, NULL);
4801             }
4802 
4803             break;
4804 
4805          break;
4806       default:
4807          SUMA_S_Err("Il ne faut pas etre ici");
4808          SUMA_RETURN(0);
4809          break;
4810    }
4811 
4812 
4813    SUMA_RETURN(1);
4814 }
4815 
SUMA_Butts2String(SUMA_EVENT * ev)4816 char *SUMA_Butts2String(SUMA_EVENT *ev)
4817 {
4818    static char ccs[10][32];
4819    static int icall=0;
4820    char *cc;
4821    int nb=0, mot;
4822 
4823    ++icall; if (icall>9) icall=0;
4824    cc = (char *)ccs[icall]; cc[0]='\0';
4825 
4826    if (ev->b1) {cc[nb++]='1'; cc[nb++]='&'; mot = 0;}
4827    if (ev->b2) {cc[nb++]='2'; cc[nb++]='&'; mot = 0;}
4828    if (ev->b3) {cc[nb++]='3'; cc[nb++]='&'; mot = 0;}
4829    if (ev->b4) {cc[nb++]='4'; cc[nb++]='&'; mot = 0;}
4830    if (ev->b5) {cc[nb++]='5'; cc[nb++]='&'; mot = 0;}
4831    if (ev->b6) {cc[nb++]='6'; cc[nb++]='&'; mot = 0;}
4832    if (ev->b7) {cc[nb++]='6'; cc[nb++]='&'; mot = 0;}
4833    if (ev->b1m) {cc[nb++]='1'; cc[nb++]='&'; mot = 1;}
4834    if (ev->b2m) {cc[nb++]='2'; cc[nb++]='&'; mot = 1;}
4835    if (ev->b3m) {cc[nb++]='3'; cc[nb++]='&'; mot = 1;}
4836    if (ev->b4m) {cc[nb++]='4'; cc[nb++]='&'; mot = 1;}
4837    if (ev->b5m) {cc[nb++]='5'; cc[nb++]='&'; mot = 1;}
4838 
4839    if (nb>1) nb = nb-1; /* Get rid of last & */
4840    cc[nb] = '\0';
4841    return(cc);
4842 }
4843 
SUMA_KeyType2String(int kt)4844 char *SUMA_KeyType2String(int kt)
4845 {
4846    switch(kt) {
4847       case KeyPress:
4848          return("key");
4849       case ButtonRelease:
4850          return("release");
4851       case ButtonPress:
4852          return("press");
4853       case MotionNotify:
4854          return("motion");
4855       default:
4856          return("UNKNOWN");
4857    }
4858 }
4859 
SUMA_ShowEvent(SUMA_EVENT * ev,int opt,char * pre)4860 void SUMA_ShowEvent(SUMA_EVENT *ev, int opt, char *pre)
4861 {
4862    static char FuncName[]={"SUMA_ShowEvent"};
4863    static int icall=0;
4864    char *s = NULL;
4865    SUMA_STRING *SS = NULL;
4866    FILE *out = stderr;
4867 
4868    SUMA_ENTRY;
4869 
4870    // fprintf(stderr, "%s\n", FuncName);
4871 
4872    SS = SUMA_StringAppend(NULL, NULL);
4873 
4874    if (pre) SUMA_StringAppend(SS,pre);
4875    if (!ev) {
4876       SUMA_StringAppend(SS,"NULL ev\n"); goto OUT;
4877    }
4878    ++icall;
4879    if (!opt) {
4880       SUMA_StringAppend_va(SS,"Event Struct (set %d, callid %d)\n"
4881                         "   ktype %d kstate %d transl %s\n"
4882                         "   keysym %d mtype %d mstate %d\n"
4883                         "   bButton %d mButton %d\n"
4884                         "   bTime %ld  mTime %ld\n"
4885                         "   mX %d mY %d bX %d bY %d\n"
4886                         "   mDelta %d, mDeltaX %d, mDeltaY %d\n"
4887                "   shift %d control %d mod1 %d mod2 %d mod3 %d mod4 %d mod5 %d\n"
4888                         "   ApplAltOpt %d DoubleClick %d\n"
4889                         "   b1 %d b2 %d b3 %d b4 %d b5 %d b6 %d b7 %d\n"
4890                         "   b1m %d b2m %d b3m %d b4m %d b5m %d\n",
4891                         ev->set, icall,
4892                         ev->ktype, ev->kstate, ev->transl,
4893                         ev->keysym, ev->mtype, ev->mstate,
4894                         ev->bButton, ev->mButton,
4895                         ev->bTime, ev->mTime,
4896                         ev->mX, ev->mY, ev->bX, ev->bY,
4897                         ev->mDelta, ev->mDeltaX, ev->mDeltaY,
4898       ev->Shift, ev->Control, ev->Mod1, ev->Mod2, ev->Mod3, ev->Mod4, ev->Mod5,
4899                         ev->AppleAltOpt, ev->DoubleClick,
4900                         ev->b1, ev->b2, ev->b3, ev->b4, ev->b5, ev->b6, ev->b7,
4901                         ev->b1m, ev->b2m, ev->b3m, ev->b4m, ev->b5m);
4902    } else {
4903       /* More readable mode */
4904       SUMA_StringAppend_va(SS,"Input Event %d: %s   \n",
4905             icall, ev->set ? "":"WARNING Event Struct Not Set!" );
4906       if (ev->ktype == KeyPress) {
4907          SUMA_StringAppend_va(SS,"%s: char>>%s<< sym>>%d<< ",
4908                            SUMA_KeyType2String(ev->ktype),
4909                            ev->transl, (int)ev->keysym);
4910       } else {
4911          SUMA_StringAppend_va(SS,"Mouse %s %s%s: ",
4912             SUMA_Butts2String(ev),
4913             SUMA_KeyType2String(ev->ktype),
4914             ev->DoubleClick ? " double click":"");
4915          if (ev->b1) SUMA_StringAppend_va(SS,"b1 ",ev->b1);
4916          if (ev->b2) SUMA_StringAppend_va(SS,"b2 ",ev->b2);
4917          if (ev->b3) SUMA_StringAppend_va(SS,"b3 ",ev->b3);
4918          if (ev->b4) SUMA_StringAppend_va(SS,"b4 ",ev->b4);
4919          if (ev->b5) SUMA_StringAppend_va(SS,"b5 ",ev->b5);
4920          if (ev->b6) SUMA_StringAppend_va(SS,"b6 ",ev->b6);
4921          if (ev->b7) SUMA_StringAppend_va(SS,"b7 ",ev->b7);
4922          if (ev->b1m) SUMA_StringAppend_va(SS,"m1 ",ev->b1m);
4923          if (ev->b2m) SUMA_StringAppend_va(SS,"m2 ",ev->b2m);
4924          if (ev->b3m) SUMA_StringAppend_va(SS,"m3 ",ev->b3m);
4925          if (ev->b4m) SUMA_StringAppend_va(SS,"m4 ",ev->b4m);
4926          if (ev->b5m) SUMA_StringAppend_va(SS,"m5 ",ev->b5m);
4927       }
4928       if (ev->Shift) {
4929          SUMA_StringAppend_va(SS,"Shift ");
4930       }
4931       if (ev->Control){
4932          SUMA_StringAppend_va(SS,"Control ");
4933       }
4934       if (ev->Mod1){
4935          SUMA_StringAppend_va(SS,"alt ");
4936       }
4937       if (ev->Mod2){
4938          SUMA_StringAppend_va(SS,"Mod2 (command on mac) ");
4939       }
4940       if (ev->Mod3){
4941          SUMA_StringAppend_va(SS,"Mod3 ");
4942       }
4943       if (ev->Mod4){
4944          SUMA_StringAppend_va(SS,"Mod4 ");
4945       }
4946       if (ev->Mod5){
4947          SUMA_StringAppend_va(SS,"Mod5 ");
4948       }
4949       if (ev->Mod2){
4950          SUMA_StringAppend_va(SS,"Mod2 ");
4951       }
4952       if (ev->AppleAltOpt){
4953         SUMA_StringAppend_va(SS,"Apple Alt/Opt ");
4954       }
4955       SUMA_StringAppend_va(SS,"k/mstate [%d/%d]\n\n", ev->kstate, ev->mstate);
4956    }
4957    OUT:
4958    SUMA_SS2S(SS,s);
4959 
4960    fprintf(out,"%s",s);
4961 
4962    SUMA_ifree(s);
4963 
4964    SUMA_RETURNe;
4965 }
4966 
4967 #ifdef DARWIN
4968 #define evALT ((ev->Mod1 || ev->Mod2 || ev->AppleAltOpt))
4969 #else
4970 #define evALT ((ev->Mod1))
4971 #endif
SUMA_ShftCont_Event(SUMA_EVENT * ev)4972 int SUMA_ShftCont_Event(SUMA_EVENT *ev)
4973 {
4974    if (!ev) ev = SUMAg_CF->lev;
4975    if (!ev || !ev->set) return(0);
4976    if (ev->Shift && ev->Control && !evALT) return(1);
4977    return(0);
4978 }
SUMA_Cont_Event(SUMA_EVENT * ev)4979 int SUMA_Cont_Event(SUMA_EVENT *ev)
4980 {
4981    if (!ev) ev = SUMAg_CF->lev;
4982    if (!ev || !ev->set) return(0);
4983    if (!ev->Shift && ev->Control && !evALT) return(1);
4984    return(0);
4985 }
SUMA_Shft_Event(SUMA_EVENT * ev)4986 int SUMA_Shft_Event(SUMA_EVENT *ev)
4987 {
4988    if (!ev) ev = SUMAg_CF->lev;
4989    if (!ev || !ev->set) return(0);
4990    if (ev->Shift && !ev->Control && !evALT) return(1);
4991    return(0);
4992 }
SUMA_ShftContAlt_Event(SUMA_EVENT * ev)4993 int SUMA_ShftContAlt_Event(SUMA_EVENT *ev)
4994 {
4995    if (!ev) ev = SUMAg_CF->lev;
4996    if (!ev || !ev->set) return(0);
4997    if (ev->Shift && ev->Control && evALT ) return(1);
4998    return(0);
4999 }
SUMA_ContAlt_Event(SUMA_EVENT * ev)5000 int SUMA_ContAlt_Event(SUMA_EVENT *ev)
5001 {
5002    if (!ev) ev = SUMAg_CF->lev;
5003    if (!ev || !ev->set) return(0);
5004    if (!ev->Shift && ev->Control && evALT ) return(1);
5005    return(0);
5006 }
SUMA_ShftAlt_Event(SUMA_EVENT * ev)5007 int SUMA_ShftAlt_Event(SUMA_EVENT *ev)
5008 {
5009    if (!ev) ev = SUMAg_CF->lev;
5010    if (!ev || !ev->set) return(0);
5011    if (ev->Shift && !ev->Control && evALT ) return(1);
5012    return(0);
5013 }
SUMA_Alt_Event(SUMA_EVENT * ev)5014 int SUMA_Alt_Event(SUMA_EVENT *ev)
5015 {
5016    if (!ev) ev = SUMAg_CF->lev;
5017    if (!ev || !ev->set) return(0);
5018    if (!ev->Shift && !ev->Control && evALT) return(1);
5019    return(0);
5020 }
SUMA_Plain_Event(SUMA_EVENT * ev)5021 int SUMA_Plain_Event(SUMA_EVENT *ev)
5022 {
5023    if (!ev) ev = SUMAg_CF->lev;
5024    if (!ev || !ev->set) return(0);
5025    if (!ev->Shift && !ev->Control && !evALT) return(1);
5026    return(0);
5027 }
5028 
5029 /*! Get a record of events.
5030     Contents based on logic used in SUMA_input()
5031     Ideally, all should be done here and SUMA_input()
5032     should use the results of this call. But we're not
5033     there yet....
5034     Once I start using this one call, then the logic
5035     can be revisited at varied points in there.
5036 */
SUMA_RecordEvent(XEvent * event,SUMA_EVENT * ev)5037 SUMA_EVENT *SUMA_RecordEvent( XEvent *event,
5038                               SUMA_EVENT *ev)
5039 {
5040    static char FuncName[]={"SUMA_RecordEvent"};
5041    XKeyEvent Kev;
5042    XButtonEvent Bev;
5043    XMotionEvent Mev;
5044    static SUMA_EVENT lev;
5045    SUMA_Boolean LocalHead = NOPE;
5046 
5047    SUMA_ENTRY;
5048 
5049    // fprintf(stderr, "%s\n", FuncName);
5050 
5051    if (!event) {
5052       SUMA_S_Err("Null event");
5053       if (ev) memset(ev, 0, sizeof(SUMA_EVENT));
5054       SUMA_RETURN(ev);
5055    }
5056 
5057    if (!ev) {
5058       if (!(ev = SUMAg_CF->lev)) {
5059          memset(&lev, 0, sizeof(SUMA_EVENT));
5060          SUMAg_CF->lev = (SUMA_EVENT *)SUMA_malloc(1*sizeof(SUMA_EVENT));
5061       }
5062       ev = SUMAg_CF->lev;
5063    }
5064    if (!ev) SUMA_RETURN(NULL);
5065    memset(ev, 0, sizeof(SUMA_EVENT));
5066 
5067    Kev = *(XKeyEvent *) &event->xkey; /* RickR's suggestion to comply with
5068                                  ANSI C, no type casting of structures  July 04*/
5069    Bev = *(XButtonEvent *) &event->xbutton;
5070    Mev = *(XMotionEvent *) &event->xmotion;
5071 
5072    ev->set = 1;
5073    /* The copied parameters */
5074    ev->ktype = Kev.type;
5075    ev->kstate = Kev.state;
5076    ev->mtype = Mev.type;
5077    ev->mstate = Mev.state;
5078    ev->bTime = Bev.time;
5079    ev->mTime = Mev.time;
5080    ev->bButton = Bev.button;
5081    ev->mButton = 0; /* Not sure this one was all that necessary */
5082    ev->mX = Mev.x;
5083    ev->mY = Mev.y;
5084    ev->bX = Bev.x;
5085    ev->bY = Bev.y;
5086 
5087    /* The inferred parameters */
5088    if ((Kev.state & ShiftMask) || (Bev.state & ShiftMask)) ev->Shift = 1;
5089    if ((Kev.state & ControlMask) || (Bev.state & ControlMask)) ev->Control = 1;
5090    if (Kev.state & Mod1Mask) ev->Mod1 = 1;
5091    if (Kev.state & Mod2Mask) ev->Mod2 = 1;
5092    if (Kev.state & Mod3Mask) ev->Mod3 = 1;
5093    if (Kev.state & Mod4Mask) ev->Mod4 = 1;
5094    if (Kev.state & Mod5Mask) ev->Mod5 = 1;
5095    if (Kev.state & SUMA_APPLE_AltOptMask) ev->AppleAltOpt = 1;
5096 
5097    switch(ev->ktype) {
5098       case KeyPress:
5099          ev->transl[0] = ev->transl[15] = '\0';
5100          XLookupString( (XKeyEvent *)event, ev->transl, 14,
5101                               &ev->keysym, NULL);
5102          break;
5103          break;
5104       case ButtonPress:
5105          if (Bev.state & Button1Mask) ev->b1 = 1;
5106          if (Bev.state & Button2Mask) ev->b2 = 1;
5107          if (Bev.state & Button3Mask) ev->b3 = 1;
5108          if (Bev.state & Button4Mask) ev->b4 = 1;
5109          if (Bev.state & Button5Mask) ev->b5 = 1;
5110          if (ev->bButton == 6) ev->b6 = 1; /* on macs Button6 not in X.h */
5111          if (ev->bButton == 7) ev->b7 = 1; /* on macs Button7 not in X.h */
5112 
5113          switch (ev->bButton) {
5114             case Button1:
5115             case Button2:
5116             case Button3:
5117             case Button4:
5118             case Button5:
5119             case 6:
5120             case 7:
5121             default:
5122                SUMA_LH("ButtonPress %d not known", ev->bButton);
5123                break;
5124          }
5125 
5126          /* trap for double click */
5127          if (Bev.time - lev.bTime < SUMA_DOUBLE_CLICK_MAX_DELAY) {
5128             ev->DoubleClick = YUP;
5129          } else {
5130             ev->DoubleClick = NOPE;
5131          }
5132 
5133          if (  SUMAg_CF->SwapButtons_1_3 ||
5134                (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5135             int kk=ev->b1;
5136             ev->b1 = ev->b3;
5137             ev->b3 = kk;
5138          }
5139 
5140          break;
5141       case ButtonRelease:
5142          ev->mTime = 0;
5143          if (Bev.state & Button1Mask) ev->b1 = 1;
5144          if (Bev.state & Button2Mask) ev->b2 = 1;
5145          if (Bev.state & Button3Mask) ev->b3 = 1;
5146          if (Bev.state & Button4Mask) ev->b4 = 1;
5147          if (Bev.state & Button5Mask) ev->b5 = 1;
5148          if (ev->bButton == 6) ev->b6 = 1; /* on macs Button6 not in X.h */
5149          if (ev->bButton == 7) ev->b7 = 1; /* on macs Button7 not in X.h */
5150 
5151          if (SUMAg_CF->SwapButtons_1_3 ||
5152              (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5153             int kk=ev->b1;
5154             ev->b1 = ev->b3;
5155             ev->b3 = kk;
5156          }
5157          break;
5158 
5159       case MotionNotify:
5160          if (Mev.state & Button1MotionMask) ev->b1m = 1;
5161          if (Mev.state & Button2MotionMask) ev->b2m = 1;
5162          if (Mev.state & Button3MotionMask) ev->b3m = 1;
5163          if (Mev.state & Button4MotionMask) ev->b4m = 1;
5164          if (Mev.state & Button5MotionMask) ev->b5m = 1;
5165          if (Mev.state) { SUMA_LH("   Something mot\n"); }
5166 
5167          /* The conditions and new assignments of mButton
5168          below is stupid. But I won't touch it until I
5169          have to. Reassignments should be to b1m, b2m, etc.
5170          mButton should not be touched.
5171          Also, there should be no need for these numerous
5172          conditions. If swapping is needed, b1m and b3m
5173          values should be swaped. Things like SUMA_Button_12_Motion
5174          should be made into functions that return an answer
5175          based on ev's contents */
5176          if (  SUMAg_CF->SwapButtons_1_3 ||
5177                (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5178            if (((Mev.state & Button3MotionMask) &&
5179                                              (Mev.state & Button2MotionMask))
5180             || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
5181                int kk=ev->b1m;
5182                ev->b1m = ev->b3m;
5183                ev->b3m = kk;
5184                ev->mButton = SUMA_Button_12_Motion;
5185             } else if(Mev.state & Button3MotionMask) {
5186                ev->mButton = SUMA_Button_1_Motion;
5187                int kk=ev->b1m;
5188                ev->b1m = ev->b3m;
5189                ev->b3m = kk;
5190             }else if(Mev.state & Button2MotionMask) {
5191                ev->mButton = SUMA_Button_2_Motion;
5192             }else if(Mev.state & Button1MotionMask) {
5193 
5194                ev->mButton = SUMA_Button_3_Motion;
5195             }else {
5196                break;
5197             }
5198          } else {
5199             if (((Mev.state & Button1MotionMask) &&
5200                                                 (Mev.state & Button2MotionMask))
5201              || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
5202                ev->mButton = SUMA_Button_12_Motion;
5203             } else if(Mev.state & Button1MotionMask) {
5204                ev->mButton = SUMA_Button_1_Motion;
5205             }else if(Mev.state & Button2MotionMask) {
5206                ev->mButton = SUMA_Button_2_Motion;
5207             } else if(Mev.state & Button3MotionMask) {
5208                ev->mButton = SUMA_Button_3_Motion;
5209             }else {
5210                break;
5211             }
5212          }
5213          switch (ev->mButton) {
5214             case SUMA_Button_12_Motion:
5215             case SUMA_Button_2_Shift_Motion:
5216                if (ev->mTime) {
5217                   ev->mDelta = Mev.time - lev.mTime;
5218                   ev->mDeltaX = Mev.x - lev.mX;
5219                   ev->mDeltaY = Mev.y - lev.mY;
5220                } else {
5221                   ev->mDelta  = 0;
5222                   ev->mDeltaX = 0;
5223                   ev->mDeltaY = 0;
5224                }
5225                break;
5226             case SUMA_Button_2_Motion:
5227                break;
5228             case SUMA_Button_3_Motion:
5229                break;
5230       }
5231 
5232    }
5233    if (LocalHead) {
5234       SUMA_ShowEvent(ev, 0, "EventRecord:\n");
5235       SUMA_ShowEvent(ev, 1, "EventRecord:\n");
5236    } else if (SUMAg_CF->Echo_KeyPress) {
5237       SUMA_ShowEvent(ev, 1, "EventRecord:\n");
5238    }
5239 
5240    /* keep local copy of last event */
5241    memcpy(&lev, ev, sizeof(SUMA_EVENT));
5242 
5243    SUMA_RETURN(ev);
5244 }
5245 
5246 /*! Mouse and Keyboard input handler function for SUMA's viewer
5247     START shifting to SUMA_RecordEvent() and its helper functions
5248     like SUMA_Alt_Event(), etc.
5249     You should also split SUMA_input() into SUMA_input_Xevent()
5250     and SUMA_input_eng(). Where SUMA_input_Xevent() just sets
5251     SUMAg_CF->lev and SUMA_input_eng() works entirely off of
5252     SUMAg_CF->lev . This way you would be able to completely
5253     drive SUMA_input_eng() without any mouse movement/X structs
5254     etc. All you need is to manipulate the content of lev.
5255 */
SUMA_input(Widget w,XtPointer clientData,XtPointer callData)5256 void SUMA_input(Widget w, XtPointer clientData, XtPointer callData)
5257 {
5258    static char FuncName[]= {"SUMA_input"};
5259    GLwDrawingAreaCallbackStruct *cd;
5260    char buffer[10], cbuf = '\0', cbuf2='\0';
5261    KeySym keysym;
5262    int xls=-1, ntot, id = 0, ND, ip, NP;
5263    SUMA_EngineData *ED = NULL;
5264    char CommString[SUMA_MAX_COMMAND_LENGTH];
5265    char s[SUMA_MAX_STRING_LENGTH], sfield[100], sdestination[100];
5266    static char ssource[]={"suma"};
5267    char modifierBuf[32];
5268    int it, ii, iv3[3], hit = 0, SwasHit = 0;
5269    float **fm, fv3[3], fv15[15];
5270    XKeyEvent Kev;
5271    XButtonEvent Bev;
5272    XMotionEvent Mev;
5273    int isv;
5274    SUMA_SurfaceViewer *sv, *svi = NULL;
5275    GLfloat *glar_ColorList = NULL;
5276    static Time B1time = 0, M1time=0, M1delta=0;
5277    static int pButton, mButton, rButton;
5278    SUMA_Boolean ROI_mode;
5279    static SUMA_Boolean DoubleClick = NOPE;
5280    DListElmt *NextElm= NULL;
5281    float bevx, bevy, mevx, mevy, wwid, whei, zc_fac, mvx_fac, mvy_fac;
5282    static int mvxlast, mvylast, mvdeltax, mvdeltay;
5283    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL; /* Use this only to create prompt
5284                                              that are not to be preserved */
5285    SUMA_Boolean LocalHead = NOPE; /* local debugging messages */
5286    int  i, planeIndex;
5287    static int locallySelectedPlane = 0;
5288    SUMA_ENTRY;
5289    static DList *list = NULL;
5290 
5291 
5292    /* get the callData pointer */
5293    cd = (GLwDrawingAreaCallbackStruct *) callData;
5294 
5295    /* find out who's calling, only GLXAREA calls this function */
5296    SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
5297    if (isv < 0) {
5298       fprintf (SUMA_STDERR,
5299                "Error %s: Failed in macro SUMA_GLXAREA_WIDGET2SV.\n", FuncName);
5300       SUMA_RETURNe;
5301    }
5302    SUMA_LH("A call from SUMA_SurfaceViewer[%d], Pointer %p\n", isv, sv);
5303 
5304    /* ******** ABOUT EVENT HANDLING ************** */
5305    /* Eventually you should use the structure
5306       created by RecordEvent to decide on what was clicked
5307       and how. While a little less efficient than
5308       what is done below, RecordEvent will eventually
5309       be considerably more flexible, and easier to debug.
5310       But for now, so that visible progress can be made,
5311       I will leave button processing and queries below
5312       as is, and try to make the switch gradually */
5313 
5314    SUMAg_CF->lev = SUMA_RecordEvent( cd->event, SUMAg_CF->lev);
5315 
5316    Kev = *(XKeyEvent *) &cd->event->xkey; /* RickR's suggestion to comply with
5317                                  ANSI C, no type casting of structures  July 04*/
5318    Bev = *(XButtonEvent *) &cd->event->xbutton;
5319    Mev = *(XMotionEvent *) &cd->event->xmotion;
5320 
5321    /* a sample keypresses */
5322    if (SUMAg_CF->Echo_KeyPress) {
5323       if (Kev.type == KeyPress) {
5324          buffer[0] = '\0';
5325          xls = XLookupString((XKeyEvent *) cd->event, buffer, 8, &keysym, NULL);
5326          fprintf (SUMA_STDERR,"%s KeyPress char>>%s<< sym>>%d<< ",
5327                   FuncName, buffer, (int)keysym);
5328       } else {
5329          fprintf (SUMA_STDERR,"%s Mouse Action: ", FuncName);
5330       }
5331       if (Kev.state & ShiftMask) {
5332          fprintf (SUMA_STDERR,"Shift ");
5333       }
5334       if (Kev.state & ControlMask){
5335          fprintf (SUMA_STDERR,"Control ");
5336       }
5337       if (Kev.state & Mod1Mask){
5338          fprintf (SUMA_STDERR,"alt ");
5339       }
5340       if (Kev.state & Mod2Mask){
5341          fprintf (SUMA_STDERR,"Mod2 (command on mac) ");
5342       }
5343       if (Kev.state & Mod3Mask){
5344          fprintf (SUMA_STDERR,"Mod3 ");
5345       }
5346       if (Kev.state & Mod4Mask){
5347          fprintf (SUMA_STDERR,"Mod4 ");
5348       }
5349       if (Kev.state & Mod5Mask){
5350          fprintf (SUMA_STDERR,"Mod5 ");
5351       }
5352       if (Kev.state & SUMA_APPLE_AltOptMask){
5353          fprintf (SUMA_STDERR,"Apple Alt/Opt ");
5354       }
5355       fprintf (SUMA_STDERR,"State %d\n\n", Kev.state);
5356   }
5357 
5358   switch (Kev.type) { /* switch event type */
5359   case KeyPress:
5360   {
5361       if (xls < 0) {
5362          /* avoid double call in case SUMAg_CF->Echo_KeyPress called already */
5363          xls = XLookupString((XKeyEvent *) cd->event, buffer, 8, &keysym, NULL);
5364       }
5365       // fprintf(stderr, "***** keysym = %ld\n", keysym);
5366 
5367         // Modifier
5368         sprintf(modifierBuf, "\0");
5369         if (SUMA_ALTHELL) strcat(modifierBuf, "Alt+");
5370         if ((Kev.state & ControlMask)) strcat(modifierBuf, "Ctrl+");
5371 
5372       /* XK_* are found in keysymdef.h */
5373       switch (keysym) { /* keysym */
5374          case XK_bracketleft: /* The left bracket */
5375             if (!SUMA_bracketleft_Key(sv, "[", "interactive")) {
5376                SUMA_S_Err("Failed in key func.");
5377             }
5378             break;
5379 
5380          case XK_bracketright: /* The right bracket */
5381             if (!SUMA_bracketright_Key(sv, "]", "interactive")) {
5382                SUMA_S_Err("Failed in key func.");
5383             }
5384             break;
5385 
5386          case XK_slash:
5387             if (Kev.state & ControlMask){
5388                 if (!SUMA_slash_Key(sv, "Ctrl+/", "interactive")) {
5389                    SUMA_S_Err("Failed in key func.");
5390                 }
5391             } else {
5392                 if (!SUMA_slash_Key(sv, "/", "interactive")) {
5393                    SUMA_S_Err("Failed in key func.");
5394                 }
5395             }
5396             break;
5397 
5398          case XK_space:   /* The spacebar. */
5399             if (!SUMA_space_Key(sv, "SPACE", "interactive")) {
5400                SUMA_S_Err("Failed in key func.");
5401                }
5402             break;
5403 
5404          case XK_Escape:
5405             if (Kev.state & ShiftMask){
5406                 if (!SUMA_escape_key(sv, "Shift+escape", "interactive",
5407                     w, clientData, callData)) {
5408                    SUMA_S_Err("Failed in key func.");
5409                    }
5410             } else {
5411                 if (!SUMA_escape_key(sv, "escape", "interactive",
5412                     w, clientData, callData)) {
5413                    SUMA_S_Err("Failed in key func.");
5414                    }
5415             }
5416             break;
5417 
5418          case XK_A:
5419              if (!SUMA_A_Key(sv, "Shift+A", "interactive")) {
5420                     SUMA_S_Err("Failed in key func.");
5421                }
5422                 break;
5423 
5424          case XK_a:
5425              if (!SUMA_A_Key(sv, "a", "interactive")) {
5426                     SUMA_S_Err("Failed in key func.");
5427                }
5428                 break;
5429 
5430          case XK_B:
5431                if (( Kev.state & ControlMask)){
5432                   if (SUMAg_CF->Dev ) {
5433                      if (!SUMA_B_Key(sv, "Shift+ctrl+B", "interactive")) {
5434                         SUMA_S_Err("Failed in key func.");
5435                      }
5436                   }
5437                } else {
5438                   if (!SUMA_B_Key(sv, "Shift+B", "interactive")) {
5439                      SUMA_S_Err("Failed in key func.");
5440                   }
5441                }
5442             break;
5443 
5444          case XK_b:
5445             if (!SUMA_B_Key(sv, "b", "interactive")) {
5446                SUMA_S_Err("Failed in key func.");
5447             }
5448             break;
5449 
5450          case XK_C:
5451             if ((SUMA_ALTHELL)){
5452                 if ((Kev.state & ControlMask)){ // Ctrl-Shift-alt-C (clip plane box
5453                     if (!SUMA_C_Key(sv, "Shift+Ctrl+Alt+C", "interactive")) {
5454                         SUMA_S_Err("Failed in key func.");
5455                     }
5456                 }else {
5457                     if (!SUMA_C_Key(sv, "Shift+Alt+C", "interactive")) {
5458                         SUMA_S_Err("Failed in key func.");
5459                     }
5460                 }
5461             }  else if ((Kev.state & ControlMask)){
5462                 if (!SUMA_C_Key(sv, "Shift+Ctrl+C", "interactive")) {
5463                     SUMA_S_Err("Failed in key func.");
5464                 }
5465             } else {
5466                 if (!SUMA_C_Key(sv, "Shift+C", "interactive")) {
5467                     SUMA_S_Err("Failed in key func.");
5468                 }
5469             }
5470             break;
5471 
5472          case XK_c:
5473             if (!SUMA_C_Key(sv, "c", "interactive")) {
5474                 SUMA_S_Err("Failed in key func.");
5475             }
5476             break;
5477 
5478          case XK_D:
5479             if (1) {
5480                if (SUMA_ALTHELL){
5481                   /*  Mod1Mask is alt in linux, Mod2Mask is the apple on mac*/
5482                } else {
5483                   if (!SUMA_D_Key(sv,"D", "interactive")) {
5484                      SUMA_S_Err("Failed in key func.");
5485                   }
5486                }
5487             }
5488             break;
5489 
5490          case XK_d:
5491             if (SUMAg_CF->Dev) {
5492                if (SUMA_ALTHELL){
5493                   /*  Mod1Mask is alt in linux, Mod2Mask is the apple on mac*/
5494                } else {
5495                   if (!SUMA_D_Key(sv,"d", "interactive")) {
5496                      SUMA_S_Err("Failed in key func.");
5497                   }
5498                }
5499             }
5500             break;
5501 
5502          case XK_e:
5503          case XK_dead_acute:  /* that is alt/option+e on macs
5504                                XK_dead_acute is 0xfe51 or decimal 65105 */
5505             if (SUMAg_CF->Dev) {
5506                if (SUMA_ALTHELL){ /* Mod1Mask is alt in linux,
5507                                      Mod2Mask is the apple on mac*/
5508                   SUMA_GL_ERRS;
5509                }
5510             }
5511             break;
5512 
5513          case XK_F:
5514             if (!SUMA_F_Key(sv, "Shift+F", "interactive")) {
5515                 SUMA_S_Err("Failed in key func.");
5516             }
5517             break;
5518 
5519          case XK_f:
5520             if ((Kev.state & ControlMask)){
5521                 if (!SUMA_F_Key(sv, "Ctrl+f", "interactive")) {
5522                     SUMA_S_Err("Failed in key func.");
5523                     }
5524             } else {
5525                 if (!SUMA_F_Key(sv, "f", "interactive")) {
5526                     SUMA_S_Err("Failed in key func.");
5527                     }
5528             }
5529             break;
5530 
5531          case XK_g:
5532             if (Kev.state & ControlMask){
5533                   if (SUMAg_CF->Dev) {
5534                      if (!SUMA_G_Key(sv, "ctrl+g", "interactive")) {
5535                         SUMA_S_Err("Failed in key func.");
5536                      }
5537                   }
5538                } else {
5539                   if (!SUMA_G_Key(sv, "g", "interactive")) {
5540                      SUMA_S_Err("Failed in key func.");
5541                   }
5542                }
5543              break;
5544 
5545          case XK_H:
5546               if (!SUMA_H_Key(sv, "Shift+H", "interactive")) {
5547                  SUMA_S_Err("Failed in key func.");
5548               }
5549              break;
5550 
5551          case XK_h:
5552             if (Kev.state & ControlMask){
5553                  if (!SUMA_H_Key(sv, "ctrl+h", "interactive")) {
5554                     SUMA_S_Err("Failed in key func.");
5555                  }
5556             } else {
5557                  if (!SUMA_H_Key(sv, "h", "interactive")) {
5558                     SUMA_S_Err("Failed in key func.");
5559                  }
5560             }
5561              break;
5562 
5563          case XK_j:
5564                if (Kev.state & ControlMask){
5565                   if (!SUMA_J_Key(sv, "ctrl+j", "interactive", NULL)) {
5566                      SUMA_S_Err("Failed in key func.");
5567                   }
5568                } else if (SUMA_ALTHELL){
5569                   if (!SUMA_J_Key(sv, "alt+j", "interactive", NULL)) {
5570                      SUMA_S_Err("Failed in key func.");
5571                   }
5572                } else {
5573                   if (!SUMA_J_Key(sv, "j", "interactive", NULL)) {
5574                      SUMA_S_Err("Failed in key func.");
5575                   }
5576                }
5577             break;
5578 
5579          case XK_J:
5580                if (!SUMA_J_Key(sv, "J", "interactive", NULL)) {
5581                      SUMA_S_Err("Failed in key func.");
5582                }
5583             break;
5584 
5585          case XK_l:
5586                if (Kev.state & ControlMask){
5587                   if (!SUMA_L_Key(sv, "ctrl+l", "interactive", NULL)) {
5588                         SUMA_S_Err("Failed in key func.");
5589                   }
5590                } else if (SUMA_ALTHELL){
5591                   if (!SUMA_L_Key(sv, "alt+l", "interactive", NULL)) {
5592                      SUMA_S_Err("Failed in key func.");
5593                   }
5594                } else {
5595                   if (!SUMA_L_Key(sv, "l", "interactive", NULL)) {
5596                         SUMA_S_Err("Failed in key func.");
5597                   }
5598                }
5599             break;
5600 
5601          case XK_L:
5602                if (Kev.state & ControlMask){
5603                   if (!SUMA_L_Key(sv, "ctrl+L", "interactive", NULL)) {
5604                         SUMA_S_Err("Failed in key func.");
5605                   }
5606                } else if (SUMA_ALTHELL){
5607                   if (!SUMA_L_Key(sv, "alt+L", "interactive", NULL)) {
5608                      SUMA_S_Err("Failed in key func.");
5609                   }
5610                } else {
5611                   if (!SUMA_L_Key(sv, "L", "interactive", NULL)) {
5612                         SUMA_S_Err("Failed in key func.");
5613                   }
5614                }
5615             break;
5616 
5617          case XK_M:
5618             if ((SUMA_ALTHELL) && (Kev.state & ControlMask) ){
5619                   if (!SUMA_M_Key(sv, "alt+ctrl+M", "interactive")) {
5620                      SUMA_S_Err("Failed in key func.");
5621                   }
5622             }
5623             break;
5624 
5625          case XK_m:
5626                if (Kev.state & ControlMask){
5627                   if (SUMAg_CF->Dev) {
5628                      if (!SUMA_M_Key(sv, "ctrl+m", "interactive")) {
5629                         SUMA_S_Err("Failed in key func.");
5630                      }
5631                   }
5632                } else {
5633                   if (!SUMA_M_Key(sv, "m", "interactive")) {
5634                      SUMA_S_Err("Failed in key func.");
5635                   }
5636                }
5637              break;
5638 
5639          case XK_N:
5640              if (!SUMA_N_Key(sv, "Shift+N", "interactive")) {
5641                 SUMA_S_Err("Failed in key func.");
5642              }
5643              break;
5644 
5645          case XK_n:
5646             // if (clippingPlaneMode){
5647             if (Kev.state & ControlMask){
5648                   SUMA_LH("Going to N_Key");
5649                   if (!SUMA_N_Key(sv, "ctrl+n", "interactive")) {
5650                      SUMA_S_Err("Failed in key func.");
5651                   }
5652                }else {
5653                   if (SUMAg_CF->Dev) {
5654                      if (!SUMA_N_Key(sv, "n", "interactive")) {
5655                         SUMA_S_Err("Failed in key func.");
5656                      }
5657                   }
5658                }
5659             break;
5660          case XK_o:
5661             if (SUMA_ALTHELL) {
5662                if (!SUMA_O_Key(sv, "alt+o", "interactive")) {
5663                   SUMA_S_Err("Failed in key func.");
5664                }
5665             } else if (Kev.state & ControlMask){
5666                if (!SUMA_O_Key(sv, "ctrl+o", "interactive")) {
5667                   SUMA_S_Err("Failed in key func.");
5668                }
5669             } else {
5670                if (!SUMA_O_Key(sv, "o", "interactive")) {
5671                   SUMA_S_Err("Failed in key func.");
5672                }
5673             }
5674             break;
5675          case XK_O:
5676             if (SUMA_ALTHELL) {
5677                if (!SUMA_O_Key(sv, "alt+O", "interactive")) {
5678                   SUMA_S_Err("Failed in key func.");
5679                }
5680             } else if (Kev.state & ControlMask){
5681                if (!SUMA_O_Key(sv, "ctrl+O", "interactive")) {
5682                   SUMA_S_Err("Failed in key func.");
5683                }
5684             } else {
5685                if (!SUMA_O_Key(sv, "O", "interactive")) {
5686                   SUMA_S_Err("Failed in key func.");
5687                }
5688             }
5689             break;
5690          case XK_p:
5691             if (Kev.state & ControlMask){
5692                if (!SUMA_P_Key(sv, "ctrl+p", "interactive")) {
5693                   SUMA_S_Err("Failed in key func.");
5694                }
5695             } else {
5696                if (!SUMA_P_Key(sv, "p", "interactive")) {
5697                   SUMA_S_Err("Failed in key func.");
5698                }
5699             }
5700             break;
5701 
5702          case XK_P:
5703             if (!SUMA_P_Key(sv, "P", "interactive")) {
5704                SUMA_S_Err("Failed in key func.");
5705             }
5706             break;
5707 
5708          case XK_r:
5709             if (SUMA_ALTHELL) {
5710                if (!SUMA_R_Key(sv, "alt+r", "interactive")) {
5711                   SUMA_S_Err("Failed in key func.");
5712                }
5713             } else if (Kev.state & ControlMask){
5714                if (!SUMA_R_Key(sv, "ctrl+r", "interactive")) {
5715                   SUMA_S_Err("Failed in key func.");
5716                }
5717             } else {
5718                if (!SUMA_R_Key(sv, "r", "interactive")) {
5719                   SUMA_S_Err("Failed in key func.");
5720                }
5721             }
5722             break;
5723 
5724          case XK_R:
5725             if (Kev.state & ControlMask){
5726                if (!SUMA_R_Key(sv, "ctrl+R", "interactive")) {
5727                      SUMA_S_Err("Failed in key func.");
5728                }
5729             } else {
5730                if (!SUMA_R_Key(sv, "R", "interactive")) {
5731                      SUMA_S_Err("Failed in key func.");
5732                }
5733             }
5734             break;
5735 
5736          case XK_S:
5737            if (!SUMA_S_Key(sv, "Shift+S", "interactive")) {
5738                  SUMA_S_Err("Failed in key func.");
5739            }
5740            break;
5741 
5742          case XK_s:
5743             if ((SUMA_ALTHELL) && (Kev.state & ControlMask) ){
5744                if (!SUMA_S_Key(sv, "Alt+Ctrl+s", "interactive")) {
5745                      SUMA_S_Err("Failed in key func.");
5746                }
5747             } else if (SUMA_ALTHELL){
5748                if (!SUMA_S_Key(sv, "Alt+s", "interactive")) {
5749                      SUMA_S_Err("Failed in key func.");
5750                }
5751             } else if (!SUMA_S_Key(sv, "s", "interactive")) {
5752                  SUMA_S_Err("Failed in key func.");
5753             }
5754             break;
5755 
5756          case XK_t:
5757             if ((Kev.state & ControlMask)){
5758                if (!SUMA_T_Key(sv, "ctrl+t", "interactive")) {
5759                   SUMA_S_Err("Failed in key func.");
5760                }
5761             } else {
5762                if (!SUMA_T_Key(sv, "t", "interactive")) {
5763                   SUMA_S_Err("Failed in key func.");
5764                }
5765             }
5766             break;
5767 
5768          case XK_T:
5769             if (!SUMA_T_Key(sv, "T", "interactive")) {
5770                SUMA_S_Err("Failed in key func.");
5771             }
5772             break;
5773 
5774          case XK_u:
5775             if (!SUMA_U_Key(sv, "u", "interactive")) {
5776                SUMA_S_Err("Failed in key func.");
5777             }
5778             break;
5779          case XK_U:
5780             if (!SUMA_U_Key(sv, "U", "interactive")) {
5781                SUMA_S_Err("Failed in key func.");
5782             }
5783             break;
5784          case XK_v:
5785             #if 0
5786             /*** No longer in use, Jan 03 2004 */
5787             if (SUMAg_CF->Dev) {
5788                SUMA_Show_SurfaceViewer_Struct (sv, stdout, 0);
5789             }
5790             #endif
5791             break;
5792 
5793          case XK_W:
5794             if ((Kev.state & ControlMask)){
5795                if (!SUMA_W_Key(sv, "Shift+ctrl+W", "interactive")) {
5796                   SUMA_S_Err("Failed in key func.");
5797                }
5798             } else {
5799                if (!SUMA_W_Key(sv, "Shift+W", "interactive")) {
5800                   SUMA_S_Err("Failed in key func.");
5801                }
5802             }
5803             break;
5804 
5805          case XK_w:
5806                if (!SUMA_W_Key(sv, "w", "interactive")) {
5807                   SUMA_S_Err("Failed in key func.");
5808                }
5809             break;
5810 
5811          case XK_Z:
5812             if (!SUMA_Z_Key(sv, "Z", "interactive")) {
5813                SUMA_S_Err("Failed in key func.");
5814             }
5815             break;
5816 
5817          case XK_z:
5818             if (!SUMA_Z_Key(sv, "z", "interactive")) {
5819                SUMA_S_Err("Failed in key func.");
5820             }
5821             break;
5822 
5823          // ctrl-<number> keys, where number in [1,6] select the clipping plane by index
5824          case XK_1:
5825                 strcat(modifierBuf, "1");
5826                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5827                  SUMA_S_Err("Failed in Key function.");
5828                 }
5829             break;
5830          case XK_2:
5831                 strcat(modifierBuf, "2");
5832                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5833                  SUMA_S_Err("Failed in Key function.");
5834                 }
5835             break;
5836          case XK_3:
5837                 strcat(modifierBuf, "3");
5838                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5839                  SUMA_S_Err("Failed in Key function.");
5840                 }
5841             break;
5842          case XK_4:
5843                 strcat(modifierBuf, "4");
5844                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5845                  SUMA_S_Err("Failed in Key function.");
5846                 }
5847             break;
5848          case XK_5:
5849                 strcat(modifierBuf, "5");
5850                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5851                  SUMA_S_Err("Failed in Key function.");
5852                 }
5853             break;
5854          case XK_6:
5855                 strcat(modifierBuf, "6");
5856                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5857                  SUMA_S_Err("Failed in Key function.");
5858                 }
5859             break;
5860          case XK_7:
5861                 strcat(modifierBuf, "7");
5862                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5863                  SUMA_S_Err("Failed in Key function.");
5864                 }
5865             break;
5866          case XK_8:
5867                 strcat(modifierBuf, "8");
5868                 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5869                  SUMA_S_Err("Failed in Key function.");
5870                 }
5871             break;
5872 
5873          case XK_0: // Zero key
5874             strcat(modifierBuf, "0");
5875             if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5876              SUMA_S_Err("Failed in Key function.");
5877             }
5878             break;
5879 
5880          case XK_asterisk:
5881             if (!SUMA_asterisk_Key(sv, "*", "drivesuma")) {
5882              SUMA_S_Err("Failed in Key function.");
5883             }
5884             break;
5885 
5886           case XK_at:
5887             if (!SUMA_at_Key(sv, "@", "drivesuma")) {
5888              SUMA_S_Err("Failed in Key function.");
5889             }
5890             break;
5891 
5892          case XK_parenleft:
5893             if (!SUMA_parenleft_Key(sv, "(", "drivesuma", w, clientData, callData)) {
5894              SUMA_S_Err("Failed in Key function.");
5895             }
5896             break;
5897 
5898          case XK_comma:
5899             if (!SUMA_comma_Key(sv, "comma", "interactive")) {
5900                SUMA_S_Err("Failed in key func.");
5901             }
5902             break;
5903 
5904          case XK_period:
5905             if (!SUMA_period_Key(sv, "period", "interactive")) {
5906                SUMA_S_Err("Failed in key func.");
5907             }
5908             break;
5909 
5910          case XK_F1: /* F1 */
5911             /*printf("F1\n");*/
5912             if (!SUMA_F1_Key(sv, "F1", "interactive")) {
5913                SUMA_S_Err("Failed in key func.");
5914             }
5915             break;
5916 
5917          case XK_F2:
5918             /*printf("F2\n");*/
5919             if (!SUMA_F2_Key(sv, "F2", "interactive")) {
5920                SUMA_S_Err("Failed in key func.");
5921             }
5922             break;
5923 
5924          case XK_F3: /* F3 */
5925             if (!SUMA_F3_Key(sv, "F3", "interactive")) {
5926                SUMA_S_Err("Failed in key func.");
5927             }
5928             break;
5929 
5930          case XK_F4: /* F4 */
5931             if (!SUMA_F4_Key(sv, "F4", "interactive")) {
5932                SUMA_S_Err("Failed in key func.");
5933             }
5934             break;
5935 
5936          case XK_F5: /* F5 */
5937             if (!SUMA_F5_Key(sv, "F5", "interactive")) {
5938                SUMA_S_Err("Failed in key func.");
5939             }
5940             break;
5941 
5942          case XK_F6: /*F6 */
5943             if (!SUMA_F6_Key(sv, "F6", "interactive")) {
5944                SUMA_S_Err("Failed in key func.");
5945             }
5946             break;
5947 
5948          case XK_F7: /*F7 */
5949             if (!SUMA_F7_Key(sv, "F7", "interactive")) {
5950                SUMA_S_Err("Failed in key func.");
5951             }
5952             break;
5953 
5954          case XK_F8: /*F8 */
5955             if (!SUMA_F8_Key(sv, "F8", "interactive")) {
5956                SUMA_S_Err("Failed in key func.");
5957             }
5958             break;
5959 
5960          case XK_F9: /*F9 */
5961             if (!SUMA_F9_Key(sv, "F9", "interactive")) {
5962                SUMA_S_Err("Failed in key func.");
5963             }
5964             break;
5965 
5966          case XK_F10: /*F10 */
5967             if (!SUMA_F10_Key(sv, "F10", "interactive", NULL)) {
5968                SUMA_S_Err("Failed in key func.");
5969             }
5970             break;
5971          case XK_F11: /* F11 */
5972             if (!SUMA_F11_Key(sv, "F11", "interactive", NULL)) {
5973                SUMA_S_Err("Failed in key func.");
5974             }
5975             break;
5976          case XK_F12: /* F12 */
5977             if (!SUMA_F12_Key(sv, "F12", "interactive")) {
5978                SUMA_S_Err("Failed in key func.");
5979             }
5980             break;
5981          case XK_F13:
5982             if (!SUMA_F13_Key(sv, "F12", "interactive")) {
5983                SUMA_S_Err("Failed in key func.");
5984             }
5985             break;
5986          case XK_Home:
5987             if (!SUMA_home_Key(sv, "home", "interactive")) {
5988                SUMA_S_Err("Failed in key func.");
5989             }
5990             break;
5991 
5992         case XK_plus:
5993             if (!SUMA_plus_Key(sv, "+", "interactive")) {
5994                SUMA_S_Err("Failed in key func.");
5995             }
5996             break;
5997 
5998         case XK_minus:
5999             if (!SUMA_minus_Key(sv, "-", "interactive")) {
6000                SUMA_S_Err("Failed in key func.");
6001             }
6002             break;
6003 
6004         case XK_equal:
6005             if (!SUMA_equal_Key(sv, "=", "interactive")) {
6006                SUMA_S_Err("Failed in key func.");
6007             }
6008             break;
6009 
6010          case XK_Left:   /*KEY_LEFT:*/
6011          {
6012             if (clippingPlaneMode && SUMA_ALTHELL){
6013                if (!SUMA_Left_Key(sv, "Alt+left", "interactive")) {
6014                   SUMA_S_Err("Error in key func.");
6015                   break;
6016                }
6017                 // clipPlaneTransform(0, -tiltInc, 0, 0, -1, 0, 0);
6018             } else if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6019                if (!SUMA_Left_Key(sv, "ctrl+shift+left", "interactive")) {
6020                   SUMA_S_Err("Error in key func.");
6021                   break;
6022                }
6023             }else if (Kev.state & ShiftMask) {
6024                if (!SUMA_Left_Key(sv, "shift+left", "interactive")) {
6025                   SUMA_S_Err("Error in key func.");
6026                   break;
6027                }
6028             }else if (Kev.state & ControlMask){
6029                if (!SUMA_Left_Key(sv, "ctrl+left", "interactive")) {
6030                   SUMA_S_Err("Error in key func.");
6031                   break;
6032                }
6033             }else if (SUMA_ALTHELL) {
6034                if ((Kev.state & ControlMask)) {
6035                    if (!SUMA_Left_Key(sv, "alt+ctrl+left", "interactive")) {
6036                       SUMA_S_Err("Error in key func.");
6037                       break;
6038                    }
6039                } else if ((Kev.state & ShiftMask)) {
6040                    if (!SUMA_Left_Key(sv, "alt+shift+left", "interactive")) {
6041                       SUMA_S_Err("Error in key func.");
6042                       break;
6043                    }
6044                }
6045                else if (!SUMA_Left_Key(sv, "alt+left", "interactive")) {
6046                   SUMA_S_Err("Error in key func.");
6047                   break;
6048                }
6049             }else {
6050                if (!SUMA_Left_Key(sv, "left", "interactive")) {
6051                   SUMA_S_Err("Error in key func.");
6052                   break;
6053                }
6054             }
6055         }
6056             break;
6057 
6058          case XK_Right:   /*KEY_RIGHT: */
6059             if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6060                if (!SUMA_Right_Key(sv, "ctrl+shift+right", "interactive")) {
6061                   SUMA_S_Err("Error in key func.");
6062                   break;
6063                }
6064             }else if (Kev.state & ShiftMask) {
6065                if (!SUMA_Right_Key(sv, "shift+right", "interactive")) {
6066                   SUMA_S_Err("Error in key func.");
6067                   break;
6068                }
6069             }else if (Kev.state & ControlMask){
6070                if (!SUMA_Right_Key(sv, "ctrl+right", "interactive")) {
6071                   SUMA_S_Err("Error in key func.");
6072                   break;
6073                }
6074             }else if (SUMA_ALTHELL) {
6075                if (!SUMA_Right_Key(sv, "alt+right", "interactive")) {
6076                   SUMA_S_Err("Error in key func.");
6077                   break;
6078                }
6079             }else {
6080                if (!SUMA_Right_Key(sv, "right", "interactive")) {
6081                   SUMA_S_Err("Error in key func.");
6082                   break;
6083                }
6084             }
6085             break;
6086 
6087          case XK_Down:   /*KEY_DOWN*/
6088            if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6089                if (!SUMA_Down_Key(sv, "ctrl+shift+down", "interactive")) {
6090                   SUMA_S_Err("Error in key func.");
6091                   break;
6092                }
6093             }else if (Kev.state & ShiftMask) {
6094                if (!SUMA_Down_Key(sv, "shift+down", "interactive")) {
6095                   SUMA_S_Err("Error in key func.");
6096                   break;
6097                }
6098             }else if (Kev.state & ControlMask){
6099                if (!SUMA_Down_Key(sv, "ctrl+down", "interactive")) {
6100                   SUMA_S_Err("Error in key func.");
6101                   break;
6102                }
6103             }else if (SUMA_ALTHELL) {
6104                if (!SUMA_Down_Key(sv, "alt+down", "interactive")) {
6105                   SUMA_S_Err("Error in key func.");
6106                   break;
6107                }
6108             }else {
6109                if (!SUMA_Down_Key(sv, "down", "interactive")) {
6110                   SUMA_S_Err("Error in key func.");
6111                   break;
6112                }
6113             }
6114 
6115             break;
6116 
6117          case XK_Up: /*KEY_UP*/
6118             if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6119                if (!SUMA_Up_Key(sv, "ctrl+shift+up", "interactive")) {
6120                   SUMA_S_Err("Error in key func.");
6121                   break;
6122                }
6123             }else if (Kev.state & ShiftMask) {
6124                if (!SUMA_Up_Key(sv, "shift+up", "interactive")) {
6125                   SUMA_S_Err("Error in key func.");
6126                   break;
6127                }
6128             }else if (Kev.state & ControlMask){
6129                if (!SUMA_Up_Key(sv, "ctrl+up", "interactive")) {
6130                   SUMA_S_Err("Error in key func.");
6131                   break;
6132                }
6133             }else if (SUMA_ALTHELL) {
6134                if (!SUMA_Up_Key(sv, "alt+up", "interactive")) {
6135                   SUMA_S_Err("Error in key func.");
6136                   break;
6137                }
6138             }else {
6139                if (!SUMA_Up_Key(sv, "up", "interactive")) {
6140                   SUMA_S_Err("Error in key func.");
6141                   break;
6142                }
6143             }
6144             break;
6145          default:
6146             break;
6147 
6148       } /* keysym */
6149   } // KeyPress
6150    break;
6151   case KeyRelease:
6152   {
6153     switch (keysym) { /* keysym */
6154         case XK_Control_L:
6155         case XK_Control_R:
6156             break;
6157     }   // keysym
6158   }
6159   break;
6160 
6161    case ButtonPress:
6162       SUMAg_CF->X->ButtonDown=1;
6163       pButton = Bev.button; // PDL: Has value 4 if scrollwheel scrolled forward and value 5 if scrollwheel scrolled back
6164       SUMA_LHv("In ButtonPress Button %d, %d @ x,y=%d,%d\n",
6165                               pButton, SUMAg_CF->X->ButtonDown, Bev.x, Bev.y);
6166       if (  SUMAg_CF->SwapButtons_1_3 ||
6167             (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
6168          if (pButton == Button1) pButton = Button3;
6169          else if (pButton == Button3) pButton = Button1;
6170       }
6171       if (SUMAg_CF->Echo_KeyPress) {
6172          fprintf (SUMA_STDERR,"Button Press: %d (%d,%d,%d,%d,%d)\n"
6173                               , pButton, Button1, Button2, Button3, Button4,
6174                               Button5);
6175       }
6176 
6177      /* trap for double click */
6178       if (Bev.time - B1time < SUMA_DOUBLE_CLICK_MAX_DELAY) {
6179          if (LocalHead) fprintf(SUMA_STDERR, "%s: Double click.\n", FuncName);
6180          DoubleClick = YUP;
6181       } else {
6182          DoubleClick = NOPE;
6183       }
6184 
6185 
6186       if (strstr(sv->State, "GMATRIX")==sv->State) {
6187          /* For graph in matrix representation swap buttons 1 and 2 */
6188          switch (pButton) {
6189             case Button1:
6190                pButton = Button2;
6191                break;
6192             case Button2:
6193                pButton = Button1;
6194                break;
6195          }
6196       }
6197 
6198 
6199       B1time = Bev.time;
6200       M1time = 0;
6201       switch (pButton) { /* switch type of button Press */
6202          case Button1:
6203             if (Bev.state & Button2Mask) {
6204                /* setup initial zooming conditions */
6205                /*fprintf(SUMA_STDERR,"%s: Button 1 &2 down. New\n", FuncName); */
6206                sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
6207                sv->GVS[sv->StdView].zoomDelta = 0;
6208             }else {
6209                bevx=(float)Bev.x; bevy = (float)Bev.y;
6210                /*fprintf(SUMA_STDERR,"%s: Button 1 down. New\n", FuncName);*/
6211                /* setup initial spinning conditions */
6212                sv->GVS[sv->StdView].spinBeginX = bevx;
6213                sv->GVS[sv->StdView].spinBeginY = bevy;
6214                sv->GVS[sv->StdView].spinDeltaX = 0;
6215                sv->GVS[sv->StdView].spinDeltaY = 0;
6216                /* check to see if other viewers need to be notified */
6217                ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
6218                if (SUMAg_CF->ViewLocked[ii]) {
6219                   for (it=0; it < SUMAg_N_SVv; ++it) {
6220                      svi = &SUMAg_SVv[it];
6221                      if (it != ii && SUMAg_CF->ViewLocked[it]) {
6222                         svi->GVS[svi->StdView].spinBeginX = bevx;
6223                         svi->GVS[svi->StdView].spinBeginY = bevy;
6224                         svi->GVS[svi->StdView].spinDeltaX = 0;
6225                         svi->GVS[svi->StdView].spinDeltaY = 0;
6226                      }
6227                   }
6228                }
6229                if (DoubleClick) {
6230                   if (Kev.state & ControlMask) SUMA_ResetPrying(sv);
6231                   else {
6232                      SUMA_HOME_QUAT(sv->StdView,
6233                                     sv->GVS[sv->StdView].currentQuat);
6234                      SUMA_postRedisplay(w, NULL, NULL);
6235                   }
6236                }
6237             }
6238             break;
6239          case Button4:
6240          case 6:  /* This is shift and wheel on mac, Button6 is not in X.h ! */
6241             // PDL: Ctrl-scroll forward
6242             if (clippingPlaneMode && pButton==4 && SUMA_ALTHELL && SUMAg_CF->N_ClipPlanes > 0){
6243                 clipPlaneTransform(0, 0, -scrollInc, 0,-1, 0, 0);
6244             } else {
6245 
6246                 if (pButton==6 || Bev.state & ShiftMask) {
6247                    SUMA_ALL_DO *ado=NULL;
6248                    char variant[2];
6249                    #if 0
6250                    int ii;
6251                    SUMA_VolumeObject *VO=NULL;
6252                    for (ii=0; ii<SUMAg_N_DOv; ++ii) {
6253                       if (SUMA_isVO(SUMAg_DOv[ii])) {
6254                          VO = (SUMA_VolumeObject *)(SUMAg_DOv[ii].OP);
6255                          if (VO->SelectedCutPlane >= 0) {
6256                             SUMA_LHv("Moving cut plane %d\n",
6257                                            VO->SelectedCutPlane);
6258                             if (!SUMA_MoveCutplane(VO, VO->SelectedCutPlane, 1.0)) {
6259                                SUMA_SLP_Err("Bad");
6260                             }
6261                          }
6262                  /* JB: only allow cutplane from 1st volume object,
6263                       otherwise remove 'break' */
6264                  break;
6265                       }
6266                    }
6267                    SUMA_postRedisplay(w, NULL, NULL);
6268                    #else
6269                    if ((ado = SUMA_SV_Focus_ADO(sv))) {
6270                       switch (ado->do_type) {
6271                          case VO_type: {
6272                             float incr = 1.0;
6273                             SUMA_VolumeObject *vo=(SUMA_VolumeObject *)ado;
6274                             SUMA_VOL_SAUX *VSaux = SUMA_ADO_VSaux(ado);
6275                             if (VSaux && VSaux->PR) {
6276                                if (SUMA_dset_gui_slice_from_tex_slice_d(vo->VE, 0,
6277                                               VSaux->PR->dAltSel+SUMA_VOL_SLC_EQ0,
6278                                               0, variant, NULL)   >=0 ){
6279                                   SUMA_set_slice(ado, variant, &incr,
6280                                                  "increment", 0);
6281                                }
6282                             }
6283                             SUMA_postRedisplay(w, NULL, NULL);
6284                             break; }
6285                          default:
6286                             SUMA_LH("Nothing here for types %s\n",
6287                                   ADO_TNAME(ado));
6288                             break;
6289                       }
6290                    }
6291                    #endif
6292                 } else if (pButton==6 || Bev.state & ControlMask) {
6293                    SUMA_ALL_DO *ado=NULL;
6294                    SUMA_X_SurfCont *SurfCont;
6295                    if (MASK_MANIP_MODE(sv)) {
6296                       ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
6297                       if (ado && ado->do_type == MASK_type) {
6298                          SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
6299                          float fv[3];
6300                          int irow=-1;
6301                          {
6302                             fv[0] = mdo->hdim[0]-(0.2*mdo->init_hdim[0]);
6303                             fv[1] = mdo->hdim[1]-(0.2*mdo->init_hdim[1]);
6304                             fv[2] = mdo->hdim[2]-(0.2*mdo->init_hdim[2]);
6305                             if (fv[0] < 0 || fv[1] < 0 || fv[2] < 0) {
6306                                SUMA_BEEP;
6307                                break;
6308                             }
6309                             SUMA_MDO_New_Dim(mdo, fv);
6310                          }
6311                          if ((SurfCont=SUMA_ADO_Cont(ado))) {
6312                             irow = SUMA_ObjectID_Row(SurfCont->MaskTable,
6313                                                      ADO_ID(ado));
6314                             if (irow >= 0) {
6315                                SUMA_InitMasksTable_row(SurfCont,mdo, irow);
6316                             }
6317                          }
6318                          SUMA_NEW_MASKSTATE();
6319                          /* enough for now */
6320                          goto REDISP;
6321                       }
6322                    } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
6323                                ado->do_type == GRAPH_LINK_type &&
6324                                !strcmp(SUMA_ADO_variant(ado),"GMATRIX")) {
6325                       SUMA_OVERLAYS *Sover = NULL;
6326                       SUMA_LH("Going forward one sub-brick");
6327                       Sover = SUMA_ADO_CurColPlane(ado);
6328                       SUMA_SwitchColPlaneIntensity( ado, Sover,
6329                                                     SUMA_FORWARD_ONE_SUBBRICK, 1);
6330                       /* redisplay done in function above ... */
6331                       SUMA_RETURNe;
6332                    }
6333                 } else {
6334                    if (!SUMA_Z_Key(sv, "z", "interactive")) {
6335                       SUMA_S_Err("Failed in key func.");
6336                    }
6337                 }
6338             }
6339             break;
6340          case Button5:
6341          case 7: /* This is shift and wheel on mac, Button7 is not in X.h ! */
6342             // PDL: Ctrl-scroll backward
6343             if (clippingPlaneMode && pButton==5 && SUMA_ALTHELL && SUMAg_CF->N_ClipPlanes > 0){
6344                 clipPlaneTransform(0, 0, scrollInc, 0,-1, 0, 0);
6345            } else {
6346 
6347                 if (pButton==7 || Bev.state & ShiftMask) {
6348                    SUMA_ALL_DO *ado=NULL;
6349                    char variant[2];
6350                    #if 0
6351                    int ii;
6352                    SUMA_VolumeObject *VO=NULL;
6353                    for (ii=0; ii<SUMAg_N_DOv; ++ii) {
6354                       if (SUMA_isVO(SUMAg_DOv[ii])) {
6355                          VO = (SUMA_VolumeObject *)(SUMAg_DOv[ii].OP);
6356                          if (VO->SelectedCutPlane >= 0) {
6357                             SUMA_LHv("Moving cut plane %d\n",
6358                                            VO->SelectedCutPlane);
6359                             if (!SUMA_MoveCutplane(VO, VO->SelectedCutPlane, -1.0)) {
6360                                SUMA_SLP_Err("Bad");
6361                             }
6362                          }
6363                  /* JB: only allow cutplane from 1st volume object,
6364                       otherwise remove 'break' */
6365                  break;
6366                       }
6367                    }
6368                    SUMA_postRedisplay(w, NULL, NULL);
6369                    #else
6370                    if ((ado = SUMA_SV_Focus_ADO(sv))) {
6371                       switch (ado->do_type) {
6372                          case VO_type: {
6373                             float incr = -1.0;
6374                             SUMA_VolumeObject *vo=(SUMA_VolumeObject *)ado;
6375                             SUMA_VOL_SAUX *VSaux = SUMA_ADO_VSaux(ado);
6376                             if (VSaux && VSaux->PR) {
6377                                if (SUMA_dset_gui_slice_from_tex_slice_d(vo->VE, 0,
6378                                               VSaux->PR->dAltSel+SUMA_VOL_SLC_EQ0,
6379                                               0, variant, NULL)   >=0 ){
6380                                   SUMA_set_slice(ado, variant, &incr,
6381                                                  "increment", 0);
6382                                }
6383                             }
6384                             SUMA_postRedisplay(w, NULL, NULL);
6385                             break; }
6386                          default:
6387                             SUMA_LH("Nothing here for types %s\n",
6388                                   ADO_TNAME(ado));
6389                             break;
6390                       }
6391                    }
6392                    #endif
6393                 } else if (pButton==7 || Bev.state & ControlMask) {
6394                    SUMA_ALL_DO *ado=NULL;
6395                    SUMA_X_SurfCont *SurfCont;
6396                    if (MASK_MANIP_MODE(sv)) {
6397                       ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
6398                       if (ado && ado->do_type == MASK_type) {
6399                          SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
6400                          float fv[3];
6401                          int irow=-1;
6402                          {
6403                             fv[0] = mdo->hdim[0]+(0.2*mdo->init_hdim[0]);
6404                             fv[1] = mdo->hdim[1]+(0.2*mdo->init_hdim[1]);
6405                             fv[2] = mdo->hdim[2]+(0.2*mdo->init_hdim[2]);
6406                             SUMA_MDO_New_Dim(mdo, fv);
6407                          }
6408                          if ((SurfCont=SUMA_ADO_Cont(ado))) {
6409                             irow = SUMA_ObjectID_Row(SurfCont->MaskTable,
6410                                                      ADO_ID(ado));
6411                             if (irow >= 0) {
6412                                SUMA_InitMasksTable_row(SurfCont,mdo, irow);
6413                             }
6414                          }
6415                          SUMA_NEW_MASKSTATE();
6416                          /* enough for now */
6417                          goto REDISP;
6418                       }
6419                    } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
6420                                ado->do_type == GRAPH_LINK_type &&
6421                                !strcmp(SUMA_ADO_variant(ado),"GMATRIX")) {
6422                       SUMA_OVERLAYS *Sover = NULL;
6423                       SUMA_LH("Switching overlay back one");
6424                       Sover = SUMA_ADO_CurColPlane(ado);
6425                       SUMA_SwitchColPlaneIntensity( ado, Sover,
6426                                                     SUMA_BACK_ONE_SUBBRICK, 1);
6427                       /* redisplay done in function above ... */
6428                       SUMA_RETURNe;
6429                    }
6430                 } else {
6431                    if (!SUMA_Z_Key(sv, "Z", "interactive")) {
6432                       SUMA_S_Err("Failed in key func.");
6433                    }
6434                 }
6435             }
6436             break;
6437 
6438          case Button2:
6439             if (Bev.state & ShiftMask) {
6440                /* setup initial zooming conditions */
6441                /*fprintf(SUMA_STDERR,"%s: Button 2 & Shift\n", FuncName); */
6442                sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
6443                sv->GVS[sv->StdView].zoomDelta = 0;
6444             } else {
6445                /*fprintf(stdout,"Button 2 down, plain jane\n");*/
6446                /* setup initial translation conditions */
6447                bevx = (float)Bev.x; bevy = (float)Bev.y;
6448                sv->GVS[sv->StdView].translateBeginX = bevx;;
6449                sv->GVS[sv->StdView].translateBeginY = bevy;
6450                sv->GVS[sv->StdView].translateDeltaX = 0.0;
6451                sv->GVS[sv->StdView].translateDeltaY = 0.0;
6452             }
6453             break;
6454 
6455          case Button3: {
6456                SUMA_LHv("Button 3 down plain jane, "
6457                             "viewer #%d : X=%f, Y = %f\n",
6458                             SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv),
6459                               (float)Bev.x, (float)Bev.y);
6460 
6461                /* Clear any pre-existing selection */
6462                if (!SUMA_Add_To_PickResult_List(sv, NULL, "TERSUM", NULL)) {
6463                   SUMA_S_Err("Failed to clear selections");
6464                   break;
6465                }
6466 
6467                /* Bev.state does work in the line below,
6468                   unlike Mev.state further down.
6469                   Using Kev.state anyway because it works in both cases */
6470                if ((Kev.state & ShiftMask) && (Kev.state & ControlMask)) {
6471                   SUMA_LH("Allowing callbacks");
6472                   SUMAg_CF->HoldClickCallbacks = 0;
6473                } else {
6474                   SUMA_LH("Holding back callbacks");
6475                   SUMAg_CF->HoldClickCallbacks = 1;
6476                }
6477 
6478                /* are we in ROI drawing mode ? */
6479                if (  SUMAg_CF->ROI_mode
6480                      && SUMA_SV_Focus_SO(sv) && !(Bev.state & ShiftMask)) {
6481                   /* ROI drawing mode */
6482                   ROI_mode = YUP;
6483                } else {
6484                   ROI_mode = NOPE;
6485 
6486                }
6487 
6488                if (!(Kev.state & ShiftMask) && (Kev.state & ControlMask)) {
6489                   SUMA_LH("Yoking intensity to node selection");
6490                   SUMAg_CF->YokeIntToNode = 1;
6491                } else {
6492                   SUMA_LH("Holding back yoking");
6493                   SUMAg_CF->YokeIntToNode = 0;
6494                }
6495 
6496                SUMA_LH("Get the selection line, bitte");
6497                if (!SUMA_GetSelectionLine (  sv, (int)Bev.x, (int)Bev.y,
6498                                              sv->Pick0, sv->Pick1, 0,
6499                                              NULL, NULL, NULL)) {
6500                   fprintf (SUMA_STDERR,
6501                            "Error %s: Failed in SUMA_GetSelectionLine.\n",
6502                            FuncName);
6503                   break;
6504                }
6505 
6506                if (DoubleClick && !ROI_mode){/*See if you are selecting masks */
6507                   SUMA_ALL_DO *mado=NULL, *ado=NULL;
6508                   SUMA_GRAPH_SAUX *GSaux=NULL;
6509                   /* you do not want to waist time doing double calculations if
6510                      the user clicks twice by mistake */
6511                   /* make sure no viewer, other than the one clicked in is in
6512                      momentum mode */
6513                   if (SUMAg_N_SVv > 1) {
6514                      ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
6515                                                       SUMAg_N_SVv, NULL);
6516                      if (ii >= 0) {
6517                         sprintf (s, "You cannot select or draw while viewers\n"
6518                                     "(like viewer %c) are in momentum mode.\n",
6519                                     ii+65);
6520                         SUMA_RegisterMessage (SUMAg_CF->MessageList,
6521                                               s, FuncName, SMT_Error,
6522                                               SMA_LogAndPopup);
6523                         SUMA_RETURNe;
6524                      }
6525                   }
6526 
6527                   /* Any hits for masks? */
6528                   hit = SUMA_ComputeLineMaskIntersect (sv, SUMAg_DOv, 0, &mado);
6529                   if (hit < 0) {
6530                     SUMA_S_Err("Failed in SUMA_ComputeLineMaskIntersect.");
6531                   } else if (hit > 0) {
6532                      SUMA_LH("Mask was double clicked");
6533                      if (!MASK_MANIP_MODE(sv)) {
6534                         SUMA_S_Note("Turning on mask manip mode");
6535                         if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,
6536                                                   (void *)(ADO_ID(mado)))) {
6537                            SUMA_S_Warn("Mask manip mode could not be set");
6538                         }
6539                      } else {
6540                         SUMA_S_Note("Turning off mask manip mode");
6541                         if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,NULL)) {
6542                            SUMA_S_Warn("Mask manip mode could not be set");
6543                         }
6544                      }
6545                      /* Not much else to do */
6546                      goto REDISP;
6547                   } else if (MASK_MANIP_MODE(sv)) { /* turn it off */
6548                      SUMA_S_Note("Turning off mask manip mode");
6549                      if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,NULL)) {
6550                         SUMA_S_Warn("Mask manip mode could not be set");
6551                      }
6552                      /* Not much else to do */
6553                      goto REDISP;
6554                   } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
6555                               ado->do_type == GRAPH_LINK_type &&
6556                              (GSaux = SUMA_ADO_GSaux(ado)) &&
6557                              GSaux->PR && GSaux->PR->datum_index == -1 &&
6558                              GSaux->PR->iAltSel[SUMA_ENODE_0] != -1 &&
6559                              GSaux->IgnoreSelection == 0) {
6560                            /* turn off node selection to allow all connections
6561                               to be visible. Execute only if we have a graph
6562                               in focus (in 3D drawing) and a point is selected
6563                               and selection is not being ignored*/
6564                         SUMA_LH("Ignoring selection for graph display");
6565                         GSaux->IgnoreSelection = 1;
6566                         SUMA_FlushPickBufferForDO(ado);
6567                         goto REDISP;
6568                   }
6569                   SUMA_LH("No mask hit, and no selection needs ignoring");
6570                }
6571 
6572               if (!DoubleClick) {
6573                   /* you do not want to waist time doing double calculations if
6574                      the user clicks twice by mistake */
6575                   /* make sure no viewer, other than the one clicked in is in
6576                      momentum mode */
6577                   if (SUMAg_N_SVv > 1) {
6578                      ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
6579                                                       SUMAg_N_SVv, NULL);
6580                      if (ii >= 0) {
6581                         sprintf (s, "You cannot select or draw while viewers\n"
6582                                     "(like viewer %c) are in momentum mode.\n",
6583                                     ii+65);
6584                         SUMA_RegisterMessage (SUMAg_CF->MessageList,
6585                                               s, FuncName, SMT_Error,
6586                                               SMA_LogAndPopup);
6587                         SUMA_RETURNe;
6588                      }
6589                   }
6590 
6591                  #if 0
6592                   /* Try this if you are having OpenGLStateReset problems at
6593                      node selection time. It is inefficient, but helps point
6594                      to the problem.
6595                      Look at recent updates to SE_Redisplay*All* for the more
6596                      appropriate fix */
6597                   SUMA_S_Note("Blunt fix:");
6598                   SUMA_OpenGLStateReset(SUMAg_DOv, SUMAg_N_DOv, sv);
6599                   SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6600                   #endif
6601 
6602                   /* perform the intersection calcluation and mark the surface */
6603                   SUMA_LHv("Finding hit: %d %d,\n"
6604                            "Pick0: %f %f %f, Pick1: %f %f %f\n",
6605                            (int)Bev.x, (int)Bev.y,
6606                            sv->Pick0[0], sv->Pick0[1], sv->Pick0[2],
6607                            sv->Pick1[0], sv->Pick1[1], sv->Pick1[2]);
6608 
6609 
6610                  if (1) {
6611                      hit = SUMA_ComputeLineDOsIntersect (sv, SUMAg_DOv, 0, NULL);
6612                      if ( (Kev.state & ShiftMask) &&
6613                          !(Kev.state & ControlMask) &&
6614                          !SUMA_ALTHELL && !SUMAg_CF->ROI_mode){
6615                          /* Show me the click buffer */
6616                         SUMA_MarkPickInBuffer4(sv, 1, NULL);
6617                      }
6618                      if (hit < 0) {
6619                         SUMA_S_Err("Failed in SUMA_ComputeLineDOsIntersect.");
6620                      }
6621                   }
6622 
6623                   if (1) {
6624                       SUMA_LH("Trying for volume intersections");
6625                       hit =  SUMA_ComputeLineVOslicesIntersect(sv, SUMAg_DOv,
6626                                                                0, NULL);
6627                       if (hit < 0) {
6628                          fprintf( SUMA_STDERR,
6629                             "Error %s: "
6630                             "Failed in SUMA_MarkLineVOslicesIntersect.\n",
6631                                   FuncName);
6632                       }
6633                   }
6634 
6635                   if (1) {
6636                       SUMA_LH("Trying for volume VR intersections");
6637                       hit =  SUMA_ComputeLineVOvrIntersect(sv, SUMAg_DOv,
6638                                                                0, NULL);
6639                       if (hit < 0) {
6640                          fprintf( SUMA_STDERR,
6641                             "Error %s: "
6642                             "Failed in SUMA_MarkLineVOvrIntersect.\n",
6643                                   FuncName);
6644                       }
6645                   }
6646                   #if 0
6647                   if (SUMA_ALTHELL ||
6648                       SUMA_VisibleSOs(sv, SUMAg_DOv, NULL, 0) == 0) {
6649                       SUMA_LH("Trying for cutplanes");
6650                       hit = SUMA_MarkLineCutplaneIntersect (sv, SUMAg_DOv, 0);
6651                       if (hit < 0) {
6652                          fprintf( SUMA_STDERR,
6653                             "Error %s: "
6654                             "Failed in SUMA_MarkLineCutplaneIntersect.\n",
6655                                   FuncName);
6656                       }
6657                   }
6658                   #endif
6659 
6660                   SUMA_LH("Checking on registered surfaces");
6661                   SwasHit = 0;
6662 
6663                   ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
6664 
6665                   if (ii == 0) { /* no surfaces, break */
6666                      SUMA_LH("No registrants");
6667 
6668                   } else {
6669                      /* have surfaces, find hits */
6670                      hit = SUMA_ComputeLineSurfaceIntersect (sv, SUMAg_DOv, 0, NULL);
6671 
6672                      if (hit < 0) {
6673                        SUMA_S_Err("Failed in SUMA_ComputeLineSurfaceIntersect.");
6674                      } else if (hit > 0) SwasHit = 1;
6675 
6676                   }
6677 
6678                }
6679 
6680 
6681                if (ROI_mode && (SwasHit || DoubleClick)) {
6682                   /* keep track of mouse motion in window */
6683                   if (!SUMA_CreateBrushStroke (sv)) {
6684                      SUMA_RegisterMessage (SUMAg_CF->MessageList,
6685                                            "Failed to create BrushStroke.",
6686                                            FuncName,
6687                                            SMT_Error, SMA_LogAndPopup);
6688                      SUMA_RETURNe;
6689 
6690                   }
6691 
6692                   SUMA_AddToBrushStroke (sv, (int)Bev.x, (int)Bev.y, sv->Pick0,
6693                      sv->Pick1, YUP);
6694                }
6695 
6696                ASSESS:
6697                SUMA_LH("Assessment %d", dlist_size(sv->SelAdo));
6698                SUMA_ALL_DO *ado = SUMA_SV_Focus_ADO(sv);
6699                if (!(SUMA_ADO_Saux(ado))){
6700                     SUMA_S_Err("NULL Saux!!!, don't let that happen");
6701                     SUMA_RETURNe;
6702                }
6703                if (dlist_size(sv->SelAdo)) {
6704                  if (!SUMA_Process_Selected_ADO(sv,SUMA_ALTHELL)) {
6705                      SUMA_S_Err("Failed to process selected ados");
6706                      goto OUT;
6707                   }
6708 
6709                   SUMA_LH("Calling redisplay");
6710                   /* redisplay */
6711                   sv->ResetGLStateVariables = YUP;
6712                   SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6713                }
6714                goto OUT;
6715 
6716                REDISP:
6717                SUMA_LH("Calling redisplay without assessment");
6718                sv->ResetGLStateVariables = YUP;
6719                SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6720                goto OUT;
6721 
6722                OUT:
6723                /* reset hold on xforms */
6724                SUMAg_CF->HoldClickCallbacks = 0;
6725             break; }
6726       } /* switch type of button Press */
6727       break;
6728 
6729    case ButtonRelease:
6730       SUMAg_CF->X->ButtonDown=0;
6731       M1time = 0;
6732       rButton = Bev.button;
6733       SUMA_LHv("In ButtonRelease Button %d %d @ x,y=%d,%d\n",
6734                    rButton, SUMAg_CF->X->ButtonDown, Bev.x, Bev.y);
6735       if (SUMAg_CF->Echo_KeyPress) {
6736          fprintf (SUMA_STDERR,"Button Release: %d (%d,%d,%d,%d,%d)\n"
6737                               , rButton, Button1, Button2, Button3, Button4,
6738                               Button5);
6739       }
6740 
6741       if (SUMAg_CF->SwapButtons_1_3 ||
6742           (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
6743          if (rButton == Button1) rButton = Button3;
6744          else if (rButton == Button3) rButton = Button1;
6745       }
6746 
6747       if (strstr(sv->State, "GMATRIX")==sv->State) {
6748          /* For graph in matrix representation swap buttons 1 and 2 */
6749          switch (rButton) {
6750             case Button1:
6751                rButton = Button2;
6752                break;
6753             case Button2:
6754                rButton = Button1;
6755                break;
6756          }
6757       }
6758 
6759 
6760       switch (rButton) { /* switch type of button Press */
6761          case Button3:
6762             if (LocalHead)
6763                fprintf(SUMA_STDERR,"%s: In ButtonRelease3\n", FuncName);
6764 
6765             if (SUMAg_CF->ROI_mode) {
6766                SUMA_DRAWN_ROI *DrawnROI = NULL;
6767                SUMA_BRUSH_STROKE_ACTION BsA=SUMA_BSA_Undefined;
6768 
6769                if (sv->BS) {
6770                   /* Process the brush stroke*/
6771                   if (DoubleClick) BsA = SUMA_BSA_JoinEnds;
6772                   else BsA = SUMA_BSA_AppendStrokeOrFill;
6773                   if (!(DrawnROI = SUMA_ProcessBrushStroke (sv, BsA))) {
6774                      if (LocalHead)
6775                         fprintf (SUMA_STDERR,
6776                                  "%s: NULL DrawnROI returned.\n", FuncName);
6777                      SUMA_ClearBrushStroke (sv);
6778                      break;
6779                   }
6780 
6781                   /* Showme the DrawnROI */
6782                   if (LocalHead) SUMA_ShowDrawnROI (DrawnROI, NULL, NOPE);
6783 
6784                   /* do smething with the BrushStroke, then wipe it clean,
6785                      OK to show even if empty*/
6786                   if (LocalHead) SUMA_ShowBrushStroke (sv, NULL);
6787 
6788                   /* SUMA_DrawBrushStroke (sv, YUP); */
6789                   SUMA_ClearBrushStroke (sv);
6790 
6791                   /* redisplay all others */
6792                   if (!list) list = SUMA_CreateList ();
6793                   SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list,
6794                            SE_RedisplayNow_AllOtherVisible, SES_SumaWidget, sv);
6795                   SUMA_Engine (&list);
6796 
6797                   /* redisplay .
6798                      DO NOT REDISPLAY WITH SE_Redisplay_AllVisible or
6799                      you will have GL state synchronization problems */
6800                   sv->ResetGLStateVariables = YUP;
6801                   SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6802 
6803                }/* if sv->BS */
6804             } /* if SUMAg_CF->ROImode */
6805 
6806             if (sv->Focus_DO_ID > 0){/* Get surface controller page in sync */
6807                if (!SUMA_IS_CONTPAGE_ON_TOP(SUMAg_CF->X->AllMaskCont)) {
6808                   /* Switch only if 'sticky' mask controller page
6809                      is not on top */
6810                   SUMA_ALL_DO *ado = SUMA_SV_Focus_ADO(sv);
6811                   if (ado) {
6812                      SUMA_LHv("Will call Init for %s if %d\n",
6813                         SUMA_ADO_Label(ado),
6814                         SUMA_isADO_Cont_Realized(ado));
6815                      if (SUMA_isADO_Cont_Realized(ado))
6816                         SUMA_Init_SurfCont_SurfParam(ado);
6817                   }
6818                } else {
6819                   if (!SUMA_InitMasksTable(SUMAg_CF->X->AllMaskCont)) {
6820                      SUMA_S_Err("Failed to initialize mask table");
6821                   }
6822                }
6823             }
6824          break;
6825          case Button1:
6826             SUMA_LH("In Button 1 release\n");
6827             if (sv->GVS[sv->StdView].vLHpry0[0] !=
6828                                           sv->GVS[sv->StdView].vLHpry[0] ||
6829                 sv->GVS[sv->StdView].vLHpry0[1] !=
6830                                           sv->GVS[sv->StdView].vLHpry[1] ||
6831                 sv->GVS[sv->StdView].vLHpry0[2] !=
6832                                           sv->GVS[sv->StdView].vLHpry[2] ){
6833                /* update the normals just now, this would not be needed if
6834                  SUMA_ApplyPrying has set recompute_normals = 1*/
6835                SUMA_RecomputeNormsPrying(sv);
6836                SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6837             }
6838             sv->GVS[sv->StdView].vLHpry0[0] = sv->GVS[sv->StdView].vLHpry[0];
6839             sv->GVS[sv->StdView].vLHpry0[1] = sv->GVS[sv->StdView].vLHpry[1];
6840             sv->GVS[sv->StdView].vLHpry0[2] = sv->GVS[sv->StdView].vLHpry[2];
6841          break;
6842       } /* switch type of button Press */
6843       break;
6844 
6845    case MotionNotify:
6846       if (LocalHead) {
6847           fprintf(stdout,"In MotionNotify\n");
6848               if (Mev.state & Button1MotionMask) fprintf(stdout,"   B1 mot\n");
6849          else if (Mev.state & Button2MotionMask) fprintf(stdout,"   B2 mot\n");
6850          else if (Mev.state & Button3MotionMask) fprintf(stdout,"   B3 mot\n");
6851          else if (Mev.state & Button4MotionMask) fprintf(stdout,"   B4 mot\n");
6852          else if (Mev.state & Button5MotionMask) fprintf(stdout,"   B5 mot\n");
6853          else fprintf(stdout,"   Something mot, button %d\n", Bev.button);
6854       }
6855       if (SUMAg_CF->Echo_KeyPress) {
6856          if (Mev.state & Button1MotionMask)
6857             fprintf(SUMA_STDERR,"   B1 mot\n");
6858          else if (Mev.state & Button2MotionMask)
6859             fprintf(SUMA_STDERR,"   B2 mot\n");
6860          else if (Mev.state & Button3MotionMask)
6861             fprintf(SUMA_STDERR,"   B3 mot\n");
6862          else if (Mev.state & Button4MotionMask)
6863             fprintf(SUMA_STDERR,"   B4 mot\n");
6864          else if (Mev.state & Button5MotionMask)
6865             fprintf(SUMA_STDERR,"   B5 mot\n");
6866          else if (Mev.state) fprintf(SUMA_STDERR,
6867                               "   Something mot, button %d\n", Bev.button);
6868       }
6869 
6870       if (  SUMAg_CF->SwapButtons_1_3 ||
6871             (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
6872         if (((Mev.state & Button3MotionMask) && (Mev.state & Button2MotionMask))
6873          || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
6874             mButton = SUMA_Button_12_Motion;
6875          } else if(Mev.state & Button3MotionMask) {
6876             mButton = SUMA_Button_1_Motion;
6877          }else if(Mev.state & Button2MotionMask) {
6878             mButton = SUMA_Button_2_Motion;
6879          }else if(Mev.state & Button1MotionMask) {
6880             mButton = SUMA_Button_3_Motion;
6881          }else {
6882             break;
6883          }
6884       } else {
6885          if (((Mev.state & Button1MotionMask) && (Mev.state & Button2MotionMask))
6886           || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
6887             mButton = SUMA_Button_12_Motion;
6888          } else if(Mev.state & Button1MotionMask) {
6889             mButton = SUMA_Button_1_Motion;
6890          }else if(Mev.state & Button2MotionMask) {
6891             mButton = SUMA_Button_2_Motion;
6892          } else if(Mev.state & Button3MotionMask) {
6893             mButton = SUMA_Button_3_Motion;
6894          }else {
6895             break;
6896          }
6897       }
6898 
6899       if (strstr(sv->State, "GMATRIX")==sv->State) {
6900          /* For graph in matrix representation swap buttons 1 and 2 */
6901          SUMA_LH("In graph matrix, swapping 1/2 motion");
6902          switch (mButton) {
6903             case SUMA_Button_1_Motion:
6904                mButton = SUMA_Button_2_Motion;
6905                break;
6906             case SUMA_Button_2_Motion:
6907                mButton = SUMA_Button_1_Motion;
6908                break;
6909          }
6910       }
6911 
6912       switch (mButton) {
6913          case SUMA_Button_12_Motion:
6914          case SUMA_Button_2_Shift_Motion:
6915             /*fprintf(SUMA_STDERR,"%s: In motion, Butt1 & Butt2\n", FuncName);*/
6916             sv->GVS[sv->StdView].zoomDelta = 1.0 +
6917                                              (float)((int)Mev.y -
6918                                  sv->GVS[sv->StdView].zoomBegin)/MOUSE_ZOOM_FACT;
6919             if (sv->GVS[sv->StdView].zoomDelta > 2.0)
6920                sv->GVS[sv->StdView].zoomDelta = 2.0;
6921             else if (sv->GVS[sv->StdView].zoomDelta < 0.5)
6922                sv->GVS[sv->StdView].zoomDelta = 0.5;
6923             sv->FOV[sv->iState] /= sv->GVS[sv->StdView].zoomDelta;
6924             if (sv->FOV[sv->iState] < FOV_MIN) sv->FOV[sv->iState] = FOV_MIN;
6925             else if (sv->FOV[sv->iState] > FOV_MAX)
6926                sv->FOV[sv->iState] = FOV_MAX;
6927             sv->GVS[sv->StdView].zoomBegin = (float)(int)Mev.y;
6928             /*fprintf(stdout, "FOV zoom Delta = %f=n",
6929                               sv->GVS[sv->StdView].zoomDelta);*/
6930             /* Now update the zoom compensation variable */
6931             if (sv->ZoomCompensate) {
6932                sv->ZoomCompensate = sqrt(sv->FOV[sv->iState] /
6933                                     SUMA_sv_auto_fov(sv));
6934                      /* slow down compensation, with sqrt*/
6935                if (sv->ZoomCompensate > 1)
6936                   sv->ZoomCompensate = 1.0;
6937                         /* no need to compensate at low zooms */
6938                else if (sv->ZoomCompensate < 0.05)
6939                   sv->ZoomCompensate = 0.05; /* no need to go lower */
6940             }
6941             ii = SUMA_WhichSV (sv, SUMAg_SVv, SUMAg_N_SVv);
6942             SUMA_postRedisplay(w, clientData, callData);
6943             break;
6944 
6945          case SUMA_Button_1_Motion:
6946             /* fprintf(SUMA_STDERR,"%s: In motion, Butt1 \n", FuncName); */
6947             mevx = (float)Mev.x;
6948             mevy = (float)Mev.y;
6949             wwid = (float)sv->X->aWIDTH;
6950             whei = (float)sv->X->aHEIGHT;
6951             /* spinning mode */
6952             if (sv->ZoomCompensate) {
6953                zc_fac = sv->ZoomCompensate;
6954             }else {
6955                zc_fac = 1.0;
6956             }
6957             sv->GVS[sv->StdView].spinDeltaX =
6958                (mevx - sv->GVS[sv->StdView].spinBeginX);
6959             sv->GVS[sv->StdView].spinDeltaY =
6960                (mevy - sv->GVS[sv->StdView].spinBeginY);
6961             if (M1time) {
6962                M1delta = Mev.time - M1time;
6963                mvdeltax = Mev.x - mvxlast;
6964                mvdeltay = Mev.y - mvylast;
6965             } else {
6966                M1delta = 0;
6967                mvdeltax = 0;
6968                mvdeltay = 0;
6969             }
6970             M1time = Mev.time;
6971             mvxlast= Mev.x;
6972             mvylast= Mev.y;
6973 
6974             /* compute move rate in pixels per milliseconds,
6975             You could use this to add a gain on the amount of rotation,
6976             but before you could use those factors, you'll need to scale
6977             the results to something appropriate */
6978             mvx_fac = ((SUMA_ABS((float)mvdeltax)/(M1delta+0.01)));
6979             mvy_fac = ((SUMA_ABS((float)mvdeltay)/(M1delta+0.01)));
6980 
6981             #if 0
6982             fprintf(stdout,"\n"
6983                            "spinBeginX %f \n"
6984                            "spinBeginY %f \n"
6985                            "spinDeltaX %f \n"
6986                            "spinDeltaY %f \n"
6987                            "X->aWIDTH %d  \n"
6988                            "X->aHEIGHT %d\n"
6989                            "ZoomCompensate %f\n"
6990                            "mv[xy]last [%d %d]\n"
6991                            "mvdelta[xy]last [%d %d]\n"
6992                            "MoveRatePixelsPerms [%f %f]\n"
6993                            ,
6994                         sv->GVS[sv->StdView].spinBeginX,
6995                         sv->GVS[sv->StdView].spinBeginY,
6996                         sv->GVS[sv->StdView].spinDeltaX,
6997                         sv->GVS[sv->StdView].spinDeltaY,
6998                         sv->X->aWIDTH, sv->X->aHEIGHT, sv->ZoomCompensate,
6999                         mvxlast, mvylast,
7000                         mvdeltax, mvdeltay,
7001                         mvx_fac, mvy_fac
7002                         );
7003             #else
7004             /* fprintf(stdout,"%f %f; ", mvx_fac, mvy_fac); */
7005             #endif
7006             /* do not use movement rate before you scale it properly */
7007             mvx_fac = mvy_fac = 1.0;
7008             if (sv->GVS[sv->StdView].spinDeltaX ||
7009                 sv->GVS[sv->StdView].spinDeltaY){
7010                if (SUMA_Shft_Event(SUMAg_CF->lev)) {
7011                   float a[3], cQ[4];
7012                   /* rotate about Z axis   */
7013                   a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
7014                   axis_to_quat(a,
7015                               -SUMA_SIGN(mvdeltax)*sqrt(SUMA_ABS(mvdeltax))*
7016                                  sv->ArrowRotationAngle,
7017                               cQ);
7018                   /*add rotation */
7019                   add_quats ( cQ,
7020                               sv->GVS[sv->StdView].currentQuat,
7021                               sv->GVS[sv->StdView].currentQuat);
7022                } else if (SUMA_Cont_Event(SUMAg_CF->lev)) {
7023                   float val[3];
7024                   val[0] = sv->GVS[sv->StdView].spinDeltaX;
7025                   val[1] = sv->GVS[sv->StdView].spinDeltaY;
7026                   val[2] = 0.0;
7027                   SUMA_ApplyPrying(sv, val, "mouse", 0);
7028                                        /* update normals at release */
7029                } else if (SUMA_Plain_Event(SUMAg_CF->lev)){
7030                   trackball(  sv->GVS[sv->StdView].deltaQuat,
7031                               (2*sv->GVS[sv->StdView].spinBeginX - wwid) /
7032                               wwid*zc_fac*mvx_fac,
7033                               (whei - 2*sv->GVS[sv->StdView].spinBeginY) /
7034                               whei*zc_fac*mvy_fac,
7035                               (2*mevx - wwid)/wwid*zc_fac*mvx_fac,
7036                               (whei - 2*mevy)/whei*zc_fac*mvy_fac);
7037                                     /* comput the increment Quat */
7038                   sv->GVS[sv->StdView].spinBeginX = mevx;
7039                   sv->GVS[sv->StdView].spinBeginY = mevy;
7040                   add_quats ( sv->GVS[sv->StdView].deltaQuat,
7041                               sv->GVS[sv->StdView].currentQuat,
7042                               sv->GVS[sv->StdView].currentQuat);
7043                } else {
7044                   SUMA_LH("Not ready for event flavor");
7045                   break;
7046                }
7047                ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
7048                if (ii < 0) {
7049                   fprintf (SUMA_STDERR,
7050                            "Error %s: Failed to find index of sv.\n", FuncName);
7051                   break;
7052                }
7053                if (!SUMAg_CF->ViewLocked[ii]) { /* No locking,
7054                                                 just redisplay current viewer */
7055                   SUMA_postRedisplay(w, clientData, callData);
7056                } else { /* locking, update and redisplay those locked */
7057                   DList *list = NULL;
7058                   SUMA_EngineData *ED = NULL;
7059                   SUMA_STANDARD_VIEWS ed_sv, ed_svi;
7060                   /* redisplay current viewer immediately */
7061                   list = SUMA_CreateList ();
7062                   ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
7063                   SUMA_RegisterEngineListCommand (list, ED,
7064                                                    SEF_Empty, NULL,
7065                                                    SES_Suma, (void *)sv, NOPE,
7066                                                    SEI_Head, NULL);
7067                   ed_sv = SUMA_BestStandardView(sv, SUMAg_DOv, SUMAg_N_DOv);
7068                   for (it=0; it < SUMAg_N_SVv; ++it) {
7069                      svi = &SUMAg_SVv[it];
7070                      ed_svi = SUMA_BestStandardView(svi, SUMAg_DOv, SUMAg_N_DOv);
7071                      if (  it != ii &&
7072                            SUMAg_CF->ViewLocked[it] && ed_svi == ed_sv) {
7073                         /* copy quaternions */
7074                         svi->GVS[svi->StdView].spinBeginX =
7075                            sv->GVS[sv->StdView].spinBeginX;
7076                         svi->GVS[svi->StdView].spinBeginY =
7077                            sv->GVS[sv->StdView].spinBeginY;
7078                         SUMA_COPY_VEC( sv->GVS[sv->StdView].deltaQuat,
7079                                        svi->GVS[svi->StdView].deltaQuat,
7080                                        4, float, float);
7081                         SUMA_COPY_VEC( sv->GVS[sv->StdView].currentQuat,
7082                                        svi->GVS[svi->StdView].currentQuat,
7083                                        4, float, float);
7084 
7085                         /* add a redisplay now */
7086                         ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
7087                         SUMA_RegisterEngineListCommand ( list, ED,
7088                                                 SEF_Empty, NULL,
7089                                                 SES_Suma, (void *)svi, NOPE,
7090                                                 SEI_Head, NULL);
7091                      }
7092                   }
7093                   if (!SUMA_Engine (&list)) {
7094                      fprintf (SUMA_STDERR,
7095                               "Error %s: Failed calling SUMA_Engine.\n",
7096                               FuncName);
7097                      break;
7098                   }
7099                }
7100             }
7101 
7102             break;
7103 
7104          case SUMA_Button_2_Motion:
7105             mevx = (float)Mev.x; mevy = (float)Mev.y;
7106             SUMA_LHv("In motion, Butt2 %f, %f\n", mevx , mevy);
7107             if (sv->ZoomCompensate) {
7108                zc_fac = sv->ZoomCompensate;
7109             }else {
7110                zc_fac = 1.0;
7111             }
7112             if ((Kev.state & ShiftMask)){
7113 
7114             } else {
7115                sv->GVS[sv->StdView].translateDeltaX =
7116                   (mevx - sv->GVS[sv->StdView].translateBeginX) /
7117                   (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
7118                sv->GVS[sv->StdView].translateDeltaY =
7119                   -(mevy - sv->GVS[sv->StdView].translateBeginY) /
7120                    (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
7121 
7122                if (  sv->GVS[sv->StdView].translateDeltaX ||
7123                      sv->GVS[sv->StdView].translateDeltaY){
7124                   sv->GVS[sv->StdView].translateVec[0] +=
7125                      (GLfloat)sv->GVS[sv->StdView].translateDeltaX * zc_fac;
7126                   sv->GVS[sv->StdView].translateVec[1] +=
7127                      (GLfloat)sv->GVS[sv->StdView].translateDeltaY * zc_fac;
7128                   sv->GVS[sv->StdView].translateBeginX = mevx;
7129                   sv->GVS[sv->StdView].translateBeginY = mevy;
7130                   SUMA_postRedisplay(w, clientData, callData);
7131                }
7132             }
7133             break;
7134 
7135          case SUMA_Button_3_Motion: {
7136             SUMA_ALL_DO *lado=NULL;
7137             SUMA_DO_Types lado_type=NOT_SET_type;
7138 
7139             if (sv->LastSel_ado_idcode_str) {
7140                lado = SUMA_whichADOg(sv->LastSel_ado_idcode_str);
7141                if (lado) lado_type = lado->do_type;
7142             }
7143 
7144             SUMA_LH("In button 3 motion, lado=%s", ADO_LABEL(lado));
7145 
7146             /* Clear any pre-existing selection */
7147             if (!SUMA_Add_To_PickResult_List(sv, NULL, "TERSUM", NULL)) {
7148                SUMA_S_Err("Failed to clear selections");
7149                break;
7150             }
7151 
7152             if (SUMAg_CF->ROI_mode && SUMA_SV_Focus_SO(sv) && sv->BS) {
7153                /* ROI drawing mode */
7154                ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
7155                if (ii == 0) { /* no surfaces, break */
7156                   break;
7157                }
7158 
7159 
7160                if (!SUMA_GetSelectionLine(sv,
7161                      (int)Mev.x, (int)Mev.y, sv->Pick0, sv->Pick1,
7162                      0, NULL, NULL, NULL)) {
7163                   fprintf (SUMA_STDERR, "Error %s: Failed in "
7164                                        "SUMA_GetSelectionLine.\n", FuncName);
7165                   break;
7166                }
7167 
7168                if (!SUMA_AddToBrushStroke (sv, (int)Mev.x, (int)Mev.y,
7169                      sv->Pick0, sv->Pick1, YUP)) {
7170                   SUMA_RegisterMessage (SUMAg_CF->MessageList,
7171                                         "Failed to add to BrushStroke.",
7172                                         FuncName,
7173                                         SMT_Error, SMA_LogAndPopup);
7174                   break;
7175                }
7176             } else {
7177                /* Mev.state does not work in the line below */
7178                if ((Kev.state & ShiftMask) && (Kev.state & ControlMask) ) {
7179                   SUMA_LH("Allowing callbacks");
7180                   SUMAg_CF->HoldClickCallbacks = 0;
7181                } else {
7182                   SUMA_LH("Holding back callbacks");
7183                   SUMAg_CF->HoldClickCallbacks = 1;
7184                }
7185 
7186                if (SUMAg_N_SVv > 1) {
7187                   ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
7188                                                    SUMAg_N_SVv, NULL);
7189                   if (ii >= 0) {
7190                      sprintf (s, "You cannot select or draw while viewers\n"
7191                                  "(like viewer %c) are in momentum mode.\n",
7192                                  ii+65);
7193                      SUMA_RegisterMessage (SUMAg_CF->MessageList,
7194                                            s, FuncName, SMT_Error,
7195                                            SMA_LogAndPopup);
7196                      SUMA_RETURNe;
7197                   }
7198                }
7199 
7200                if (!(Kev.state & ShiftMask) && (Kev.state & ControlMask) ) {
7201                   SUMA_LH("Yoking intensity to node selection");
7202                   SUMAg_CF->YokeIntToNode = 1;
7203                } else {
7204                   SUMA_LH("Holding back callbacks");
7205                   SUMAg_CF->YokeIntToNode = 0;
7206                }
7207 
7208                   #if 0
7209                   /* Try this if you are having OpenGLStateReset problems at
7210                      node selection time. It is inefficient, but helps point
7211                      to the problem.
7212                      Look at recent updates to SE_Redisplay*All* for the more
7213                      appropriate fix */
7214                   SUMA_S_Note("Blunt fix:");
7215                   SUMA_OpenGLStateReset(SUMAg_DOv, SUMAg_N_DOv, sv);
7216                   SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
7217                   #endif
7218 
7219                if (!SUMA_GetSelectionLine (  sv, (int)Mev.x, (int)Mev.y,
7220                                              sv->Pick0, sv->Pick1, 0,
7221                                              NULL, NULL, NULL)) {
7222                   fprintf (SUMA_STDERR,
7223                            "Error %s: Failed in SUMA_GetSelectionLine.\n",
7224                            FuncName);
7225                   break;
7226                }
7227 
7228                   if (lado_type == NOT_SET_type ||
7229                       lado_type == MASK_type) {
7230                if (!MASK_MANIP_MODE(sv)) { /* You don't want these if
7231                                               you're moving them! */
7232                   SUMA_LH("Mask picking");
7233                   hit = SUMA_ComputeLineMaskIntersect (sv, SUMAg_DOv, 0, NULL);
7234                   if (hit < 0) {
7235                      SUMA_S_Err("Failed in SUMA_ComputeLineMaskIntersect.");
7236                   }
7237                }
7238                   }
7239 
7240                   if (lado_type == NOT_SET_type ||
7241                       lado_type == TRACT_type || lado_type == GRAPH_LINK_type) {
7242                if (1) {
7243                   SUMA_LH("Tract picking");
7244                   hit = SUMA_ComputeLineDOsIntersect (sv, SUMAg_DOv, 0, NULL);
7245                   if (hit < 0) {
7246                      SUMA_S_Err("Failed in SUMA_ComputeLineDOsIntersect.");
7247                   }
7248                }
7249                   }
7250 
7251                   if (lado_type == NOT_SET_type ||
7252                       lado_type == VO_type) {
7253                if (1) {
7254                    SUMA_LH("Trying for volume intersections");
7255                    hit =  SUMA_ComputeLineVOslicesIntersect(sv, SUMAg_DOv,
7256                                                             0, NULL);
7257                    if (hit < 0) {
7258                       fprintf( SUMA_STDERR,
7259                          "Error %s: "
7260                          "Failed in SUMA_MarkLineVOslicesIntersect.\n",
7261                                FuncName);
7262                    }
7263                }
7264                if (1) {
7265                    SUMA_LH("Trying for volume rendering intersections");
7266                    hit =  SUMA_ComputeLineVOvrIntersect(sv, SUMAg_DOv,
7267                                                             0, NULL);
7268                    if (hit < 0) {
7269                       fprintf( SUMA_STDERR,
7270                          "Error %s: "
7271                          "Failed in SUMA_MarkLineVOvrIntersect.\n",
7272                                FuncName);
7273                    }
7274                }
7275                   }
7276 
7277                   if ((lado_type == NOT_SET_type ||
7278                        lado_type == SO_type)) {
7279                ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
7280                if (ii > 0) { /* some surfaces, try */
7281                   /* perform the intersection calcluation and mark the surface */
7282                   hit = SUMA_ComputeLineSurfaceIntersect (sv, SUMAg_DOv,
7283                                                           1, NULL);
7284                   if (hit < 0) {
7285                      fprintf( SUMA_STDERR,
7286                               "Error %s: "
7287                               "Failed in SUMA_ComputeLineSurfaceIntersect.\n",
7288                               FuncName);
7289                      break;
7290                   }
7291                }
7292                   }
7293 
7294                ASSESS_MOTION:
7295                SUMA_LH("Assessment");
7296                if (dlist_size(sv->SelAdo)) {
7297                   if (!SUMA_Process_Selected_ADO(sv, SUMA_ALTHELL)) {
7298                      SUMA_S_Err("Failed to process selected ado");
7299                      SUMA_RETURNe;
7300                   }
7301 
7302                   /* redisplay */
7303                   sv->ResetGLStateVariables = YUP;
7304                   SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
7305                }
7306                OUT_MOTION:
7307                /* reset hold on xforms */
7308                SUMAg_CF->HoldClickCallbacks = 0;
7309             }
7310 
7311             break; }
7312       }
7313 
7314 
7315       break;
7316   }
7317 
7318   /* switch event type */
7319 
7320    SUMA_RETURNe;
7321 }
7322 
7323 /*!
7324    SUMA_momentum(XtPointer clientData, XtIntervalId *id);
7325 
7326    client data contains the widget responsible for the call to SUMA_momentum
7327 */
SUMA_momentum(XtPointer clientData,XtIntervalId * id)7328 void SUMA_momentum(XtPointer clientData, XtIntervalId *id)
7329 {
7330    static char FuncName[]={"SUMA_momentum"};
7331    static int ReDisp;
7332    Widget w = NULL;
7333    int isv;
7334    SUMA_SurfaceViewer *sv;
7335 
7336    SUMA_ENTRY;
7337 
7338    // fprintf(stderr, "%s\n", FuncName);
7339 
7340    /* the widget is passed as client data */
7341    w = (Widget)clientData;
7342 
7343    /* find out which Surface viewer the widget belongs to */
7344    SUMA_ANY_WIDGET2SV((Widget)clientData, sv, isv);
7345    if (isv < 0) {
7346       SUMA_S_Err("Failed in macro SUMA_ANY_WIDGET2SV.");
7347       SUMA_RETURNe;
7348    }
7349 
7350 
7351    ReDisp = 0;
7352    if ( ((sv->GVS[sv->StdView].spinDeltaX*sv->GVS[sv->StdView].spinDeltaX) >
7353                                           sv->GVS[sv->StdView].MinIdleDelta ) ||
7354         ((sv->GVS[sv->StdView].spinDeltaY*sv->GVS[sv->StdView].spinDeltaY) >
7355                                           sv->GVS[sv->StdView].MinIdleDelta ) )
7356       { /* rotate if SUMA_momentum is enabled and spinDeltaX or spinDeltaY
7357            are larger than the minimum set */
7358          /*fprintf(stdout,"SUMA_momentum:  spinDeltaX %f spinDeltaY %f\n",
7359                   sv->GVS[sv->StdView].spinDeltaX,
7360                   sv->GVS[sv->StdView].spinDeltaY);*/
7361          add_quats ( sv->GVS[sv->StdView].deltaQuat,
7362                      sv->GVS[sv->StdView].currentQuat,
7363                      sv->GVS[sv->StdView].currentQuat);
7364          ReDisp = 1;
7365       }
7366    if ( ((sv->GVS[sv->StdView].translateDeltaX*
7367           sv->GVS[sv->StdView].translateDeltaX) >
7368                                           sv->GVS[sv->StdView].MinIdleDelta ) ||
7369         ((sv->GVS[sv->StdView].translateDeltaY*
7370           sv->GVS[sv->StdView].translateDeltaY) >
7371                                           sv->GVS[sv->StdView].MinIdleDelta ) )
7372       { /* translate */
7373          sv->GVS[sv->StdView].translateVec[0] +=
7374                         (GLfloat)sv->GVS[sv->StdView].translateDeltaX;
7375          sv->GVS[sv->StdView].translateVec[1] +=
7376                         (GLfloat)sv->GVS[sv->StdView].translateDeltaY;
7377          ReDisp = 1;
7378       }
7379    if (ReDisp) {
7380       /*fprintf(stdout,"Momentum Redisplay\n");*/
7381       SUMA_postRedisplay(w, NULL, NULL);
7382    }
7383     sv->X->MOMENTUMID = XtAppAddTimeOut(SUMAg_CF->X->App, 1,
7384                                           SUMA_momentum, (XtPointer) w);
7385 
7386   SUMA_RETURNe;
7387 }
7388 
7389 /*
7390    Show the buffer used to pick displayable objects (DOs) with color id
7391    The function adds a cross hair (4 white pixels) around the selection
7392    point and displays the image in AFNI's viewer (InViewer == 1) and/or
7393    save the image to an image file if OnDisk is not NULL.
7394    Set OnDisk to something like PickBuff.ppm so that you get the exact
7395    pixels rendered in the output. Consecutive images are numbered with
7396    a time stamp.
7397 
7398    Note that the 4th chanel (alpha) is not shown or written to disk at
7399    the moment.
7400 */
SUMA_MarkPickInBuffer4(SUMA_SurfaceViewer * sv,int InViewer,char * OnDisk)7401 SUMA_Boolean SUMA_MarkPickInBuffer4(SUMA_SurfaceViewer *sv, int InViewer,
7402                                     char *OnDisk)
7403 {
7404    static char FuncName[]={"SUMA_MarkPickInBuffer4"};
7405    int n4, n3, n, p0[5],p1[5],p2[5],p3[5], i;
7406    SUMA_Boolean LocalHead = NOPE;
7407 
7408    SUMA_ENTRY;
7409 
7410    // fprintf(stderr, "%s\n", FuncName);
7411   if (!InViewer && !OnDisk) {
7412       SUMA_S_Err("Nothing to do here");
7413       SUMA_RETURN(NOPE);
7414    }
7415    if (!sv->pickrenpix4) {
7416       SUMA_S_Err("Empty buffer array");
7417       SUMA_RETURN(NOPE);
7418    }
7419    p0[0] = -1; /* to hold index of pixel being marked */
7420    p1[0] = -1;
7421    p2[0] = -1;
7422    p3[0] = -1;
7423 
7424    n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0];
7425    n4 = 4*n4;
7426    SUMA_LHv("User pixel selection from whole buffer:"
7427                   " at %d %d is: %d %d %d %d\n",
7428                   sv->PickPix[0], sv->PickPix[1],
7429                   sv->pickrenpix4[n4] , sv->pickrenpix4[n4+1],
7430                   sv->pickrenpix4[n4+2] , sv->pickrenpix4[n4+3]);
7431    if (sv->PickPix[1] > 0) {
7432       n4 = (sv->PickPix[1]-1)*sv->X->aWIDTH + sv->PickPix[0];
7433       n4 = 4*n4;
7434       p0[0] = n4; p0[1] = sv->pickrenpix4[n4  ]; p0[2] = sv->pickrenpix4[n4+1];
7435                   p0[3] = sv->pickrenpix4[n4+2]; p0[4] = sv->pickrenpix4[n4+3];
7436       sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7437          sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7438    }
7439    if (sv->PickPix[0] > 0) {
7440       n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0]-1;
7441       n4 = 4*n4;
7442       p1[0] = n4; p1[1] = sv->pickrenpix4[n4  ]; p1[2] = sv->pickrenpix4[n4+1];
7443                   p1[3] = sv->pickrenpix4[n4+2]; p1[4] = sv->pickrenpix4[n4+3];
7444       sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7445          sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7446    }
7447    if (sv->PickPix[1] < (sv->X->aHEIGHT-1)) {
7448       n4 = (sv->PickPix[1]+1)*sv->X->aWIDTH + sv->PickPix[0];
7449       n4 = 4*n4;
7450       p2[0] = n4; p2[1] = sv->pickrenpix4[n4  ]; p2[2] = sv->pickrenpix4[n4+1];
7451                   p2[3] = sv->pickrenpix4[n4+2]; p2[4] = sv->pickrenpix4[n4+3];
7452       sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7453          sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7454    }
7455    if (sv->PickPix[0] < (sv->X->aWIDTH-1)) {
7456       n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0]+1;
7457       n4 = 4*n4;
7458       p3[0] = n4; p3[1] = sv->pickrenpix4[n4  ]; p3[2] = sv->pickrenpix4[n4+1];
7459                   p3[3] = sv->pickrenpix4[n4+2]; p3[4] = sv->pickrenpix4[n4+3];
7460       sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7461          sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7462    }
7463    if (InViewer) { /* show me the money in the interactive viewer */
7464       GLubyte *pp3 = (GLubyte *)SUMA_calloc(sv->X->aWIDTH*sv->X->aHEIGHT*3,
7465                                             sizeof(GLubyte));
7466       for (n3=0,n=0; n<sv->X->aWIDTH*sv->X->aHEIGHT; ++n) {
7467          n4=4*n;
7468          pp3[n3++]= sv->pickrenpix4[n4++];
7469          pp3[n3++]= sv->pickrenpix4[n4++];
7470          pp3[n3++]= sv->pickrenpix4[n4++]; n4++;
7471       }
7472       ISQ_snapsave(sv->X->aWIDTH, -sv->X->aHEIGHT,
7473                     (unsigned char *)pp3, sv->X->GLXAREA );
7474       SUMA_ifree(pp3);
7475    }
7476    if (OnDisk) {
7477       if (!SUMA_PixelsToDisk(sv, sv->X->aWIDTH, -sv->X->aHEIGHT,
7478                           (GLvoid *)sv->pickrenpix4, 4, 1, OnDisk, 1, 0)) {
7479          SUMA_S_Err("Failed to write pix to disk");
7480       }
7481    }
7482    /* now put things back where you found them */
7483    if (p0[0] >= 0) {
7484       for (i=0; i<4; ++i) sv->pickrenpix4[p0[0]+i] = p0[1+i];
7485    }
7486    if (p1[0] >= 0) {
7487       for (i=0; i<4; ++i) sv->pickrenpix4[p1[0]+i] = p1[1+i];
7488    }
7489    if (p2[0] >= 0) {
7490       for (i=0; i<4; ++i) sv->pickrenpix4[p2[0]+i] = p2[1+i];
7491    }
7492    if (p3[0] >= 0) {
7493       for (i=0; i<4; ++i) sv->pickrenpix4[p3[0]+i] = p3[1+i];
7494    }
7495 
7496    SUMA_RETURN(YUP);
7497 }
7498 
7499 /*
7500    Function to return the color in the stored rendering buffer.
7501    checking is done at the pick location first, then in progressively
7502    larger neighborhoods
7503 
7504    When first called, the search begins at pixel  *i, *j. If nothing
7505    is found, the search proceeds within the layer limit and the first
7506    non-blank find is returned in pixhit. *i and *j are set to the newly
7507    picked location
7508 
7509    i is along the width, j along the height
7510 */
SUMA_GetColidInPickBuffer4(GLubyte * pix,int Ni,int Nj,int * ii,int * ji,int maxlay,GLubyte * colid)7511 SUMA_Boolean SUMA_GetColidInPickBuffer4(GLubyte *pix, int Ni, int Nj,
7512                                         int *ii, int *ji,
7513                                         int maxlay, GLubyte *colid)
7514 {
7515    static char FuncName[]={"SUMA_GetColidInPickBuffer4"};
7516    int i0, j0, i, j, n4, k;
7517    int poff[(1+2*2)*(1+2*2)][2] = {
7518                       {0,0}, {-1,0}, {-1,-1}, {0,-1}, {-1,-1}, {1,1},/*A..F*/
7519                       {-2,0}, {-2,1}, {-2,-2}, {-1,-2}, {0,-2}, {-2,1},/*G..L*/
7520                       {1,-1}, {0,1}, {1,0}, {-2,2}, {1,-2}, {-1,2},/*M..R*/
7521                       {2,-2}, {2,-1},{0,2}, {2,0},{1,2},{2,1},{2,2} }/*S..Y*/;
7522 
7523    SUMA_ENTRY;
7524 
7525    // fprintf(stderr, "%s\n", FuncName);
7526 
7527    if (!pix || !ii || !ji || *ii <0 || *ii >= Ni || *ji<0 || *ji>Nj) {
7528       SUMA_S_Err("Bad input");
7529       SUMA_RETURN(NOPE);
7530    }
7531    if (maxlay < 0) maxlay = 0;
7532    if (maxlay > 2) {
7533       SUMA_S_Warn("Not ready for more than two layers");
7534       maxlay = 2;
7535    }
7536 
7537    i = *ii; j = *ji;
7538    n4 = 4*(i+j*Ni);
7539    if (pix[n4] || pix[n4+1] || pix[n4+2] ||  pix[n4+3]) {
7540       memcpy(colid, pix+n4, 4*sizeof(GLubyte));
7541       SUMA_RETURN(YUP);
7542    }
7543 
7544    if (maxlay == 0) SUMA_RETURN(NOPE);
7545 
7546    /* search in order shown on page 235 of labbook NIH-6
7547       The idea is to follow a search pattern based on the shape
7548       of the cursor pointing up and slightly left
7549       Actually maxlay == 1 is not quite honored here */
7550    i0 = *ii; j0 = *ji;
7551    k=1;
7552    while (k<25) {
7553       if ((i=i0+poff[k][0]) >=0 && i<Ni &&
7554           (j=j0+poff[k][0]) >=0 && j<Nj) {
7555          n4 = 4*(i+j*Ni);
7556          if (pix[n4] || pix[n4+1] || pix[n4+2] ||  pix[n4+3]) {
7557             memcpy(colid, pix+n4, 4*sizeof(GLubyte));
7558             *ii=i; *ji=j;
7559             SUMA_RETURN(YUP);
7560          }
7561       }
7562       ++k;
7563    }
7564    /* if nothing is found, and users want more layers, start searching in
7565       squarish patterns from layer 3 onwards, someday */
7566 
7567    SUMA_RETURN(NOPE);
7568 }
7569 
7570 /* if action == 0: Free saved DO picking buffer in pickrenpix4
7571                 1: Recreate pickrenpix4 regardless of whether or
7572                    not the new pickrenpix4 is expected to change
7573                 2: Recreate pickrenpix4 only if deemed necessary
7574 */
SUMA_PickBuffer(SUMA_SurfaceViewer * sv,int action,SUMA_DO * dov)7575 SUMA_Boolean SUMA_PickBuffer(SUMA_SurfaceViewer *sv, int action, SUMA_DO *dov)
7576 {
7577    static char FuncName[]={"SUMA_PickBuffer"};
7578    int Flush = 0;
7579    SUMA_Boolean LocalHead = NOPE;
7580 
7581    SUMA_ENTRY;
7582 
7583    // fprintf(stderr, "%s\n", FuncName);
7584 
7585    if (!sv) {
7586       SUMA_S_Err("Null sv!");
7587       SUMA_RETURN(NOPE);
7588    }
7589 
7590    if ( action == 0 || /* flush only */
7591         action == 1 /* Recreate regardless */ ) {
7592          /* flush needed */
7593          SUMA_LH("Flushing pickrenpix4");
7594          Flush = 1;
7595    } else if (action == 2) { /* recreate if needed */
7596       if (  MASK_MANIP_MODE(sv) ||
7597             SUMA_DiffGeomViewStruct(sv->GVS[sv->StdView],
7598                                   sv->GVS_last_PickMode[sv->StdView], 1) ||
7599             sv->FOV[sv->iState] != sv->FOV_last_PickMode[sv->iState]) {
7600          SUMA_LH("Have a changed GVS or FOV, flushing pickrenpix4");
7601          Flush = 1;
7602       } else {
7603          SUMA_LH("GVS and FOV still the same");
7604       }
7605    } else {
7606       SUMA_S_Errv("Bad action value %d\n", action);
7607       SUMA_RETURN(NOPE);
7608    }
7609 
7610    if (Flush) {
7611       SUMA_LHv("Flushing, action %d\n", action);
7612       if (sv->pickrenpix4) SUMA_free(sv->pickrenpix4);
7613       sv->pickrenpix4 = NULL;
7614    }
7615 
7616    if (action == 0) SUMA_RETURN(YUP);
7617 
7618    /* recreate if no pickrenpix4 */
7619    if (!sv->pickrenpix4) {
7620       /* record GVS and FOV states*/
7621       SUMA_CopyGeomViewStruct(&(sv->GVS[sv->StdView]),
7622                               &(sv->GVS_last_PickMode[sv->StdView]));
7623       sv->FOV_last_PickMode[sv->iState] = sv->FOV[sv->iState];
7624 
7625       sv->DO_PickMode = 1;
7626       SUMA_display(sv, dov);
7627       if (!(sv->pickrenpix4 =
7628                SUMA_grabPixels(4, sv->X->aWIDTH, sv->X->aHEIGHT))) {
7629          SUMA_S_Err("Failed to grab pixels");
7630       }
7631       sv->DO_PickMode = 0;
7632    }
7633    SUMA_RETURN(YUP);
7634 }
7635 
SUMA_ADO_Flush_Pick_Buffer(SUMA_ALL_DO * ado,SUMA_SurfaceViewer * sv)7636 SUMA_Boolean SUMA_ADO_Flush_Pick_Buffer(SUMA_ALL_DO *ado, SUMA_SurfaceViewer *sv)
7637 {
7638    static char FuncName[]={"SUMA_ADO_Flush_Pick_Buffer"};
7639    int ii;
7640    SUMA_ENTRY;
7641 
7642    // fprintf(stderr, "%s\n", FuncName);
7643 
7644    if (!ado) SUMA_RETURN(NOPE);
7645    if (sv) {
7646       if (SUMA_ADO_isRegistered(sv, ado)) {
7647          SUMA_PickBuffer(sv, 0, NULL);
7648       }
7649    } else { /* Do it for all */
7650       for (ii=0; ii<SUMAg_N_SVv; ++ii) {
7651          sv = &(SUMAg_SVv[ii]);
7652          if (SUMA_ADO_isRegistered(sv, ado)) {
7653             SUMA_PickBuffer(sv, 0, NULL);
7654          }
7655       }
7656    }
7657 
7658    SUMA_RETURN(YUP);
7659 }
7660 
7661 /* What was picked on a frame SO ?
7662    See SUMA_Surface_Of_NIDO_Matrix() for how surface coordinates
7663    translate to matrix pixels and eventually matrix cells.
7664    See also SUMA_GDSET_edgeij_to_GMATRIX_XYZ() and SUMA_DrawGraphDO_GMATRIX()
7665 */
SUMA_WhatWasPicked_FrameSO(SUMA_SurfaceViewer * sv,int ido)7666 SUMA_PICK_RESULT *SUMA_WhatWasPicked_FrameSO(SUMA_SurfaceViewer *sv, int ido)
7667 {
7668    static char FuncName[]={"SUMA_WhatWasPicked_FrameSO"};
7669    float P0[3], P1[3];
7670    int N[3], IIm[3], ii, jj, i, *ui=NULL, *uj=NULL, si=-1, G[3], B[3], M[3];
7671    SUMA_ALL_DO *ado=NULL;
7672    SUMA_DSET *dset=NULL;
7673    SUMA_PICK_RESULT *PR = NULL;
7674    SUMA_SurfaceObject *SO=NULL;
7675    SUMA_GRAPH_SAUX *GSaux = NULL;
7676    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
7677    double Aff[4][4], I[3], V[12], X[3], GB[3];
7678    SUMA_Boolean LocalHead = NOPE;
7679 
7680    SUMA_ENTRY;
7681 
7682    // fprintf(stderr, "%s\n", FuncName);
7683 
7684    if (!sv ) {
7685       SUMA_S_Err("NULL input");
7686       SUMA_RETURN(PR);
7687    }
7688 
7689    if (!iDO_isGLDO(ido) || !iDO_is_variant(ido,"GMATRIX")) {
7690       /* No frame SOs in this DO, not an error just keep looking */
7691       SUMA_LH("Not a DO with a FrameSO, go on");
7692       SUMA_RETURN(PR);
7693    }
7694 
7695    SUMA_LHv("Pick Query for FrameSO on sv %p, ido %d\n", sv, ido);
7696    if (iDO_is_variant(ido,"GMATRIX") &&
7697        (GSaux = iDO_GSaux(ido))) {
7698        SO=GSaux->FrameSO;
7699    }
7700    if (!SO) {
7701       SUMA_S_Errv("No FrameSO on %s\n", iDO_label(ido));
7702       SUMA_RETURN(PR);
7703    }
7704    NI_GET_DOUBLEv(GSaux->nido->ngr, "dicom_real_to_ijk", V, 12, LocalHead);
7705    if (!NI_GOT) {
7706       SUMA_S_Err("No dicom_real_to_ijk");
7707       SUMA_RETURN(PR);
7708    }
7709    V12_TO_AFF44(Aff, V);
7710 
7711    NI_GET_INTv(GSaux->nido->ngr, "Nijk", N, 3, LocalHead);
7712    if (!NI_GOT) {
7713       SUMA_S_Err("No Nijk");
7714       SUMA_RETURN(PR);
7715    }
7716 
7717    /* total num of pixels per value */
7718    NI_GET_INTv(GSaux->nido->ngr, "PixCount", M, 3, LocalHead);
7719    NI_GET_INTv(GSaux->nido->ngr, "PixPerVal", G, 3, LocalHead);
7720    NI_GET_INTv(GSaux->nido->ngr, "BorWid", B, 3, LocalHead);
7721    GB[0] = G[0]+B[0];
7722    GB[1] = G[1]+B[1];
7723    GB[2] = G[2]+B[2];
7724 
7725    SUMA_COPY_VEC(sv->Pick0, P0, 3, GLdouble, float);
7726    SUMA_COPY_VEC(sv->Pick1, P1, 3, GLdouble, float);
7727    if (!(MTI = SUMA_MT_intersect_triangle(P0, P1,
7728                            SO->NodeList, SO->N_Node,
7729                            SO->FaceSetList, SO->N_FaceSet, NULL, 0))){
7730       SUMA_S_Err("SUMA_MT_intersect_triangle failed.");
7731       SUMA_RETURN(PR);
7732    }
7733 
7734    if (MTI->N_hits < 1) {
7735       SUMA_LH("No hits");
7736       SUMA_RETURN(PR);
7737    }
7738 
7739    ui = uj = NULL;
7740    if (iDO_isGLDO(ido)) {
7741       if (!(dset = SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)SUMAg_DOv[ido].OP))) {
7742          SUMA_S_Err("No dset for GLDO?");
7743          SUMA_RETURN(PR);
7744       }
7745       GSaux->IgnoreSelection = 0; /* Selection being made on matrix
7746                                      representation of graph.
7747                                      turn off IgnoreSelection */
7748       switch (dset->Aux->matrix_shape) {
7749          case MAT_FULL:
7750          case MAT_TRI:
7751          case MAT_TRI_DIAG:
7752             SUMA_LH("Direct indexing between edge points and matrix row/col");
7753             break;
7754          case MAT_SPARSE:
7755             if (!dset->inel) {
7756                SUMA_S_Err("Don't have inel, badly shaped dataset");
7757                SUMA_RETURN(PR);
7758             }
7759             if (  !(ui = SUMA_GetUniqueIndicesVec(dset,1)) ||
7760                   !(uj = SUMA_GetUniqueIndicesVec(dset,2))    ) {
7761                SUMA_S_Err("Failed to get unique indices");
7762                SUMA_RETURN(PR);
7763             }
7764             break;
7765          default:
7766             SUMA_S_Err("Rats");
7767             SUMA_RETURN(PR);
7768             break;
7769       }
7770    }
7771 
7772 
7773    PR = SUMA_New_Pick_Result(PR);
7774    PR->ado_idcode_str = SUMA_replace_string(PR->ado_idcode_str,iDO_idcode(ido));
7775    ado = SUMA_whichADOg(PR->ado_idcode_str);
7776    PR->primitive = SUMA_replace_string(PR->primitive, "none yet");
7777    PR->primitive_index = -1;
7778    PR->PickXYZ[0] = MTI->P[0];
7779    PR->PickXYZ[1] = MTI->P[1];
7780    PR->PickXYZ[2] = MTI->P[2];
7781    sv->Focus_DO_ID = ido;
7782 
7783    PR->datum_index = -1;
7784    for (i=0; i<SUMA_N_IALTSEL_TYPES; ++i) PR->iAltSel[i] = -1;
7785    for (i=0; i<SUMA_N_DALTSEL_TYPES; ++i) PR->dAltSel[i] = 0.0;
7786    AFF44_MULT_I(I, Aff, MTI->P);
7787 
7788    SUMA_LHv("Hit on Frame SO, triangle %d %f %f %f, M=[%d %d]\n"
7789             "     Pixel hit: %.2f %.2f %.2f\n",
7790             MTI->ifacemin, MTI->P[0], MTI->P[1], MTI->P[2], M[0], M[1],
7791             I[0], I[1], I[2]);
7792 
7793    for (i=0; i<3; ++i) {
7794       /* I[i] = I[i]/GB[i]; Account for per value gain and
7795                                     background thickness */
7796       /* Round I to get matrix pixel coordinates*/
7797       I[i] = SUMA_ROUND(I[i]);
7798       if (I[i] < 0) IIm[i] = -1;
7799       else if (I[i] >= GB[i]*N[i]) IIm[i] = -1;
7800       else IIm[i] = (int)(I[i]/GB[i]); /* Undo gain to get back to matrix grid */
7801    }
7802 
7803    if (ui) { /* sparse hell */
7804       if (IIm[0]>=0) ii = ui[IIm[0]];
7805       else ii = -1;
7806       if (IIm[1]>=0) jj = uj[IIm[1]];
7807       else jj = -1;
7808    } else {
7809       ii = IIm[0]; jj=IIm[1];
7810    }
7811 
7812    SUMA_LHv("In face %d X=[%f %f %f]dicom, GB=[%d %d] \n"
7813             "     If=[%f %f %f], Im=[%d %d %d], ii,jj=[%d %d]\n",
7814             MTI->ifacemin, MTI->P[0], MTI->P[1], MTI->P[2],
7815             (int)GB[0], (int)GB[1],
7816             I[0], I[1], I[2], IIm[0], IIm[1], IIm[2], ii, jj);
7817 
7818    switch (MTI->ifacemin) {
7819       case 0:
7820       case 1:
7821          /* in matrix */
7822          PR->primitive = SUMA_replace_string(PR->primitive, "segments");
7823          if (!ui && ii >= 0 && jj >= 0) {
7824             PR->datum_index = PR->primitive_index = ii+jj*N[0];
7825          } else { /* sparse */
7826             if (ii < 0 || jj < 0) {
7827                PR->datum_index = PR->primitive_index = -1;
7828             } else if (!SUMA_GDSET_PointsToSegIndex(dset, ii, jj, &si)) {
7829                SUMA_S_Errv("Failed to find segment for %d %d\n", ii, jj);
7830                if (LocalHead) SUMA_DUMP_TRACE("Now what?");
7831                PR->datum_index = PR->primitive_index = -1;
7832             } else {
7833                PR->datum_index = PR->primitive_index = si;
7834             }
7835          }
7836          if (MTI->ifacemin == 1) {
7837             PR->iAltSel[SUMA_ENODE_0] = ii;
7838             PR->iAltSel[SUMA_ENODE_1] = jj;
7839          } else {
7840             PR->iAltSel[SUMA_ENODE_0] = jj;
7841             PR->iAltSel[SUMA_ENODE_1] = ii;
7842          }
7843          break;
7844       case 2:
7845       case 3:
7846          /* top edge*/
7847          PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7848          PR->iAltSel[SUMA_ENODE_0] = jj;
7849          PR->iAltSel[SUMA_ENODE_1] = -1;
7850          break;
7851       case 4:
7852       case 5:
7853          /* right edge*/
7854          PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7855          PR->iAltSel[SUMA_ENODE_0] = ii;
7856          PR->iAltSel[SUMA_ENODE_1] = -1;
7857          break;
7858       case 6:
7859       case 7:
7860          /* bottom edge*/
7861          PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7862          PR->iAltSel[SUMA_ENODE_0] = jj;
7863          PR->iAltSel[SUMA_ENODE_1] = -1;
7864          break;
7865       case 8:
7866       case 9:
7867          /* left edge*/
7868          PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7869          PR->iAltSel[SUMA_ENODE_0] = ii;
7870          PR->iAltSel[SUMA_ENODE_1] = -1;
7871          break;
7872       default:
7873          SUMA_S_Errv("Faceset %d???\n", MTI->ifacemin);
7874          SUMA_RETURN(PR);
7875    }
7876 
7877    MTI = SUMA_Free_MT_intersect_triangle(MTI);
7878 
7879    SUMA_RETURN(PR);
7880 }
7881 
7882 /*!
7883    \brief find the closest location on a bundle to a point
7884    on the screen.
7885 
7886    p (void *) One bundle
7887    ptype (char): Type of bundle. 'N' --> p is a NI_element *
7888                                  'B' --> p is a TAYLOR_BUNDLE *
7889    Tmask (int): if not < 0 then only consider intersections in
7890                 tract Tmask of the bundle.
7891    sv (SUMA_SurfaceViewer *) The viewer
7892    scpx (float *) The pixel location in screen coordinates.
7893                   If NULL, form it from sv->PickPix;
7894    crude (int) if (0) then use crude search, return closest point
7895                       not bothering with where along the segment
7896                       between the two closest points you are
7897                   1   a fine search, locating where between
7898                       the two closest points one clicked
7899    tmin (int *) Will contain the index of the tract that was
7900                 hit within the bundle (-1 for no cigar)
7901    pmin (int *) Will contain the index of the closest point
7902                 to the hit in tract tmin
7903    fmin (float *) Will contain the fraction between pmin and
7904                   pmin+1 where intersection occurred
7905    mindist (float *) Distance from closest location on tract
7906    \ret YUP all good, NOPE nothing found or bad input
7907 */
7908 
SUMA_Bundle_Pick_Intersect(void * p,char ptype,int Tmask,SUMA_SurfaceViewer * sv,float * scpxu,int crude,int * tmin,int * pmin,float * frmin,float * mindistu)7909 SUMA_Boolean SUMA_Bundle_Pick_Intersect(void *p, char ptype, int Tmask,
7910                      SUMA_SurfaceViewer *sv, float *scpxu, int crude,
7911                      int *tmin, int *pmin, float *frmin, float *mindistu)
7912 {
7913    static char FuncName[]={"SUMA_Bundle_Pick_Intersect"};
7914    int nn, nnmin, mmmin, mm, nn_max, nn_min;
7915    float *scrxyz = NULL, dx, dy, dxy2=0.0, fmin, scpx[3];
7916    float  mindist2, mindist, *A, *B;
7917    double P[3], f = 0.0;
7918    NI_element *nelitp=NULL;
7919    TAYLOR_BUNDLE *tb = NULL;
7920    TAYLOR_TRACT *ttn=NULL;
7921 
7922    SUMA_ENTRY;
7923 
7924    // fprintf(stderr, "%s\n", FuncName);
7925 
7926    if (tmin) *tmin = -1;
7927    if (pmin) *pmin = -1;
7928    if (frmin) *frmin = -1.0;
7929    if (mindistu) *mindistu = -1.0;
7930 
7931    if (!p || !sv) SUMA_RETURN(NOPE);
7932 
7933    nn_min = 0;
7934    if (ptype == 'N') { /* NI_element */
7935       nelitp = (NI_element *)p;
7936       nn_max = nelitp->vec_len;
7937    } else if (ptype == 'B') { /* Taylor Bundle */
7938       tb = (TAYLOR_BUNDLE *)p;
7939       if (Tmask < 0) {
7940          nn_max = tb->N_tracts;
7941       } else {
7942          if (Tmask < tb->N_tracts) {
7943             nn_min = Tmask;
7944             nn_max = nn_min+1;
7945          } else {
7946             SUMA_S_Err("Tmask (%d) exceeds number of tracts (%d) in bundle",
7947                        Tmask, tb->N_tracts);
7948             SUMA_RETURN(NOPE);
7949          }
7950       }
7951    } else {
7952       SUMA_RETURN(NOPE);
7953    }
7954 
7955    nnmin=-1; mmmin=-1; mindist=mindist2=1000; fmin=1.0;
7956    if (scpxu) {
7957       scpx[0] = scpxu[0]; scpx[1] = scpxu[1]; scpx[2] = scpxu[2];
7958    } else {
7959       GLint viewport[4];
7960       glGetIntegerv(GL_VIEWPORT, viewport);
7961       /* screen pick coordinate in screen coords */
7962       scpx[0] = sv->PickPix[0];
7963       scpx[1] = viewport[3]-sv->PickPix[1]-1;
7964       scpx[2] = 0.0;
7965    }
7966 
7967    for (nn=nn_min; nn<nn_max; ++nn) {
7968       if (nelitp) {
7969          ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nn;
7970       } else {
7971          ttn = tb->tracts+nn;
7972       }
7973       scrxyz = (float *)SUMA_calloc(ttn->N_pts3, sizeof(float));
7974       memcpy(scrxyz, ttn->pts, (ttn->N_pts3)*sizeof(float));
7975       /* tranform bundle points to screen space*/
7976       if (!SUMA_World2ScreenCoordsF(sv, ttn->N_pts3/3,
7977                                    ttn->pts, scrxyz, NULL,
7978                                    YUP, YUP)) {
7979          SUMA_S_Err("Failed to get screen coords");
7980          SUMA_RETURN(NOPE);
7981       }
7982       /* Now search for the closest point of bundle to the click
7983          The depth is ignored, in the hope that a simple closest
7984          search is enough. Otherwise we need to add a heuristic
7985          for the cost of depth */
7986       if (crude) {
7987             /* For finer tracing, you should project scpx onto the
7988             segment between the 1st and 2 points forming a segment,
7989             much like what is done in SUMA_PROJECT_C_ONTO_AB below
7990             The finer tracing is needed for crass paths. However
7991             for real bundles, on high-res data this might be
7992             overkill */
7993          mm=0;
7994          while (mm < ttn->N_pts3) {
7995             if ( ((dx = SUMA_ABS(scrxyz[mm  ]-scpx[0])) < mindist) &&
7996                  ((dy = SUMA_ABS(scrxyz[mm+1]-scpx[1])) < mindist) ){                            if ((dxy2 = dx*dx+dy*dy) < mindist2) {
7997                   mindist2 = dxy2;
7998                   mindist  = sqrtf(mindist2);
7999                   nnmin=nn; mmmin=mm/3;  fmin = 0.0;
8000                }
8001             }
8002             mm += 3;
8003          }
8004       } else {
8005          mm=0;
8006          while (mm < ttn->N_pts3-3) {
8007             A = scrxyz+mm;
8008             B = scrxyz+mm+3;
8009             SUMA_PROJECT_C_ONTO_AB(scpx, A, B, P, f);
8010             if ( (f > -0.2 && f < 1.2) &&
8011                  ((dx = SUMA_ABS(P[0]-scpx[0])) < mindist) &&
8012                  ((dy = SUMA_ABS(P[1]-scpx[1])) < mindist) ){                                    if ((dxy2 = dx*dx+dy*dy) < mindist2) {
8013                   mindist2 = dxy2;
8014                   mindist  = sqrtf(mindist2);
8015                   nnmin=nn; mmmin=mm/3; fmin=f;
8016                }
8017             }
8018             mm += 3;
8019          }
8020       }
8021       SUMA_ifree(scrxyz);
8022    }
8023 
8024    if (tmin) *tmin=nnmin;
8025    if (pmin) *pmin=mmmin;
8026    if (frmin) *frmin=fmin;
8027    if (mindistu) *mindistu = mindist;
8028 
8029    SUMA_RETURN(YUP);
8030 }
8031 
8032 /* Find the object that was picked, pointer copy to found object is
8033    returned in ucodf and should not be freed by calling function*/
SUMA_WhatWasPicked(SUMA_SurfaceViewer * sv,GLubyte * colid,SUMA_COLID_OFFSET_DATUM ** ucodf,int ipick,int jpick,SUMA_PICK_RESULT * PR)8034 SUMA_PICK_RESULT *SUMA_WhatWasPicked(SUMA_SurfaceViewer *sv, GLubyte *colid,
8035                                 SUMA_COLID_OFFSET_DATUM **ucodf,
8036                                 int ipick, int jpick,
8037                                 SUMA_PICK_RESULT *PR)
8038 {
8039    static char FuncName[]={"SUMA_WhatWasPicked"};
8040    DListElmt *el=NULL;
8041    SUMA_COLID_OFFSET_DATUM *cod=NULL, *codf=NULL;
8042    long int n4;
8043    int iii;
8044    double f = 0.0;
8045    SUMA_ALL_DO *ado=NULL;
8046    SUMA_DUMB_DO DDO;
8047    SUMA_Boolean LocalHead = NOPE;
8048 
8049    SUMA_ENTRY;
8050 
8051    // fprintf(stderr, "%s\n", FuncName);
8052 
8053    if (ucodf) *ucodf=codf;
8054    PR = SUMA_New_Pick_Result(PR);
8055    if (!sv || !colid) {
8056       SUMA_S_Err("NULL input");
8057       SUMA_RETURN(PR);
8058    }
8059    if (!sv->pick_colid_list || !dlist_size(sv->pick_colid_list)) {
8060       SUMA_S_Err("NULL or Empty pick_colid_list");
8061       SUMA_RETURN(PR);
8062    }
8063    if (LocalHead) SUMA_Show_Pick_Colid_List(sv->pick_colid_list, SUMA_STDERR);
8064    SUMA_COLID_RGBA2N(colid[0], colid[1], colid[2], colid[3], n4);
8065    do {
8066       if (!el) el = dlist_head(sv->pick_colid_list);
8067       else el = dlist_next(el);
8068       cod = (SUMA_COLID_OFFSET_DATUM *)el->data;
8069       if (n4>= cod->i0 && n4<= cod->i1) { /* we're in this object */
8070          codf = cod;
8071       }
8072    } while (!codf && el != dlist_tail(sv->pick_colid_list));
8073 
8074    if (!codf) SUMA_RETURN(PR);
8075    if (ucodf) *ucodf=codf;
8076 
8077    /* Compute get more info about intersection  */
8078    if (codf) {
8079       NI_element *nelitp=NULL;
8080       float *fv=NULL;
8081       double xyzw[9], scl[9], U[3], P[3], C[3], *dv=NULL;
8082       int i0, i1, ir, datum_index;
8083       SUMA_ALL_DO *ado=NULL;
8084       SUMA_DSET *dset=NULL;
8085       GLint viewport[4];
8086       SUMA_GRAPH_SAUX *GSaux = NULL;
8087 
8088       glGetIntegerv(GL_VIEWPORT, viewport);
8089       PR->ado_idcode_str = SUMA_replace_string(PR->ado_idcode_str,
8090                                                codf->ref_idcode_str);
8091       PR->primitive = SUMA_replace_string(PR->primitive, codf->primitive);
8092       PR->primitive_index = (n4-codf->i0);
8093       for (i0=0; i0<SUMA_N_IALTSEL_TYPES; ++i0) PR->iAltSel[i0] = -1;
8094       for (i0=0; i0<SUMA_N_DALTSEL_TYPES; ++i0) PR->dAltSel[i0] = 0.0;
8095       PR->datum_index = -1;
8096       ado = SUMA_whichADOg(PR->ado_idcode_str);
8097       switch (codf->ref_do_type) {
8098          case GRAPH_LINK_type: {
8099             dset = SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)ado);
8100             DDO.err = 1; SUMA_Load_Dumb_DO(ado, &DDO);
8101             if (DDO.err) {
8102                if (DDO.err==1) {
8103                   SUMA_SL_Err("Object's parent graph set not found.");
8104                } else if (DDO.err==2) {
8105                   SUMA_SL_Err("Could not fill DDO");
8106                } else {
8107                   SUMA_SL_Err("Weird error.");
8108                }
8109                SUMA_RETURN (PR);
8110             }
8111             if (!DDO.NodeList) {
8112                SUMA_S_Err("SDO is node based but could not get a NodeList");
8113                SUMA_RETURN (PR);
8114             }
8115             if (!(GSaux = SDSET_GSAUX(dset))) {
8116                SUMA_S_Err("No GSaux");
8117                SUMA_RETURN(PR);
8118             }
8119             GSaux->IgnoreSelection = 0; /*reset ignore selection flag */
8120             if (SUMA_is_ADO_Datum_Primitive(ado, codf)) {
8121                datum_index = SUMA_GDSET_EdgeRow_To_Index(dset,
8122                                                          PR->primitive_index);
8123                if (!(SUMA_GDSET_SegIndexToPoints(dset, datum_index,
8124                                                  &i0, &i1, NULL))) {
8125                   SUMA_RETURN(PR);
8126                }
8127                nelitp = NULL;
8128                if (GSaux->ShowBundles &&
8129                    (nelitp = SUMA_GDSET_Edge_Bundle(dset, GSaux,
8130                                                     datum_index, -1))) {
8131                #if 1 /* more unified version, older, valid one below */
8132                   int nn=0, mm=0, nnmin=-1, mmmin=-1, mmmin3=-1;
8133                   float scpx[3], *A, *B;
8134                   float mindist, dist, distatmin, seglen;
8135                   float fmin;
8136                   TAYLOR_TRACT *ttn=NULL;
8137 
8138                   SUMA_LHv("Clicked on a bundle representation of edge %d.\n",
8139                            datum_index);
8140                   /* screen pick coordinate in screen coords */
8141                   scpx[0] = sv->PickPix[0];
8142                   scpx[1] = viewport[3]-sv->PickPix[1]-1;
8143                   scpx[2] = 0.0;
8144                   /* find the closest point to where we clicked on the bundle */
8145                   if (!SUMA_Bundle_Pick_Intersect(nelitp, 'N', -1, sv, scpx, 0,
8146                                                   &nnmin, &mmmin,
8147                                                   &fmin, &mindist)) {
8148                      SUMA_LH("No bunlde intersection");
8149                   }
8150                   mmmin3 = 3*mmmin;
8151                   if (nnmin > -1) {
8152                      ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nnmin;
8153                      if (fmin != 0.0f) {
8154                         PR->PickXYZ[0]=ttn->pts[mmmin3+0]+
8155                                     fmin*(ttn->pts[mmmin3+3]-ttn->pts[mmmin3]);
8156                         PR->PickXYZ[1]=ttn->pts[mmmin3+1]+
8157                                     fmin*(ttn->pts[mmmin3+4]-ttn->pts[mmmin3+1]);
8158                         PR->PickXYZ[2]=ttn->pts[mmmin3+2]+
8159                                     fmin*(ttn->pts[mmmin3+5]-ttn->pts[mmmin3+2]);
8160                         /* where along the tract? */
8161                         mm=0; dist=0.0; distatmin=19999.9;
8162                         while (mm < ttn->N_pts3-3) {
8163                            A = ttn->pts+mm;
8164                            B = ttn->pts+mm+3;
8165                            seglen =  sqrtf((B[0]-A[0])*(B[0]-A[0])+
8166                                            (B[1]-A[1])*(B[1]-A[1])+
8167                                            (B[2]-A[2])*(B[2]-A[2]));
8168                            if (mm==mmmin3) {
8169                               distatmin = dist + fmin*seglen;
8170                            }
8171                            dist +=seglen;
8172                            mm += 3;
8173                         }
8174                         /* Which is the closest node? */
8175                         f = distatmin/dist;
8176                         if (f <= 0.5) {
8177                            PR->iAltSel[SUMA_ENODE_0] = i0;
8178                            PR->iAltSel[SUMA_ENODE_0] = i1;
8179                            if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
8180                               PR->datum_index = datum_index;
8181                            } else PR->datum_index = -1;
8182                         } else {
8183                            SUMA_LHv("++half way, look for opp. edge [%d %d]\n",
8184                                     i1, i0);
8185                            PR->iAltSel[SUMA_ENODE_0] = i1;
8186                            PR->iAltSel[SUMA_ENODE_1] = i0;
8187 
8188                            if (SUMA_ABS(1.0-f) > 0.01){/*not too close to edge*/
8189                               /* does edge [i1, i0] exist? If so take it*/
8190                               if (SUMA_GDSET_PointsToSegIndex(dset,i1,i0,&ir)) {
8191                                  SUMA_LHv("Switching primitve to edge %d\n", ir);
8192                                  PR->datum_index = ir;
8193                               } else { /* leave old hit, no opposite edge */
8194                                  PR->datum_index = datum_index;
8195                               }
8196                            } else PR->datum_index = -1;
8197                         }
8198                      } else { /* from the quick search, no fmin used*/
8199                         PR->PickXYZ[0]=ttn->pts[mmmin3+0];
8200                         PR->PickXYZ[1]=ttn->pts[mmmin3+1];
8201                         PR->PickXYZ[2]=ttn->pts[mmmin3+2];
8202                      }
8203                   } else {
8204                      PR->PickXYZ[0] = PR->PickXYZ[1] = PR->PickXYZ[2]=0.0;
8205                   }
8206                   SUMA_LHv("Closest distance of %f, tract %d, point %d, f=%f\n"
8207                            "at world [%f %f %f]\n",
8208                            mindist, nnmin, mmmin, fmin,
8209                            PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
8210                #else
8211                   int nn=0, mm=0, nnmin=-1, mmmin=-1;
8212                   float *scrxyz = NULL, scpx[3], *A, *B;
8213                   float mindist, mindist2, dist, distatmin, seglen;
8214                   float dx, dy, dxy2=0.0, fmin;
8215                   TAYLOR_TRACT *ttn=NULL;
8216 
8217                   SUMA_LHv("Clicked on a bundle representation of edge %d.\n",
8218                            datum_index);
8219                   /* screen pick coordinate in screen coords */
8220                   scpx[0] = sv->PickPix[0];
8221                   scpx[1] = viewport[3]-sv->PickPix[1]-1;
8222                   scpx[2] = 0.0;
8223                   /* find the closest point to where we clicked on the bundle */
8224                   nnmin=-1; mmmin=-1; mindist=mindist2=1000; fmin=1.0;
8225                   for (nn=0; nn<nelitp->vec_len; ++nn) {
8226                      ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nn;
8227                      scrxyz = (float *)SUMA_calloc(ttn->N_pts3, sizeof(float));
8228                      memcpy(scrxyz, ttn->pts, (ttn->N_pts3)*sizeof(float));
8229                      /* tranform bundle points to screen space*/
8230                      if (!SUMA_World2ScreenCoordsF(sv, ttn->N_pts3/3,
8231                                                   ttn->pts, scrxyz, NULL,
8232                                                   YUP, YUP)) {
8233                         SUMA_S_Err("Failed to get screen coords");
8234                         SUMA_RETURN(PR);
8235                      }
8236                      /* Now search for the closest point of bundle to the click
8237                         The depth is ignored, in the hope that a simple closest
8238                         search is enough. Otherwise we need to add a heuristic
8239                         for the cost of depth */
8240                      #ifdef CRUDE_SEARCH
8241                         /* For finer tracing, you should project scpx onto the
8242                         segment between the 1st and 2 points forming a segment,
8243                         much like what is done in SUMA_PROJECT_C_ONTO_AB below
8244                         The finer tracing is needed for crass paths. However
8245                         for real bundles, on high-res data this might be
8246                         overkill */
8247                      mm=0;
8248                      while (mm < ttn->N_pts3) {
8249                         if ( ((dx = SUMA_ABS(scrxyz[mm  ]-scpx[0])) < mindist) &&
8250                              ((dy = SUMA_ABS(scrxyz[mm+1]-scpx[1])) < mindist) ){                            if ((dxy2 = dx*dx+dy*dy) < mindist2) {
8251                               mindist2 = dxy2;
8252                               mindist  = sqrtf(mindist2);
8253                               nnmin=nn; mmmin=mm;  fmin = 0.0;
8254                            }
8255                         }
8256                         mm += 3;
8257                      }
8258                      #else
8259                      mm=0;
8260                      while (mm < ttn->N_pts3-3) {
8261                         A = scrxyz+mm;
8262                         B = scrxyz+mm+3;
8263                         SUMA_PROJECT_C_ONTO_AB(scpx, A, B, P, f);
8264                         if ( ((dx = SUMA_ABS(P[0]-scpx[0])) < mindist) &&
8265                              ((dy = SUMA_ABS(P[1]-scpx[1])) < mindist) ){                                    if ((dxy2 = dx*dx+dy*dy) < mindist2) {
8266                               mindist2 = dxy2;
8267                               mindist  = sqrtf(mindist2);
8268                               nnmin=nn; mmmin=mm; fmin=f;
8269                            }
8270                         }
8271                         mm += 3;
8272                      }
8273                      #endif
8274                      SUMA_ifree(scrxyz);
8275                   }
8276                   if (nnmin > -1) {
8277                      ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nnmin;
8278                      if (fmin != 0.0f) {
8279                         PR->PickXYZ[0]=ttn->pts[mmmin+0]+
8280                                     fmin*(ttn->pts[mmmin+3]-ttn->pts[mmmin]);
8281                         PR->PickXYZ[1]=ttn->pts[mmmin+1]+
8282                                     fmin*(ttn->pts[mmmin+4]-ttn->pts[mmmin+1]);
8283                         PR->PickXYZ[2]=ttn->pts[mmmin+2]+
8284                                     fmin*(ttn->pts[mmmin+5]-ttn->pts[mmmin+2]);
8285                         /* where along the tract? */
8286                         mm=0; dist=0.0; distatmin=19999.9;
8287                         while (mm < ttn->N_pts3-3) {
8288                            A = ttn->pts+mm;
8289                            B = ttn->pts+mm+3;
8290                            seglen =  sqrtf((B[0]-A[0])*(B[0]-A[0])+
8291                                            (B[1]-A[1])*(B[1]-A[1])+
8292                                            (B[2]-A[2])*(B[2]-A[2]));
8293                            if (mm==mmmin) {
8294                               distatmin = dist + fmin*seglen;
8295                            }
8296                            dist +=seglen;
8297                            mm += 3;
8298                         }
8299                         /* Which is the closest node? */
8300                         f = distatmin/dist;
8301                         if (f <= 0.5) {
8302                            PR->iAltSel[SUMA_ENODE_0] = i0;
8303                            PR->iAltSel[SUMA_ENODE_1] = i1;
8304 
8305                            if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
8306                               PR->datum_index = datum_index;
8307                            } else PR->datum_index = -1;
8308                         } else {
8309                            SUMA_LHv("++half way, look for opp. edge [%d %d]\n",
8310                                     i1, i0);
8311                            PR->iAltSel[SUMA_ENODE_0] = i1;
8312                            PR->iAltSel[SUMA_ENODE_1] = i0;
8313                            if (SUMA_ABS(1.0-f) > 0.01){/*not too close to edge*/
8314                               /* does edge [i1, i0] exist? If so take it*/
8315                               if (SUMA_GDSET_PointsToSegIndex(dset,i1,i0,&ir)) {
8316                                  SUMA_LHv("Switching primitve to edge %d\n", ir);
8317                                  PR->datum_index = ir;
8318                               } else { /* leave old hit, no opposite edge */
8319                                  PR->datum_index = datum_index;
8320                               }
8321                            } else PR->datum_index = -1;
8322                         }
8323                      } else { /* from the quick search, no fmin used*/
8324                         PR->PickXYZ[0]=ttn->pts[mmmin+0];
8325                         PR->PickXYZ[1]=ttn->pts[mmmin+1];
8326                         PR->PickXYZ[2]=ttn->pts[mmmin+2];
8327                      }
8328                   } else {
8329                      PR->PickXYZ[0] = PR->PickXYZ[1] = PR->PickXYZ[2]=0.0;
8330                   }
8331                   SUMA_LHv("Closest distance of %f, tract %d, point %d, f=%f\n"
8332                            "at world [%f %f %f]\n",
8333                            mindist, nnmin, mmmin, fmin,
8334                            PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
8335 
8336                #endif
8337                } else {
8338                   SUMA_LHv("Segment %d is formed by points %d and %d\n",
8339                            datum_index, i0, i1);
8340                   fv = SUMA_GDSET_NodeXYZ(dset, i0, SUMA_ADO_variant(ado), NULL);
8341                      xyzw[0] = fv[0]; xyzw[1] = fv[1]; xyzw[2] = fv[2];
8342                   fv = SUMA_GDSET_NodeXYZ(dset, i1, SUMA_ADO_variant(ado), NULL);
8343                      xyzw[3] = fv[0]; xyzw[4] = fv[1]; xyzw[5] = fv[2];
8344                   xyzw[6] = (sv->Pick0[0]+sv->Pick1[0])/2.0;
8345                   xyzw[7] = (sv->Pick0[1]+sv->Pick1[1])/2.0;
8346                   xyzw[8] = (sv->Pick0[2]+sv->Pick1[2])/2.0;
8347 
8348                   if (!SUMA_World2ScreenCoords(sv, 3,xyzw,scl, NULL, YUP, YUP)) {
8349                      SUMA_S_Err("Failed to get screen coords");
8350                      SUMA_RETURN(PR);
8351                   }
8352                   /* Project click point onto line by two nodes */
8353                   C[0] = sv->PickPix[0];
8354                   C[1] = viewport[3]-sv->PickPix[1]-1;
8355                   C[2] = 0;
8356                   dv = scl+3; /* point B */
8357                   SUMA_PROJECT_C_ONTO_AB(C, scl, dv, P, f);
8358                   /* Project point click onto segment */
8359                   SUMA_LHv(
8360                      "User click locations: %d %d Norm(%f %f)\n"
8361                         "sv PickPix: %d %d (screen/mouse y:%d)\n"
8362                         "world: near[%f %f %f] far[%f %f %f]\n"
8363                         "Edge %d formed by nodes %d [%f %f %f], %d [%f %f %f]\n"
8364                         "Nodes projected to screen: [%f %f %f], [%f %f %f]\n"
8365                   "Projection of click point screen edge: [%f %f %f], f = %f\n"
8366                         ,ipick, jpick,
8367                            ipick/(double)viewport[2], jpick/(double)viewport[3],
8368                         sv->PickPix[0], sv->PickPix[1], viewport[3]-jpick-1,
8369                            sv->Pick0[0], sv->Pick0[1], sv->Pick0[2],
8370                            sv->Pick1[0], sv->Pick1[1], sv->Pick1[2],
8371                         datum_index, i0, xyzw[0], xyzw[1], xyzw[2],
8372                                      i1, xyzw[3], xyzw[4], xyzw[5],
8373                            scl[0], scl[1], scl[2], scl[3], scl[4], scl[5],
8374                            P[0], P[1], P[2], f);
8375 
8376                   /* Record the intersection location */
8377                   PR->PickXYZ[0]=xyzw[0]+f*(xyzw[3]-xyzw[0]);
8378                   PR->PickXYZ[1]=xyzw[1]+f*(xyzw[4]-xyzw[1]);
8379                   PR->PickXYZ[2]=xyzw[2]+f*(xyzw[5]-xyzw[2]);
8380 
8381                   /* Which is the closest node? */
8382                   if (f <= 0.5) {
8383                      PR->iAltSel[SUMA_ENODE_0] = i0;
8384                      PR->iAltSel[SUMA_ENODE_1] = i1;
8385                      if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
8386                         PR->datum_index = datum_index;
8387                      } else PR->datum_index = -1;
8388                   } else {
8389                      SUMA_LHv("++half way, looking for opp. edge [%d %d]\n",
8390                               i1, i0);
8391                      PR->iAltSel[SUMA_ENODE_0] = i1;
8392                      PR->iAltSel[SUMA_ENODE_1] = i0;
8393                      if (SUMA_ABS(1.0-f) > 0.01) { /* not too close to edge */
8394                         /* does edge [i1, i0] exist? If so take it*/
8395                         if (SUMA_GDSET_PointsToSegIndex(dset, i1, i0, &ir)) {
8396                            SUMA_LHv("Switching primitve to edge %d\n", ir);
8397                            PR->datum_index = ir;
8398                         } else { /* leave old hit, no opposite edge */
8399                            PR->datum_index = datum_index;
8400                         }
8401                      } else PR->datum_index = -1;
8402                   }
8403                }
8404             } else { /* picked a node, no data on it*/
8405                PR->iAltSel[SUMA_ENODE_0] =
8406                   SUMA_GDSET_Index_To_NodeIndex(dset, PR->primitive_index);
8407                PR->iAltSel[SUMA_ENODE_1] = -1;
8408                PR->datum_index = -1;
8409                fv = SUMA_GDSET_NodeXYZ(dset, PR->iAltSel[SUMA_ENODE_0],
8410                                        SUMA_ADO_variant(ado), NULL);
8411                PR->PickXYZ[0]=fv[0]; PR->PickXYZ[1]=fv[1]; PR->PickXYZ[2]=fv[2];
8412             }
8413             break; }
8414          case GDSET_type:
8415             SUMA_S_Err("I don't expect graph dsets to be picked directly");
8416             break;
8417          case CDOM_type:
8418             SUMA_S_Err("CIFTI not picked on buffer");
8419             break;
8420          case VO_type:
8421             SUMA_S_Err("VOs not picked on buffer....");
8422             break;
8423          case MASK_type:
8424             SUMA_S_Err("Masks not picked on buffer....");
8425             break;
8426          case TRACT_type:
8427             {
8428             SUMA_TractDO *tdo=(SUMA_TractDO *)ado;
8429             int nn=0, mm=0, nnmin=-1, mmmin=-1, mmmin3=-1, oki=0, it=0, ib=0;
8430             float *scrxyz = NULL;
8431             float mindist, dist;
8432             float fmin;
8433             TAYLOR_TRACT *ttn=NULL;
8434             TAYLOR_BUNDLE *tb=NULL;
8435 
8436             oki = 0;
8437             if (!strcmp(PR->primitive,"bundles")) {
8438                ib = PR->primitive_index;
8439                SUMA_LHv("Seeking bundle %d/%d\n",
8440                            (int)PR->primitive_index, tdo->net->N_tbv);
8441                tb = TDO_BUNDLE(tdo, PR->primitive_index);
8442                if (!(oki=SUMA_Bundle_Pick_Intersect(tb, 'B', -1, sv, NULL, 0,
8443                                             &nnmin, &mmmin, &fmin, &mindist))) {
8444                   SUMA_LH("No bunlde intersection");
8445                }
8446             } else if (!strcmp(PR->primitive,"tracts")) {
8447                SUMA_LHv("Seeking tract %d/%d\n",
8448                            (int)PR->primitive_index, TDO_N_TRACTS(tdo));
8449                if (Network_1T_to_TB(tdo->net,
8450                            (int)PR->primitive_index, &it, &ib, NULL, NULL) < 0) {
8451                   SUMA_S_Err("Failed to resolve tract index");
8452                } else {
8453                   tb = TDO_BUNDLE(tdo, ib);
8454                   if (!(oki=SUMA_Bundle_Pick_Intersect(tb, 'B', it, sv, NULL, 0,
8455                                             &nnmin, &mmmin, &fmin, &mindist))) {
8456                      SUMA_LH("No tract intersection");
8457                   }
8458                }
8459             }
8460             if (oki) {
8461                if (nnmin > -1) {
8462                   mmmin3=3*mmmin;
8463                   ttn = tb->tracts+nnmin;
8464                   if (fmin != 0.0f) {
8465                      PR->PickXYZ[0]=ttn->pts[mmmin3+0]+
8466                                  fmin*(ttn->pts[mmmin3+3]-ttn->pts[mmmin3]);
8467                      PR->PickXYZ[1]=ttn->pts[mmmin3+1]+
8468                                  fmin*(ttn->pts[mmmin3+4]-ttn->pts[mmmin3+1]);
8469                      PR->PickXYZ[2]=ttn->pts[mmmin3+2]+
8470                                  fmin*(ttn->pts[mmmin3+5]-ttn->pts[mmmin3+2]);
8471                   } else {
8472                      /* from the quick search, no fmin used*/
8473                      PR->PickXYZ[0]=ttn->pts[mmmin3+0];
8474                      PR->PickXYZ[1]=ttn->pts[mmmin3+1];
8475                      PR->PickXYZ[2]=ttn->pts[mmmin3+2];
8476                   }
8477                   PR->iAltSel[SUMA_TRC_PNT] = mmmin;
8478                   PR->iAltSel[SUMA_BUN_TRC] = nnmin;
8479                   PR->iAltSel[SUMA_NET_BUN] = ib;
8480                   PR->datum_index = Network_PTB_to_1P(tdo->net,
8481                                                       PR->iAltSel[SUMA_TRC_PNT],
8482                                                       PR->iAltSel[SUMA_BUN_TRC],
8483                                                       PR->iAltSel[SUMA_NET_BUN]);
8484                   PR->iAltSel[SUMA_NET_TRC] = Network_TB_to_1T(tdo->net,
8485                                                       PR->iAltSel[SUMA_BUN_TRC],
8486                                                       PR->iAltSel[SUMA_NET_BUN]);
8487                   SUMA_LHv("Bundle %ld intersected, tract %ld, "
8488                            "point %ld, tract in net %ld. \n"
8489                            "Point NetID: %ld\n"
8490                            "XYZ[%.3f %.3f %.3f], fmin=%f\n",
8491                            PR->iAltSel[SUMA_NET_BUN],
8492                            PR->iAltSel[SUMA_BUN_TRC],
8493                            PR->iAltSel[SUMA_TRC_PNT],
8494                            PR->iAltSel[SUMA_NET_TRC], PR->datum_index,
8495                            PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2], fmin);
8496 
8497                   #if 0 /* Just to debug reverse lookup */
8498                   if (Network_1P_to_PTB(tdo->net, PR->datum_index,
8499                                          &mmmin, &nnmin, &nn, NULL) < 0) {
8500                      SUMA_S_Err("Failed in reverse lookup test");
8501                   } else {
8502                      SUMA_LHv("Inverse lookup: %ld --> P %d, T %d, B %d\n",
8503                               PR->datum_index, mmmin, nnmin, nn);
8504                   }
8505                   #endif
8506                }
8507             }
8508             f = fmin;
8509             break; }
8510          default:
8511             SUMA_S_Warnv("Not ready to get location for %s\n",
8512                       SUMA_ObjectTypeCode2ObjectTypeName(codf->ref_do_type));
8513             break;
8514       }
8515    }
8516 
8517    /* report */
8518    if (codf) {
8519          SUMA_S_Notev("\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n"
8520                    "DO pick: colid (%ld=[%d %d %d %d]) \n"
8521                    "      is in    <%s, %s, %s>, f=%1.3f\n"
8522                    "   datum = %ld, iAltSel = [",
8523                    n4, colid[0], colid[1], colid[2], colid[3],
8524                    cod->Label, cod->variant, cod->primitive, f,
8525                    PR->datum_index);
8526         for (iii=0; iii<SUMA_N_IALTSEL_TYPES; ++iii)
8527             fprintf(SUMA_STDOUT, "%ld, ", PR->iAltSel[iii]);
8528         fprintf(SUMA_STDOUT, "]\n   dAltSel = [");
8529         for (iii=0; iii<SUMA_N_DALTSEL_TYPES; ++iii)
8530             fprintf(SUMA_STDOUT, "%.3f, ", PR->dAltSel[iii]);
8531         fprintf(SUMA_STDOUT, "]\n"
8532                       "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
8533    }
8534 
8535    SUMA_RETURN(PR);
8536 }
8537 
SUMA_New_Pick_Result(SUMA_PICK_RESULT * PR)8538 SUMA_PICK_RESULT *SUMA_New_Pick_Result(SUMA_PICK_RESULT *PR)
8539 {
8540    static char FuncName[]={"SUMA_New_Pick_Result"};
8541 
8542    // fprintf(stderr, "%s\n", FuncName);
8543    int i;
8544    if (!PR) {
8545       PR = (SUMA_PICK_RESULT *)SUMA_calloc(1,sizeof(SUMA_PICK_RESULT));
8546    }
8547    PR->primitive_index = -1;
8548    PR->datum_index = -1;
8549    for (i=0; i<SUMA_N_IALTSEL_TYPES; ++i) PR->iAltSel[i] = -1;
8550    for (i=0; i<SUMA_N_DALTSEL_TYPES; ++i) PR->dAltSel[i] = 0.0;
8551    SUMA_ifree(PR->primitive);
8552    SUMA_ifree(PR->ado_idcode_str);
8553    /* Imprint with event structure */
8554    PR->evr = (SUMA_EVENT *)malloc(sizeof(SUMA_EVENT));
8555    if (SUMAg_CF->lev) memcpy(PR->evr, SUMAg_CF->lev, sizeof(SUMA_EVENT));
8556    else memset(PR->evr, 0, sizeof(SUMA_EVENT));
8557    /* SUMA_ShowEvent(PR->evr, 0, "From New Pick Result\n"); */
8558    return(PR);
8559 }
8560 
SUMA_free_PickResult(SUMA_PICK_RESULT * PR)8561 SUMA_PICK_RESULT *SUMA_free_PickResult(SUMA_PICK_RESULT *PR)
8562 {
8563    static char FuncName[]={"SUMA_free_PickResult"};
8564    SUMA_ENTRY;
8565 
8566    if (!PR) SUMA_RETURN(PR);
8567 
8568    if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8569         fprintf(stderr, "### SUMA_free_PickResult: Free PR->primitive\n");
8570    if (PR->primitive) SUMA_ifree(PR->primitive);
8571    if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8572         fprintf(stderr, "### SUMA_free_PickResult: Free PR->ado_idcode_str\n");
8573    if (PR->ado_idcode_str) SUMA_ifree(PR->ado_idcode_str);
8574    if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8575         fprintf(stderr, "### SUMA_free_PickResult: Free PR->dset_idcode_str\n");
8576    if (PR->dset_idcode_str){
8577         SUMA_ifree(PR->dset_idcode_str);
8578        if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8579             fprintf(stderr, "### SUMA_free_PickResult: Free PR->evr\n");
8580         if (PR->evr) SUMA_ifree(PR->evr);
8581     }
8582 
8583    SUMA_free(PR);
8584 
8585    SUMA_RETURN(NULL);
8586 }
8587 
SUMA_ADO_StorePickResult(SUMA_ALL_DO * ado,SUMA_PICK_RESULT ** PRP)8588 SUMA_Boolean SUMA_ADO_StorePickResult(SUMA_ALL_DO *ado, SUMA_PICK_RESULT **PRP)
8589 {
8590    static char FuncName[]={"SUMA_ADO_StorePickResult"};
8591 
8592    SUMA_ENTRY;
8593 
8594    // fprintf(stderr, "%s\n", FuncName);
8595 
8596    if (!PRP || !*PRP) SUMA_RETURN(NOPE);
8597 
8598    switch (ado->do_type) {
8599       case SO_type: {
8600          SUMA_SURF_SAUX *Saux = SUMA_ADO_SSaux(ado);
8601          if (!Saux){
8602             SUMA_S_Err("NULL Saux!!!, don't let that happen");
8603             SUMA_RETURN(NOPE);
8604          }
8605          if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8606             fprintf(stderr, "### SUMA_free_PickResult\n");
8607          SUMA_free_PickResult(Saux->PR);
8608          Saux->PR = *PRP; *PRP = NULL;
8609          SUMA_RETURN(YUP);
8610          break; }
8611       case CDOM_type: {
8612          SUMA_CIFTI_SAUX *Saux = SUMA_ADO_CSaux(ado);
8613          SUMA_free_PickResult(Saux->PR);
8614          Saux->PR = *PRP; *PRP = NULL;
8615          SUMA_RETURN(YUP);
8616          break; }
8617       case GDSET_type: {
8618          SUMA_DSET *dset=(SUMA_DSET *)ado;
8619          SUMA_GRAPH_SAUX *Saux = SDSET_GSAUX(dset);
8620          /* Is the selection type changed? If so, then
8621          you need to flush the pick buffer */
8622 
8623          if (Saux->PR) {
8624             if ( (Saux->PR->datum_index * (*PRP)->datum_index < 0) ||
8625                  ((*PRP)->datum_index == -1 &&
8626                   (Saux->PR->iAltSel[SUMA_ENODE_0] !=
8627                               (*PRP)->iAltSel[SUMA_ENODE_0])) )  {
8628                /* Going from edge selection to node selection, in general
8629                   But there is no need to get picky */
8630               SUMA_FlushPickBufferForDO((SUMA_ALL_DO *)SUMA_find_Dset_GLDO(dset,
8631                                                  "G3D",NULL));
8632             }
8633          }
8634          SUMA_free_PickResult(Saux->PR);
8635          Saux->PR = *PRP; *PRP = NULL;
8636          SUMA_RETURN(YUP);
8637          break; }
8638       case GRAPH_LINK_type:
8639          SUMA_RETURN(SUMA_ADO_StorePickResult(
8640             (SUMA_ALL_DO*)SUMA_find_GLDO_Dset(
8641                            (SUMA_GraphLinkDO*)ado),PRP));
8642          break;
8643       case TRACT_type: {
8644          SUMA_TRACT_SAUX *Saux = SUMA_ADO_TSaux(ado);
8645          SUMA_free_PickResult(Saux->PR);
8646          Saux->PR = *PRP; *PRP = NULL;
8647          SUMA_RETURN(YUP);
8648          break; }
8649       case MASK_type: {
8650          SUMA_MASK_SAUX *Saux = SUMA_ADO_MSaux(ado);
8651          if (Saux) {
8652             SUMA_free_PickResult(Saux->PR);
8653             Saux->PR = *PRP; *PRP = NULL;
8654          } else {
8655             SUMA_S_Err("NULL Saux!!!, don't let that happen");
8656             SUMA_RETURN(NOPE);
8657          }
8658          SUMA_RETURN(YUP);
8659          break; }
8660       case VO_type: {
8661          SUMA_VOL_SAUX *Saux = SUMA_ADO_VSaux(ado);
8662          if (!(*PRP)->primitive) {
8663             SUMA_S_Err("NULL primitve not acceptable for VOs");
8664             break;
8665          }
8666          if (!strcmp((*PRP)->primitive,"voxel")) {
8667             SUMA_free_PickResult(Saux->PR);
8668             Saux->PR = *PRP; *PRP = NULL;
8669             SUMA_RETURN(YUP);
8670          } else if (!strcmp((*PRP)->primitive,"cutplane")) {
8671             SUMA_free_PickResult(Saux->PRc);
8672             Saux->PRc = *PRP; *PRP = NULL;
8673             SUMA_RETURN(YUP);
8674          } else {
8675             SUMA_S_Err("Bad primitive %s for VO", (*PRP)->primitive);
8676             SUMA_DUMP_TRACE("Who dunit?");
8677          }
8678          break; }
8679       default:
8680          SUMA_S_Errv("Note ready for type %s\n", ADO_TNAME(ado));
8681          break;
8682    }
8683    SUMA_RETURN(NOPE);
8684 }
8685 
SUMA_ADO_GetPickResult(SUMA_ALL_DO * ado,char * primitive)8686 SUMA_PICK_RESULT * SUMA_ADO_GetPickResult(SUMA_ALL_DO *ado, char *primitive)
8687 {
8688    static char FuncName[]={"SUMA_ADO_GetPickResult"};
8689    SUMA_PICK_RESULT *PR=NULL;
8690 
8691    SUMA_ENTRY;
8692 
8693    // fprintf(stderr, "%s\n", FuncName);
8694 
8695    if (!ado) SUMA_RETURN(NULL);
8696    if (!primitive) primitive = "none";
8697 
8698    switch (ado->do_type) {
8699       case SO_type:{
8700          SUMA_SURF_SAUX *Saux = SUMA_ADO_SSaux(ado);
8701          SUMA_RETURN(Saux->PR);
8702          break; }
8703       case CDOM_type: {
8704          SUMA_CIFTI_SAUX *Saux = SUMA_ADO_CSaux(ado);
8705          SUMA_RETURN(Saux->PR);
8706          break; }
8707       case GDSET_type: {
8708          SUMA_DSET *dset=(SUMA_DSET *)ado;
8709          SUMA_GRAPH_SAUX *Saux = SDSET_GSAUX(dset);
8710          SUMA_RETURN(Saux->PR);
8711          break; }
8712       case GRAPH_LINK_type:
8713          SUMA_RETURN(SUMA_ADO_GetPickResult(
8714            (SUMA_ALL_DO*)SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)ado),primitive));
8715          break;
8716       case TRACT_type: {
8717          SUMA_TRACT_SAUX *Saux = SUMA_ADO_TSaux(ado);
8718          SUMA_RETURN(Saux->PR);
8719          break; }
8720       case MASK_type: {
8721          SUMA_MASK_SAUX *Saux = SUMA_ADO_MSaux(ado);
8722          SUMA_RETURN(Saux->PR);
8723          break; }
8724       case VO_type: {
8725          SUMA_VOL_SAUX *Saux = SUMA_ADO_VSaux(ado);
8726          if (!strcmp(primitive,"voxel")) SUMA_RETURN(Saux->PR);
8727          else if (!strcmp(primitive,"cutplane")) SUMA_RETURN(Saux->PRc);
8728          else {
8729             SUMA_S_Err("Bad primitive %s for VO", primitive);
8730          }
8731          break; }
8732       default:
8733          SUMA_S_Errv("Note ready for type %s\n", ADO_TNAME(ado));
8734          break;
8735    }
8736    SUMA_RETURN(NOPE);
8737 }
8738 
8739 
8740 /*!
8741 */
SUMA_Show_Pick_Colid_List(DList * pick_colid_list,FILE * fout)8742 void SUMA_Show_Pick_Colid_List(DList *pick_colid_list, FILE *fout)
8743 {
8744    static char FuncName[]={"SUMA_Show_Pick_Colid_List"};
8745    char *s = NULL;
8746 
8747    SUMA_ENTRY;
8748 
8749    // fprintf(stderr, "%s\n", FuncName);
8750    if (!fout) fout = SUMA_STDOUT;
8751 
8752    s = SUMA_Pick_Colid_List_Info(pick_colid_list);
8753    fprintf(fout, "%s", s);
8754    SUMA_ifree(s);
8755 
8756    SUMA_RETURNe;
8757 }
8758 
SUMA_Pick_Colid_List_Info(DList * pick_colid_list)8759 char *SUMA_Pick_Colid_List_Info (DList *pick_colid_list)
8760 {
8761    static char FuncName[]={"SUMA_Pick_Colid_List_Info"};
8762    char *s = NULL;
8763    SUMA_STRING *SS = NULL;
8764    SUMA_SurfaceObject *SO=NULL;
8765    SUMA_DO_Types do_type;
8766    void *vv=NULL;
8767    SUMA_DSET *dset=NULL;
8768    DListElmt *el=NULL;
8769    SUMA_ALL_DO *ado=NULL;
8770    SUMA_COLID_OFFSET_DATUM *cod=NULL;
8771 
8772    SUMA_ENTRY;
8773 
8774    // fprintf(stderr, "%s\n", FuncName);
8775 
8776    SS = SUMA_StringAppend(NULL, NULL);
8777 
8778    if (!pick_colid_list) {
8779       SS = SUMA_StringAppend(SS,"NULL pick_colid_list"); goto CLEAN_RETURN;
8780    }
8781    if (!dlist_size(pick_colid_list)) {
8782       SS = SUMA_StringAppend(SS,"Empty pick_colid_list"); goto CLEAN_RETURN;
8783    }
8784    SS = SUMA_StringAppend_va(SS,"DO Pick List of %d elements\n",
8785                               dlist_size(pick_colid_list));
8786    do {
8787       if (!el) el = dlist_head(pick_colid_list);
8788       else el = dlist_next(el);
8789       if (!el || !el->data) {
8790          SS = SUMA_StringAppend(SS, "   NULL element!");
8791       } else {
8792          cod = (SUMA_COLID_OFFSET_DATUM *)el->data;
8793          SS = SUMA_StringAppend_va(SS,"   DO %s, Primitive %s, [%ld to %ld]\n",
8794                                           cod->Label, cod->primitive,
8795                                           cod->i0, cod->i1);
8796          vv = SUMA_Picked_reference_object(cod, &do_type);
8797          switch (do_type) {
8798             case MD_DSET_type:
8799                dset = (SUMA_DSET *)vv;
8800                SS = SUMA_StringAppend_va(SS,
8801                         "     Reference object is a %s dataset labeled %s "
8802                         "(reference type %s)\n",
8803                         "Multi Domain",
8804                         SDSET_LABEL(dset),
8805                         SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8806                break;
8807             case ANY_DSET_type:
8808             case GDSET_type:
8809                dset = (SUMA_DSET *)vv;
8810                SS = SUMA_StringAppend_va(SS,
8811                         "     Reference object is a %s dataset labeled %s "
8812                         "(reference type %s)\n",
8813                         SUMA_isCIFTIDset(dset) ? "CIFTI" :
8814                               (SUMA_isGraphDset(dset) ? "Graph":"Surface-based"),
8815                         SDSET_LABEL(dset),
8816                         SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8817                break;
8818             case SO_type:
8819                SO = (SUMA_SurfaceObject *)vv;
8820                SS = SUMA_StringAppend_va(SS,
8821                         "     Reference object is a surface labeled %s "
8822                         "(reference type %s)\n",
8823                         SO->Label,
8824                         SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8825                break;
8826             case GRAPH_LINK_type:
8827                ado = (SUMA_ALL_DO *)vv;
8828                   SS = SUMA_StringAppend_va(SS,
8829                         "     Reference object is a graph link labeled %s "
8830                         "(reference type %s)\n",
8831                         SUMA_ADO_Label(ado),
8832                         SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8833                break;
8834             case TRACT_type:
8835                SS = SUMA_StringAppend_va(SS,
8836                         "     Reference object is a tract object labeled %s "
8837                         "(reference type %s)\n",
8838                         SUMA_ADO_Label(ado),
8839                         SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8840                break;
8841             case CDOM_type:
8842                SS = SUMA_StringAppend_va(SS,
8843                         "     Reference object is a CIFTI DO labeled %s "
8844                         "(reference type %s)\n",
8845                         SUMA_ADO_Label(ado),
8846                         SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8847                break;
8848             case MASK_type:
8849                SS = SUMA_StringAppend_va(SS,
8850                         "     Reference object is a mask object labeled %s "
8851                         "(reference type %s)\n",
8852                         SUMA_ADO_Label(ado),
8853                         SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8854                break;
8855             default:
8856                SS = SUMA_StringAppend_va(SS,
8857                      "     Parent, not surface or dset.\n");
8858                break;
8859          }
8860       }
8861    } while (el != dlist_tail(pick_colid_list));
8862 
8863    CLEAN_RETURN:
8864    SUMA_SS2S(SS,s);
8865 
8866    SUMA_RETURN(s);
8867 }
8868 
SUMA_MarkLineDOsIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)8869 int SUMA_MarkLineDOsIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8870                                int IgnoreSameNode)
8871 {
8872    static char FuncName[]={"SUMA_MarkLineDOsIntersect"};
8873 
8874    SUMA_PICK_RESULT *PR = NULL;
8875    SUMA_ALL_DO *ado = NULL;
8876    int ans;
8877 
8878    SUMA_ENTRY;
8879 
8880    // fprintf(stderr, "%s\n", FuncName);
8881    SUMA_S_Warn("Do not call me anymore."
8882                "Go via SUMA_ComputeLineDOsIntersect. "
8883                "This is left here for testing purposes");
8884    ans = SUMA_ComputeLineDOsIntersect(sv, dov, IgnoreSameNode, &ado);
8885    if (ans <= 0) {
8886       SUMA_RETURN(ans);
8887    }
8888    /* just for temporary testing, get PR back from list and apply it */
8889    PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
8890    ans = SUMA_Apply_PR(sv, &PR);
8891 
8892    SUMA_RETURN(ans);
8893 }
8894 
8895 /*!
8896    Determines the intersection between pickline and displayable objects
8897 */
SUMA_ComputeLineDOsIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)8898 int SUMA_ComputeLineDOsIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8899                                   int IgnoreSameNode, SUMA_ALL_DO **pado)
8900 {
8901    static char FuncName[]={"SUMA_ComputeLineDOsIntersect"};
8902    int i, j, *MembDOs=NULL, N_MembDOs;
8903    SUMA_DO_Types ttv[12];
8904    SUMA_PICK_RESULT *hit=NULL;
8905    GLubyte colans[4];
8906    SUMA_COLID_OFFSET_DATUM *codf=NULL;
8907    SUMA_ALL_DO *ado=NULL;
8908    SUMA_EngineData *ED = NULL;
8909    DList *list = NULL;
8910    DListElmt *SetNodeElem = NULL, *Location=NULL;
8911    SUMA_SurfaceObject *SO = NULL;
8912    SUMA_Boolean NodeIgnored = NOPE;
8913    SUMA_Boolean LocalHead = NOPE;
8914 
8915    SUMA_ENTRY;
8916 
8917    // fprintf(stderr, "%s\n", FuncName);
8918 
8919    if (!sv || !dov) SUMA_RETURN(-1);
8920 
8921    SUMA_LH("DO pickin");
8922 
8923    if (sv->PickPix[0] < 0 || sv->PickPix[1] < 0 ||
8924        sv->PickPix[0] >= sv->X->aWIDTH ||  sv->PickPix[1] >= sv->X->aHEIGHT) {
8925       /* This happens when you select and drag outside of the viewing area
8926       Don't return in error */
8927       SUMA_LHv("Bad PickPix=[%d %d] for viewport %d %d\n",
8928                  sv->PickPix[0], sv->PickPix[1], sv->X->aWIDTH, sv->X->aHEIGHT);
8929       SUMA_RETURN(0);
8930    }
8931 
8932    /* Any pickable DO, other than brain surfaces, that does not require
8933       pick buffer picking? */
8934    ttv[0] = GRAPH_LINK_type; ttv[1] = NOT_SET_type;
8935    MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
8936    for (i=0; i<N_MembDOs; ++i) {
8937       if ((hit = SUMA_WhatWasPicked_FrameSO(sv, MembDOs[i]))) {
8938          if ( hit->datum_index < 0 && (
8939              ( hit->iAltSel[SUMA_ENODE_0]>=0 &&
8940                hit->iAltSel[SUMA_ENODE_1]>=0)) ) {
8941             /* You have selected a point pair that has no edge defined.
8942                This can happen when you click on an empty cell in the matrix */
8943             hit = SUMA_free_PickResult(hit);
8944          } else {
8945             /* got something, leave.
8946                Perhaps in the future will need to go through
8947             all stack (slices) and pick the best one ... */
8948             ado = iDO_ADO(MembDOs[i]);
8949             if (pado) *pado = ado;
8950             break;
8951          }
8952       }
8953    }
8954    SUMA_ifree(MembDOs);
8955 
8956    if (!hit) { /* nothing found above, go for pick buffer */
8957       if (!SUMA_PickBuffer(sv, 2, dov)) { /* refresh the buffer only if needed */
8958          SUMA_S_Err("Failed to refresh buffer");
8959          SUMA_RETURN(-1);
8960       }
8961 
8962       if (!sv->pickrenpix4) {
8963          SUMA_S_Err("Could not form pickrenpix4, should this be an error?");
8964          SUMA_RETURN(-1);
8965       }
8966       if (!sv->pick_colid_list || !dlist_size(sv->pick_colid_list)) {
8967          SUMA_LH("No such pickable objects");
8968       } else {
8969          /* get pixel at click */
8970          i = sv->PickPix[0]; j = sv->PickPix[1];
8971          if (SUMA_GetColidInPickBuffer4(sv->pickrenpix4,
8972                               sv->X->aWIDTH, sv->X->aHEIGHT,
8973                               &i, &j, 2, colans)) {
8974             if (LocalHead) {
8975                /* Just for debugging, draw the crosshair point */
8976                SUMA_MarkPickInBuffer4(sv, 1, NULL);
8977                SUMA_LHv("User pixel selection: \n"
8978                         "  closest hit to click at %d %d was from %d %d\n"
8979                         "  colid = %d %d %d %d \n",
8980                         sv->PickPix[0], sv->PickPix[1], i, j,
8981                         colans[0] , colans[1],
8982                         colans[2] , colans[3]);
8983             }
8984             /* so what was that you touched. Note hit is never
8985                returned as null. */
8986             hit = SUMA_WhatWasPicked(sv, colans, &codf, i, j, NULL);
8987             if (!hit || !hit->ado_idcode_str) {
8988                SUMA_LH("Not hit found.");
8989             } else {
8990                if (!(ado = iDO_ADO(SUMA_Picked_DO_ID(codf)))) {
8991                   SUMA_S_Err("Could not locate object in codf (%s) /hit (%s)!",
8992                             codf->ref_idcode_str, hit->ado_idcode_str);
8993                   SUMA_free_PickResult(hit); hit = NULL;
8994                } else {
8995                   if (pado) *pado = ado;
8996                }
8997             }
8998          } else {
8999             SUMA_LH("There is no there there\n");
9000             hit = NULL;
9001          }
9002       }
9003    }
9004 
9005    if (hit && ado) {
9006       SUMA_LH("Adding hit to list");
9007       if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &hit)) {
9008          SUMA_S_Err("Failed to add selected ado");
9009          SUMA_RETURN(-1);
9010       }
9011       SUMA_RETURN(1);
9012    } else SUMA_RETURN(0);
9013 }
9014 
SUMA_Apply_PR_DO(SUMA_SurfaceViewer * sv,SUMA_ALL_DO * ado,SUMA_PICK_RESULT ** PRi)9015 int SUMA_Apply_PR_DO(SUMA_SurfaceViewer *sv, SUMA_ALL_DO *ado,
9016                      SUMA_PICK_RESULT **PRi)
9017 {
9018    static char FuncName[]={"SUMA_Apply_PR_DO"};
9019    DList *list = NULL;
9020    DListElmt *SetNodeElem = NULL, *Location=NULL;
9021    SUMA_Boolean NodeIgnored = NOPE;
9022    SUMA_PICK_RESULT *PR;
9023    int NP=0, ip=0, it=-1, id = 0, iv3[3], iv15[15];
9024    SUMA_EngineData *ED = NULL;
9025    SUMA_Boolean LocalHead = NOPE;
9026 
9027    SUMA_ENTRY;
9028 
9029    // fprintf(stderr, "%s\n", FuncName);
9030    SUMA_LH("Here");
9031    if (!sv || !ado || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
9032 
9033    PR = *PRi; /* keep local copy */
9034    /* Store the PR in ado, hide it from return potential */
9035    SUMA_ADO_StorePickResult(ado, PRi);
9036 
9037    SUMA_LHv("Hit object type %s, label %s\n",
9038          SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type),
9039          SUMA_ADO_Label(ado));
9040 
9041    sv->Focus_DO_ID = ADO_iDO(ado);
9042    SUMA_UpdateViewerTitle(sv);
9043 
9044    /* if the surface controller is open, update it */
9045    if (SUMA_isADO_Cont_Realized(ado))
9046       SUMA_Init_SurfCont_SurfParam(ado);
9047 
9048    /* print nodes about the pick */
9049    switch (ado->do_type) {
9050       case TRACT_type:
9051    fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9052    fprintf(SUMA_STDOUT, "Selected network %s (Focus_DO_ID # %d).\n"
9053                         "Point %ld, (Bundle %ld, Tract %ld, Point %ld)\n",
9054       ADO_LABEL(ado), sv->Focus_DO_ID, PR->datum_index,
9055       PR->iAltSel[SUMA_NET_BUN], PR->iAltSel[SUMA_BUN_TRC],
9056       PR->iAltSel[SUMA_TRC_PNT]);
9057    fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
9058    fprintf(SUMA_STDOUT, "%f, %f, %f\n",
9059       PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
9060    fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9061          break;
9062       case MASK_type:
9063    fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9064    fprintf(SUMA_STDOUT, "Selected mask %s (Focus_DO_ID # %d).\n",
9065       ADO_LABEL(ado), sv->Focus_DO_ID);
9066    fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
9067    fprintf(SUMA_STDOUT, "%f, %f, %f\n",
9068       PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
9069    fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9070          break;
9071       case GRAPH_LINK_type:
9072    fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9073    fprintf(SUMA_STDOUT, "Selected Graph Dset %s (Focus_DO_ID # %d).\n"
9074                         "Edge %ld, (P0 %ld, P1 %ld)\n",
9075       ADO_LABEL(ado), sv->Focus_DO_ID, PR->datum_index,
9076       PR->iAltSel[SUMA_ENODE_0], PR->iAltSel[SUMA_ENODE_1]);
9077    fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
9078    fprintf(SUMA_STDOUT, "%f, %f, %f\n",
9079       PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
9080    fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9081          break;
9082       default:
9083    SUMA_S_Err("Not yet set to report on %s", ADO_LABEL(ado));
9084          break;
9085    }
9086 
9087    /* Based on what you selected, update controller */
9088    /* Set the Nodeselection at the closest node */
9089    if (PR->datum_index >= 0 ||
9090        (PR->datum_index == -1 &&
9091         PR->iAltSel[SUMA_ENODE_0] >= 0 &&
9092         PR->iAltSel[SUMA_ENODE_1] == -1) ) {
9093                      /* 2nd condition is when only edge node is selected.
9094                         We insist on PR->iAltSel[SUMA_ENODE_1] == -1 otherwise
9095                         we would have picked a cell in the matrix for which
9096                         there is no data, hence we have ENODE_0, and ENODE_1,
9097                         but datum_index = -1 */
9098       it = (int)PR->datum_index;
9099       if (!list) list = SUMA_CreateList();
9100       if (PR->ignore_same_datum &&
9101             SUMA_ADO_SelectedDatum(ado, NULL, NULL) == it) {
9102          SUMA_LHv("Ignoring identical datum selection %d on object %s\n",
9103                   SUMA_ADO_SelectedDatum(ado, NULL, NULL), SUMA_ADO_Label(ado));
9104          NodeIgnored = YUP;
9105       } else {
9106          ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
9107          SetNodeElem = SUMA_RegisterEngineListCommand (  list, ED,
9108                                                 SEF_i, (void*)&it,
9109                                                 SES_Suma, (void *)sv, NOPE,
9110                                                 SEI_Head, NULL);
9111          if (!SetNodeElem) {
9112             fprintf( SUMA_STDERR,
9113                      "Error %s: Failed to register SetNodeElem\n", FuncName);
9114             SUMA_RETURN (-1);
9115          } else {
9116             SUMA_RegisterEngineListCommand (  list, ED,
9117                                               SEF_ngr, NULL,
9118                                               SES_Suma, (void *)sv, NOPE,
9119                                               SEI_In, SetNodeElem);
9120          }
9121          switch (ado->do_type) {
9122             case TRACT_type:
9123                iv15[SUMA_NET_BUN] = (int)PR->iAltSel[SUMA_NET_BUN];
9124                iv15[SUMA_BUN_TRC] = (int)PR->iAltSel[SUMA_BUN_TRC];
9125                iv15[SUMA_TRC_PNT] = (int)PR->iAltSel[SUMA_TRC_PNT];
9126                iv15[SUMA_NET_TRC] = (int)PR->iAltSel[SUMA_NET_TRC];
9127                SUMA_RegisterEngineListCommand (  list, ED,
9128                                                  SEF_iv15, (void *)iv15,
9129                                                  SES_Suma, (void *)sv, NOPE,
9130                                                  SEI_In, SetNodeElem);
9131                break;
9132             case SO_type:
9133             case VO_type:
9134                /* handled in separate function */
9135                break;
9136             default:
9137                SUMA_LH("No aux set here for type %s of %s\n",
9138                         ADO_TNAME(ado), SUMA_ADO_Label(ado));
9139                break;
9140          }
9141 
9142       }
9143    }
9144 
9145 
9146    /* Set the selected edge node (cunningly in recycled selected face set) */
9147    it = PR->iAltSel[SUMA_ENODE_0];
9148    if (!list) list = SUMA_CreateList();
9149    ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
9150    if (!SUMA_RegisterEngineListCommand (  list, ED,
9151                                           SEF_i, (void*)&it,
9152                                           SES_Suma, (void *)sv, NOPE,
9153                                           SEI_Head, NULL)) {
9154       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9155       SUMA_RETURN (-1);
9156    }
9157 
9158    /* Now set the cross hair position at the intersection*/
9159    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
9160    if (!(Location = SUMA_RegisterEngineListCommand (  list, ED,
9161                                           SEF_fv3, (void*)PR->PickXYZ,
9162                                           SES_Suma, (void *)sv, NOPE,
9163                                           SEI_Head, NULL))) {
9164       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9165       SUMA_RETURN (-1);
9166    }
9167    /* and add the ado with this location, needed for VisX business*/
9168    SUMA_RegisterEngineListCommand (  list, ED,
9169                                            SEF_vp, (void *)ado,
9170                                            SES_Suma, (void *)sv, NOPE,
9171                                            SEI_In, Location);
9172    /* attach the cross hair to the selected ado */
9173    iv3[0] = SUMA_whichDO(PR->ado_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
9174    iv3[1] = PR->datum_index;
9175    iv3[2] = PR->iAltSel[SUMA_ENODE_0];
9176    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
9177    if (!SUMA_RegisterEngineListCommand (  list, ED,
9178                                           SEF_iv3, (void*)iv3,
9179                                           SES_Suma, (void *)sv, NOPE,
9180                                           SEI_Head, NULL)) {
9181       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9182       SUMA_RETURN (-1);
9183    }
9184 
9185    /* check to see if AFNI needs to be notified */
9186    /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
9187       Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
9188    if (  ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
9189            sv->LinkAfniCrossHair )                             ||
9190          ( SUMAg_CF->Connected_v[SUMA_HALLO_SUMA_LINE])        ||
9191          ( SUMAg_CF->Connected_v[SUMA_INSTA_TRACT_LINE])    ) {
9192       if (LocalHead)
9193          fprintf(SUMA_STDERR,
9194                   "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
9195       /* register a call to SetAfniCrossHair */
9196       if (!list) list = SUMA_CreateList();
9197       it = SUMA_ShftCont_Event(PR->evr);
9198       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
9199       if (!SUMA_RegisterEngineListCommand (  list, ED,
9200                                           SEF_i, (void*)&it,
9201                                           SES_Suma, (void *)sv, NOPE,
9202                                           SEI_Tail, NULL)) {
9203          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9204          SUMA_RETURN (-1);
9205       }
9206       if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
9207          SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
9208          DListElmt *Location=NULL;
9209          SUMA_LH("Might be telling afni about mask...");
9210          if (ado && ado->do_type == MASK_type) {
9211             SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
9212             ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
9213             if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
9214                                                 SEF_fv3, (void*)mdo->cen,
9215                                                 SES_Suma, (void *)sv, NOPE,
9216                                                 SEI_Tail, NULL))) {
9217                SUMA_S_Err("Failed to register element\n");
9218                SUMA_RETURN (-1);
9219             }
9220             SUMA_RegisterEngineListCommand (  list, ED,
9221                                            SEF_s, (void *)(ADO_ID(ado)),
9222                                            SES_Suma, (void *)sv, NOPE,
9223                                            SEI_In, Location);
9224          }
9225       }
9226 
9227       if (!SUMA_Engine (&list)) {
9228          fprintf( SUMA_STDERR,
9229                   "Error %s: SUMA_Engine call failed.\n", FuncName);
9230          SUMA_RETURN (-1);
9231       }
9232    }else {
9233       if (LocalHead)
9234          fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
9235    }
9236 
9237    /* now put in a request for locking cross hair but you must do
9238       this after the node selection has been executed
9239       NOTE: You do not always have SetNodeElem because the list might
9240       get emptied in the call to AFNI notification.
9241       You should just put the next call at the end of the list.*/
9242    if (!list) list = SUMA_CreateList();
9243    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
9244    if (!SUMA_RegisterEngineListCommand (  list, ED,
9245                                           SEF_iv3, (void*)iv3,
9246                                           SES_Suma, (void *)sv, NOPE,
9247                                           SEI_Tail, NULL)) {
9248       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9249       SUMA_RETURN (-1);
9250    }
9251    if (!SUMA_Engine (&list)) {
9252       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
9253       SUMA_RETURN (-1);
9254    }
9255 
9256    SUMA_RETURN(1);
9257 }
9258 
SUMA_Apply_PR(SUMA_SurfaceViewer * sv,SUMA_PICK_RESULT ** PR)9259 int SUMA_Apply_PR(SUMA_SurfaceViewer *sv, SUMA_PICK_RESULT **PR)
9260 {
9261    static char FuncName[]={"SUMA_Apply_PR"};
9262    SUMA_ALL_DO *ado=NULL, *ado_pick=NULL;
9263    float *xyz=NULL;
9264    SUMA_Boolean LocalHead = NOPE;
9265 
9266    SUMA_ENTRY;
9267 
9268    // fprintf(stderr, "%s\n", FuncName);
9269 
9270    if (!sv || !PR || !*PR) {
9271       SUMA_S_Err("NULL input %p %p %p", sv, PR, *PR);
9272       SUMA_DUMP_TRACE("PR application");
9273       SUMA_RETURN(-1);
9274    }
9275    if (MASK_MANIP_MODE(sv)) {
9276       ado_pick = SUMA_whichADOg((*PR)->ado_idcode_str);
9277       SUMA_LH("Mask Manip Mode, moving to %f %f %f per ado %s\n",
9278                (*PR)->PickXYZ[0], (*PR)->PickXYZ[1], (*PR)->PickXYZ[2],
9279                ADO_LABEL(ado_pick));
9280       SUMA_ifree(sv->LastSel_ado_idcode_str);
9281       sv->LastSel_ado_idcode_str = SUMA_copy_string((*PR)->ado_idcode_str);
9282       /* Just move the selected mask */
9283       if (!(ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str))) {
9284          SUMA_S_Err("Yikes, got not ado for MouseMode_ado_idcode_str %s",
9285               sv->MouseMode_ado_idcode_str?sv->MouseMode_ado_idcode_str:"NULL");
9286          SUMA_RETURN(-1);
9287       }
9288       if (ado->do_type != MASK_type) {
9289          SUMA_S_Err("Bad ID for mouse mode value");
9290          SUMA_RETURN(-1);
9291       }
9292       /* Set the parent as the ado_pick */
9293       SUMA_MDO_New_parent((SUMA_MaskDO *)ado, (*PR)->ado_idcode_str,
9294                           (*PR)->datum_index);
9295 
9296       if (ado_pick->do_type == SO_type) {
9297          SUMA_SurfaceObject *SO = (SUMA_SurfaceObject *)ado_pick;
9298          /* PickXYZ might be under VisX */
9299          xyz = SO->NodeList+SO->NodeDim* (*PR)->datum_index;
9300          SUMA_MDO_New_Doppel((SUMA_MaskDO *)ado, (*PR)->PickXYZ);
9301       } else {
9302          xyz = (*PR)->PickXYZ;
9303          SUMA_MDO_New_Doppel((SUMA_MaskDO *)ado, NULL);
9304       }
9305       if (LocalHead) SUMA_DUMP_TRACE("Box motion");
9306       SUMA_NEW_MASKSTATE();
9307       SUMA_MDO_New_Cen((SUMA_MaskDO *)ado, xyz);
9308    }
9309 
9310    {
9311       ado = SUMA_whichADOg((*PR)->ado_idcode_str);
9312       SUMA_ifree(sv->LastSel_ado_idcode_str);
9313       sv->LastSel_ado_idcode_str = SUMA_copy_string((*PR)->ado_idcode_str);
9314       switch (ado->do_type) {
9315          case SO_type:
9316             SUMA_RETURN(SUMA_Apply_PR_SO(sv, (SUMA_SurfaceObject *)ado, PR));
9317             break;
9318          case VO_type:
9319             SUMA_RETURN(SUMA_Apply_PR_VO(sv, (SUMA_VolumeObject *)ado, PR));
9320             break;
9321          case GRAPH_LINK_type:
9322             SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
9323             break;
9324          case TRACT_type:
9325             SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
9326             break;
9327          case MASK_type:
9328             SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
9329             break;
9330          default:
9331             SUMA_S_Err("Not yet implemented for %s", ADO_TNAME(ado));
9332             SUMA_RETURN(-1);
9333             break;
9334       }
9335    }
9336    SUMA_RETURN(-1);
9337 }
9338 
SUMA_MarkLineMaskIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)9339 int SUMA_MarkLineMaskIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9340                                 int IgnoreSameNode)
9341 {/* determine intersection */
9342    static char FuncName[]={"SUMA_MarkLineMaskIntersect"};
9343    SUMA_PICK_RESULT *PR = NULL;
9344    SUMA_ALL_DO *ado = NULL;
9345    int ans;
9346 
9347    SUMA_ENTRY;
9348 
9349    // fprintf(stderr, "%s\n", FuncName);
9350    SUMA_S_Warn("Do not call me anymore. Follow the new selection logic");
9351    ans = SUMA_ComputeLineMaskIntersect(sv, dov, IgnoreSameNode, &ado);
9352    if (ans <= 0) {
9353       SUMA_RETURN(ans);
9354    }
9355    /* just for temporary testing, get PR back from list and apply it */
9356    PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
9357    ans = SUMA_Apply_PR(sv, &PR);
9358    SUMA_RETURN(ans);
9359 }
9360 
SUMA_ComputeLineMaskIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)9361 int SUMA_ComputeLineMaskIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9362                                       int IgnoreSameNode, SUMA_ALL_DO **pado)
9363 {/* determine intersection */
9364    static char FuncName[]={"SUMA_ComputeLineMaskIntersect"};
9365    float P0f[3], P1f[3];
9366    int NP;
9367    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
9368    float delta_t_tmp, dmin;
9369    struct timeval tt_tmp;
9370    SUMA_ALL_DO *ado=NULL;
9371    int ip, it, id, ii, N_MDOlist,
9372        MDOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
9373    char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9374    SUMA_MaskDO *MDO = NULL;
9375    SUMA_Boolean LocalHead = NOPE;
9376 
9377    SUMA_ENTRY;
9378 
9379    // fprintf(stderr, "%s\n", FuncName);
9380 
9381    P0f[0] = sv->Pick0[0];
9382    P0f[1] = sv->Pick0[1];
9383    P0f[2] = sv->Pick0[2];
9384    P1f[0] = sv->Pick1[0];
9385    P1f[1] = sv->Pick1[1];
9386    P1f[2] = sv->Pick1[2];
9387 
9388    N_MDOlist = SUMA_VisibleMDOs(sv, dov, MDOlist);
9389    if (LocalHead) {
9390       SUMA_LH("%d visible MDOs", N_MDOlist);
9391       for (ii=0; ii < N_MDOlist; ++ii) {
9392          ado = (SUMA_ALL_DO *)dov[MDOlist[ii]].OP;
9393          fprintf(SUMA_STDERR,"%d: object %d in DOv, label %s, type %s\n",
9394                   ii, MDOlist[ii], ADO_LABEL(ado), ADO_TNAME(ado));
9395       }
9396    }
9397    imin = -1;
9398    dmin = 10000000.0;
9399    for (ii=0; ii < N_MDOlist; ++ii) { /* find the closest intersection */
9400       if (LocalHead)
9401             fprintf (SUMA_STDERR,
9402                      "%s: working %d/%d shown masks ...\n",
9403                      FuncName, ii, N_MDOlist);
9404       MDO = (SUMA_MaskDO *)dov[MDOlist[ii]].OP;
9405       if (!MDO_IS_SURF(MDO) && !MDO_IS_BOX(MDO) && !MDO_IS_SPH(MDO)) {
9406          fprintf(SUMA_STDERR,
9407             "Error %s: "
9408             "Not ready to handle such MDO (%s) intersections on %s\n",
9409             FuncName, MDO->mtype, ADO_LABEL((SUMA_ALL_DO *)MDO));
9410       } if (!MDO->SO) {
9411          SUMA_S_Err("No SO buster on %s", ADO_LABEL((SUMA_ALL_DO *)MDO));
9412       } else {
9413          /* Here we're doing the intersection the lazy way, via the SO,
9414          although this can be done a lot faster in other ways for box and
9415          sphere, speed is not an issue here */
9416          SUMA_etime (&tt_tmp, 0);
9417          MTIi = SUMA_MT_intersect_triangle(P0f, P1f, MDO->SO->NodeList,
9418                                  MDO->SO->N_Node, MDO->SO->FaceSetList,
9419                                  MDO->SO->N_FaceSet, NULL, 0);
9420 
9421          delta_t_tmp = SUMA_etime (&tt_tmp, 1);
9422          SUMA_LH("Intersection took %f seconds with %s.\n",
9423                delta_t_tmp,
9424                ADO_LABEL((SUMA_ALL_DO *)dov[MDOlist[ii]].OP));
9425 
9426          if (MTIi == NULL) {
9427             fprintf(SUMA_STDERR,
9428                      "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
9429             SUMA_RETURN (-1);
9430          }
9431 
9432          if (MTIi->N_hits) {
9433             /* decide on the closest surface to the clicking point */
9434             if (MTIi->t[MTIi->ifacemin] < dmin) {
9435                if (LocalHead)
9436                   fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
9437                            FuncName, ii);
9438                dmin = MTIi->t[MTIi->ifacemin];
9439                imin = MDOlist[ii];
9440                MTI = MTIi;
9441             }else {
9442                /* not good, toss it away */
9443                SUMA_LH("ii=%d not any closer (%f vs %f). freeing MTIi...\n",
9444                         ii,MTIi->t[MTIi->ifacemin], dmin);
9445                MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9446             }
9447          }else {
9448             /* not good, toss it away */
9449            if (LocalHead)
9450                fprintf (SUMA_STDERR,
9451                         "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
9452            MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9453         }
9454       }
9455     }
9456 
9457    if (LocalHead)
9458       fprintf (SUMA_STDERR,
9459                "%s: Closest surface is indexed %d in DOv.\n", FuncName, imin);
9460 
9461    if (imin >= 0) {
9462       SUMA_PICK_RESULT *PR;
9463       SUMA_ALL_DO *ado;
9464       if (!(ado = iDO_ADO(imin))) {
9465          SUMA_S_Err("NULL ado at this point? imin = %d", imin);
9466          SUMA_RETURN(-1);
9467       }
9468       PR = SUMA_New_Pick_Result(NULL);
9469       if (pado) *pado = ado; /* user want answer back */
9470       PR->ado_idcode_str = SUMA_copy_string(ADO_ID(ado));
9471       PR->datum_index = MTI->inodemin;
9472       PR->ignore_same_datum = IgnoreSameNode;
9473       PR->iAltSel[SUMA_SURF_TRI] = MTI->ifacemin;
9474       SUMA_COPY_VEC(MTI->P, PR->PickXYZ, 3, float, float);
9475       /* Add selection result to stack */
9476       if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &PR)) {
9477          SUMA_S_Err("Failed to add selected ado");
9478          SUMA_RETURN(-1);
9479       }
9480    }
9481 
9482    /* clear MTI */
9483    if (MTI) {
9484       MTI = SUMA_Free_MT_intersect_triangle(MTI);
9485    }
9486 
9487    if (imin >=0) SUMA_RETURN(1);
9488    else SUMA_RETURN(0);
9489 }
9490 
9491 
SUMA_MarkLineSurfaceIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)9492 int SUMA_MarkLineSurfaceIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9493                                     int IgnoreSameNode)
9494 {
9495    static char FuncName[]={"SUMA_MarkLineSurfaceIntersect"};
9496    SUMA_PICK_RESULT *PR = NULL;
9497    SUMA_ALL_DO *ado = NULL;
9498    int ans;
9499 
9500    SUMA_ENTRY;
9501 
9502    // fprintf(stderr, "%s\n", FuncName);
9503    SUMA_S_Warn("Do not call me anymore."
9504                "Go via SUMA_ComputeLineSurfaceIntersect. "
9505                "This is left here for testing purposes");
9506    ans = SUMA_ComputeLineSurfaceIntersect(sv, dov, IgnoreSameNode, &ado);
9507    if (ans <= 0) {
9508       SUMA_RETURN(ans);
9509    }
9510    /* just for temporary testing, get PR back from list and apply it */
9511    PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
9512    ans = SUMA_Apply_PR(sv, &PR);
9513 
9514    SUMA_RETURN(ans);
9515 }
9516 
9517 /*!
9518    Determines the intersection between ]sv->Pick0 sv->Pick1[ and SO
9519    Highlights the intersected faceset, node and updates cross hair location
9520    This used to be part of Button3's code in SUMA_input
9521    ans = SUMA_ComputeLineSurfaceIntersect (sv, dov);
9522    \param sv (SUMA_SurfaceViewer *) surface viewer pointer
9523    \param dov (SUMA_DO *) displayable object vector pointer
9524    \param IgnoreSameNode (int) 1 do nothing if node already selected
9525                                0 don't care if it was already selected
9526    \param pado  (SUMA_ALL_DO **) If not NULL, *pado will contain a copy
9527                                  of an ADO pointer to the intersected
9528                                  object, if any.
9529    \ret ans (int)  -1 error, 0 no hit, hit
9530 
9531    Note that this function will register whatever surfaces get hit in the
9532    selections list with a call to SUMA_Add_To_PickResult_List()
9533 
9534    also requires SUMAg_DOv and SUMAg_N_DOv
9535 */
SUMA_ComputeLineSurfaceIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)9536 int SUMA_ComputeLineSurfaceIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9537                                       int IgnoreSameNode, SUMA_ALL_DO **pado)
9538 {/* determine intersection */
9539    static char FuncName[]={"SUMA_ComputeLineSurfaceIntersect"};
9540    float P0f[3], P1f[3];
9541    int NP;
9542    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
9543    float delta_t_tmp, dmin;
9544    struct timeval tt_tmp;
9545    int ip, it, id, ii, N_SOlist,
9546        SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
9547    char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9548    SUMA_SurfaceObject *SO = NULL;
9549    SUMA_Boolean LocalHead = NOPE;
9550 
9551    SUMA_ENTRY;
9552 
9553    // fprintf(stderr, "%s\n", FuncName);
9554 
9555    P0f[0] = sv->Pick0[0];
9556    P0f[1] = sv->Pick0[1];
9557    P0f[2] = sv->Pick0[2];
9558    P1f[0] = sv->Pick1[0];
9559    P1f[1] = sv->Pick1[1];
9560    P1f[2] = sv->Pick1[2];
9561 
9562    N_SOlist = SUMA_VisibleSOs(sv, dov, SOlist, 0);
9563    imin = -1;
9564    dmin = 10000000.0;
9565 
9566    for (ii=0; ii < N_SOlist; ++ii) { /* find the closest intersection */
9567       if (LocalHead)
9568             fprintf (SUMA_STDERR,
9569                      "%s: working %d/%d shown surfaces ...\n",
9570                      FuncName, ii, N_SOlist);
9571       SO = (SUMA_SurfaceObject *)dov[SOlist[ii]].OP;
9572       SUMA_VisX_Pointers4Display(SO, 1); /* using coordinates as displayed */
9573       if (SO->FaceSetDim != 3) {
9574          fprintf(SUMA_STDERR,
9575             "Error %s: "
9576             "SUMA_MT_intersect_triangle only works for triangular meshes.\n",
9577             FuncName);
9578       } else {
9579 
9580          SUMA_etime (&tt_tmp, 0);
9581 
9582          MTIi = SUMA_MT_intersect_triangle(P0f, P1f, SO->NodeList, SO->N_Node,
9583                                         SO->FaceSetList, SO->N_FaceSet, NULL, 0);
9584 
9585          delta_t_tmp = SUMA_etime (&tt_tmp, 1);
9586          if (LocalHead)
9587             fprintf (SUMA_STDERR,
9588                "Local Debug %s: Intersection took %f seconds.\n",
9589                FuncName, delta_t_tmp);
9590 
9591          if (MTIi == NULL) {
9592             fprintf(SUMA_STDERR,
9593                      "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
9594             SUMA_RETURN (-1);
9595          }
9596 
9597          if (MTIi->N_hits) {
9598             /* decide on the closest surface to the clicking point */
9599             if (MTIi->t[MTIi->ifacemin] < dmin) {
9600                if (LocalHead)
9601                   fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
9602                            FuncName, ii);
9603                dmin = MTIi->t[MTIi->ifacemin];
9604                imin = SOlist[ii];
9605                MTI = MTIi;
9606             }else {
9607                /* not good, toss it away */
9608                if (LocalHead)
9609                   fprintf (SUMA_STDERR,
9610                            "%s: ii=%d freeing MTIi...\n", FuncName, ii);
9611                MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9612             }
9613          }else {
9614             /* not good, toss it away */
9615            if (LocalHead)
9616                fprintf (SUMA_STDERR,
9617                         "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
9618            MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9619         }
9620       }
9621       SUMA_VisX_Pointers4Display(SO, 0); /* put things back young man */
9622     }
9623 
9624    if (LocalHead)
9625       fprintf (SUMA_STDERR,
9626                "%s: Closest surface is indexed %d in DOv.\n", FuncName, imin);
9627 
9628    if (imin >= 0) {
9629       SUMA_PICK_RESULT *PR;
9630       SUMA_ALL_DO *ado;
9631       if (!(ado = iDO_ADO(imin))) {
9632          SUMA_S_Err("NULL ado at this point?");
9633          SUMA_RETURN(-1);
9634       }
9635       PR = SUMA_New_Pick_Result(NULL);
9636       if (pado) *pado = ado; /* user want answer back */
9637       PR->ado_idcode_str = SUMA_copy_string(ADO_ID(ado));
9638       PR->datum_index = MTI->inodemin;
9639       PR->ignore_same_datum = IgnoreSameNode;
9640       PR->iAltSel[SUMA_SURF_TRI] = MTI->ifacemin;
9641       SUMA_COPY_VEC(MTI->P, PR->PickXYZ, 3, float, float);
9642       /* Add selection result to stack.  NB.  This increments sv->SelAdo->size
9643         PR has the surface details.  */
9644       if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &PR)) {
9645          SUMA_S_Err("Failed to add selected ado");
9646          SUMA_RETURN(-1);
9647       }
9648    }
9649 
9650    /* clear MTI */
9651    if (MTI) {
9652       MTI = SUMA_Free_MT_intersect_triangle(MTI);
9653    }
9654 
9655    if (imin >=0) SUMA_RETURN(1);
9656    else SUMA_RETURN(0);
9657 }
9658 
SUMA_Apply_PR_SO(SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO,SUMA_PICK_RESULT ** PRi)9659 int SUMA_Apply_PR_SO(SUMA_SurfaceViewer *sv, SUMA_SurfaceObject *SO,
9660                      SUMA_PICK_RESULT **PRi)
9661 {
9662    static char FuncName[]={"SUMA_Apply_PR_SO"};
9663    SUMA_ALL_DO *ado=NULL;
9664    DList *list = NULL;
9665    DListElmt *SetNodeElem = NULL, *Location=NULL;
9666    SUMA_Boolean NodeIgnored = NOPE;
9667    SUMA_PICK_RESULT *PR;
9668    int NP=0, ip=0, it=0, id = 0, iv3[3];
9669    SUMA_EngineData *ED = NULL;
9670    SUMA_Boolean LocalHead = NOPE;
9671 
9672    SUMA_ENTRY;
9673 
9674    if (strstr(SO->Label, "clippingPlaneIdentificationSquare_")){
9675     fprintf(stderr, "Clipping plane identification squares may not be selected.\n");
9676     return (0);
9677    }
9678 
9679    // fprintf(stderr, "%s\n", FuncName);
9680 
9681    if (!sv || !SO || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
9682 
9683    /* Mark intersection Facsets */
9684    ado = (SUMA_ALL_DO *)SO;
9685 
9686    PR = *PRi;   /* Keep local copy */
9687    /* Store the PR in ado, hide it from return potential */
9688    SUMA_ADO_StorePickResult(ado, PRi);
9689 
9690 
9691    sv->Focus_DO_ID = ADO_iDO(ado);
9692    SUMA_UpdateViewerTitle(sv);
9693 
9694    NP = SO->FaceSetDim;
9695    ip = NP * PR->iAltSel[SUMA_SURF_TRI];
9696 
9697 
9698    /* if the surface controller is open, update it */
9699    if (SUMA_isADO_Cont_Realized(ado))
9700        SUMA_Init_SurfCont_SurfParam(ado);
9701 
9702    /* print nodes about the closets faceset*/
9703    fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9704    fprintf(SUMA_STDOUT, "Selected surface %s (Focus_DO_ID # %d).\n"
9705                         "FaceSet %ld, Closest Node %ld\n",
9706       SO->Label, sv->Focus_DO_ID, PR->iAltSel[SUMA_SURF_TRI],
9707       PR->datum_index);
9708    fprintf(SUMA_STDOUT, "Nodes forming closest FaceSet:\n");
9709    fprintf(SUMA_STDOUT, "%d, %d, %d\n",
9710       SO->FaceSetList[ip], SO->FaceSetList[ip+1],SO->FaceSetList[ip+2]);
9711 
9712    fprintf (SUMA_STDOUT,"Coordinates of Nodes forming closest FaceSet:\n");
9713    for (it=0; it < 3; ++it) {
9714 
9715       id = SO->NodeDim * SO->FaceSetList[ip+it];
9716       fprintf(SUMA_STDOUT, "%f, %f, %f\n", SO->NodeList[id],
9717                                            SO->NodeList[id+1],
9718                                            SO->NodeList[id+2]);
9719    }
9720    fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9721 
9722    /* Set the Nodeselection at the closest node */
9723    it = PR->datum_index;
9724    if (!list) list = SUMA_CreateList();
9725    if (PR->ignore_same_datum && SO->SelectedNode == PR->datum_index) {
9726       SUMA_LHv("Ignoring identical node selection %d on surface %s\n",
9727                SO->SelectedNode, SO->Label);
9728       NodeIgnored = YUP;
9729    } else {
9730       ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
9731       SetNodeElem = SUMA_RegisterEngineListCommand (  list, ED,
9732                                              SEF_i, (void*)&it,
9733                                              SES_Suma, (void *)sv, NOPE,
9734                                              SEI_Head, NULL);
9735       if (!SetNodeElem) {
9736          fprintf( SUMA_STDERR,
9737                   "Error %s: Failed to register SetNodeElem\n", FuncName);
9738          SUMA_RETURN (-1);
9739       } else {
9740          SUMA_RegisterEngineListCommand (  list, ED,
9741                                            SEF_ngr, NULL,
9742                                            SES_Suma, (void *)sv, NOPE,
9743                                            SEI_In, SetNodeElem);
9744       }
9745    }
9746 
9747 
9748    /* Set the FaceSetselection */
9749    it = PR->iAltSel[SUMA_SURF_TRI];
9750    ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
9751    if (!SUMA_RegisterEngineListCommand (  list, ED,
9752                                           SEF_i, (void*)&it,
9753                                           SES_Suma, (void *)sv, NOPE,
9754                                           SEI_Head, NULL)) {
9755       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9756       SUMA_RETURN (-1);
9757    }
9758 
9759    /* Now set the cross hair position at the intersection*/
9760    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
9761    if (!(Location = SUMA_RegisterEngineListCommand (  list, ED,
9762                                           SEF_fv3, (void*)PR->PickXYZ,
9763                                           SES_Suma, (void *)sv, NOPE,
9764                                           SEI_Head, NULL))) {
9765       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9766       SUMA_RETURN (-1);
9767    }
9768    /* and add the SO with this location, needed for VisX business*/
9769    SUMA_RegisterEngineListCommand (  list, ED,
9770                                            SEF_vp, (void *)SO,
9771                                            SES_Suma, (void *)sv, NOPE,
9772                                            SEI_In, Location);
9773 
9774    /* attach the cross hair to the selected surface */
9775    iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
9776    iv3[1] = PR->datum_index;
9777    iv3[2] = PR->iAltSel[SUMA_SURF_TRI];
9778    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
9779    if (!SUMA_RegisterEngineListCommand (  list, ED,
9780                                           SEF_iv3, (void*)iv3,
9781                                           SES_Suma, (void *)sv, NOPE,
9782                                           SEI_Head, NULL)) {
9783       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9784       SUMA_RETURN (-1);
9785    }
9786 
9787    /* check to see if AFNI needs to be notified */
9788    /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
9789       Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
9790    if (  ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
9791            sv->LinkAfniCrossHair )                             ||
9792          ( SUMAg_CF->Connected_v[SUMA_HALLO_SUMA_LINE])        ||
9793          ( SUMAg_CF->Connected_v[SUMA_INSTA_TRACT_LINE])    ) {
9794       if (LocalHead)
9795          fprintf(SUMA_STDERR,
9796                   "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
9797       /* register a call to SetAfniCrossHair */
9798       if (!list) list = SUMA_CreateList();
9799       it = SUMA_ShftCont_Event(PR->evr);
9800       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
9801       if (!SUMA_RegisterEngineListCommand (  list, ED,
9802                                           SEF_i, (void*)&it,
9803                                           SES_Suma, (void *)sv, NOPE,
9804                                           SEI_Tail, NULL)) {
9805          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9806          SUMA_RETURN (-1);
9807       }
9808       if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
9809          SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
9810          if (ado && ado->do_type == MASK_type) {
9811             SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
9812             ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
9813             if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
9814                                                 SEF_fv3, (void*)mdo->cen,
9815                                                 SES_Suma, (void *)sv, NOPE,
9816                                                 SEI_Tail, NULL))) {
9817                SUMA_S_Err("Failed to register element\n");
9818                SUMA_RETURN (-1);
9819             }
9820             SUMA_RegisterEngineListCommand (  list, ED,
9821                                            SEF_s, (void *)(ADO_ID(ado)),
9822                                            SES_Suma, (void *)sv, NOPE,
9823                                            SEI_In, Location);
9824          }
9825       }
9826       if (!SUMA_Engine (&list)) {
9827          fprintf( SUMA_STDERR,
9828                   "Error %s: SUMA_Engine call failed.\n", FuncName);
9829          SUMA_RETURN (-1);
9830       }
9831    }else {
9832       if (LocalHead)
9833          fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
9834    }
9835 
9836    /* put in a request for GICOR if need be */
9837    if (  !NodeIgnored &&
9838          SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
9839          SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
9840       if (LocalHead)
9841          fprintf(SUMA_STDERR,
9842                   "%s: Notifying GICOR of node selection\n", FuncName);
9843       /* register a call to SetGICORnode */
9844       if (!list) list = SUMA_CreateList();
9845       SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
9846                                           SES_Suma, sv);
9847       if (!SUMA_Engine (&list)) {
9848          fprintf( SUMA_STDERR,
9849                   "Error %s: SUMA_Engine call failed.\n", FuncName);
9850          SUMA_RETURN (-1);
9851       }
9852    }else {
9853       if (LocalHead)
9854          fprintf(SUMA_STDERR,"%s: No Notification to GICOR.\n", FuncName);
9855    }
9856    /* now put in a request for locking cross hair but you must do
9857       this after the node selection has been executed
9858       NOTE: You do not always have SetNodeElem because the list might
9859       get emptied in the call to AFNI notification.
9860       You should just put the next call at the end of the list.*/
9861    SUMA_LH("Cross hair locking");
9862    if (!list) list = SUMA_CreateList();
9863    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
9864    if (!SUMA_RegisterEngineListCommand (  list, ED,
9865                                           SEF_iv3, (void*)iv3,
9866                                           SES_Suma, (void *)sv, NOPE,
9867                                           SEI_Tail, NULL)) {
9868       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9869       SUMA_RETURN (-1);
9870    }
9871 
9872    SUMA_LH("Cross hair locking Engine call");
9873    if (!SUMA_Engine (&list)) {
9874       fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
9875       SUMA_RETURN (-1);
9876    }
9877    SUMA_LH("Returning");
9878    SUMA_RETURN (1); /* OK */
9879 }/* determine intersection */
9880 
SUMA_MarkLineCutplaneIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)9881 int SUMA_MarkLineCutplaneIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9882                                     int IgnoreSameNode)
9883 {/* determine intersection */
9884    static char FuncName[]={"SUMA_MarkLineCutplaneIntersect"};
9885    float P0f[3], P1f[3];
9886    int NP;
9887    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
9888    float delta_t_tmp, dmin;
9889    struct timeval tt_tmp;
9890    int ip, it, id, iv3[3], ii, N_SOlist,
9891        SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
9892    char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9893    SUMA_EngineData *ED = NULL;
9894    DList *list = NULL;
9895    DListElmt *SetNodeElem = NULL, *Location=NULL;
9896    SUMA_SurfaceObject *SO = NULL;
9897    SUMA_SurfaceObject **SOv = NULL;
9898    SUMA_VolumeObject *VO=NULL;
9899    SUMA_Boolean NodeIgnored = NOPE;
9900    SUMA_Boolean LocalHead = NOPE;
9901 
9902    SUMA_ENTRY;
9903 
9904    // fprintf(stderr, "%s\n", FuncName);
9905 
9906    P0f[0] = sv->Pick0[0];
9907    P0f[1] = sv->Pick0[1];
9908    P0f[2] = sv->Pick0[2];
9909    P1f[0] = sv->Pick1[0];
9910    P1f[1] = sv->Pick1[1];
9911    P1f[2] = sv->Pick1[2];
9912 
9913    SUMA_LH("Getting array of pointers to clip plane surfaces");
9914    if (!(SOv = SUMA_TextureClipPlaneSurfaces(&N_SOlist))) {
9915       SUMA_LH("No clip plane surfaces");
9916       SUMA_RETURN(0);
9917    }
9918    imin = -1;
9919    dmin = 10000000.0;
9920    for (ii=0; ii < N_SOlist; ++ii) { /* find the closest intersection */
9921       if (LocalHead)
9922             fprintf (SUMA_STDERR,
9923                      "%s: working %d/%d clip plane ...\n",
9924                      FuncName, ii, N_SOlist);
9925       SO = SOv[ii];
9926       if (SO->FaceSetDim != 3) {
9927          fprintf(SUMA_STDERR,
9928             "Error %s: "
9929             "SUMA_MT_intersect_triangle only works for triangular meshes.\n",
9930             FuncName);
9931       } else {
9932 
9933          SUMA_etime (&tt_tmp, 0);
9934          SUMA_LH("About to call intersection function");
9935 
9936          MTIi = SUMA_MT_intersect_triangle(P0f, P1f, SO->NodeList, SO->N_Node,
9937                                         SO->FaceSetList, SO->N_FaceSet, NULL, 0);
9938 
9939          delta_t_tmp = SUMA_etime (&tt_tmp, 1);
9940          if (LocalHead)
9941             fprintf (SUMA_STDERR,
9942                "Local Debug %s: Intersection took %f seconds.\n",
9943                FuncName, delta_t_tmp);
9944 
9945          if (MTIi == NULL) {
9946             fprintf(SUMA_STDERR,
9947                      "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
9948             SUMA_RETURN (-1);
9949          }
9950 
9951          if (MTIi->N_hits) {
9952             /* decide on the closest surface to the clicking point */
9953             if (MTIi->t[MTIi->ifacemin] < dmin) {
9954                if (LocalHead)
9955                   fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
9956                            FuncName, ii);
9957                dmin = MTIi->t[MTIi->ifacemin];
9958                imin = ii;
9959                MTI = MTIi;
9960             }else {
9961                /* not good, toss it away */
9962                if (LocalHead)
9963                   fprintf (SUMA_STDERR,
9964                            "%s: ii=%d freeing MTIi...\n", FuncName, ii);
9965                MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9966             }
9967          }else {
9968             /* not good, toss it away */
9969            if (LocalHead)
9970                fprintf (SUMA_STDERR,
9971                         "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
9972            MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9973         }
9974       }
9975     }
9976 
9977    if (LocalHead)
9978       fprintf (SUMA_STDERR,
9979                "%s: Closest surface is indexed %d in cutplane surfaces.\n",
9980                FuncName, imin);
9981 
9982    /* Mark intersection Facsets */
9983    if (imin >= 0) {
9984       SUMA_ALL_DO *ado=NULL;
9985       if (!(VO = SUMA_VolumeObjectOfClipPlaneSurface(SO))) {
9986          SUMA_S_Err("Failed to find volume object for clipped surface");
9987          SUMA_RETURN(-1);
9988       }
9989       VO->SelectedCutPlane = imin;
9990       SUMA_S_Warn("NEED TO IMPLEMENT PR THING HERE, THEN PASS IT BELOW");
9991       ado = (SUMA_ALL_DO *)VO;
9992       if (!SUMA_Add_To_PickResult_List(sv, ado, "cutplane", NULL)) {
9993          SUMA_S_Err("Failed to add selected ado");
9994          SUMA_RETURN(-1);
9995       }
9996       /* Now set this volume as the focus DO */
9997       sv->Focus_DO_ID =
9998          SUMA_findVO_inDOv(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
9999 
10000       /* if the surface controller is open, update it */
10001       if (SUMA_isADO_Cont_Realized(ado))
10002          SUMA_Init_SurfCont_SurfParam(ado);
10003 
10004       SUMA_UpdateViewerTitle(sv);
10005 
10006       /* if the surface controller is open, update it */
10007       if (SUMA_isADO_Cont_Realized(ado))
10008          SUMA_Init_SurfCont_SurfParam(ado);
10009 
10010 
10011       ip = SO->FaceSetDim * MTI->ifacemin;
10012       SUMA_S_Note("Have to decide on what to do here,\n"
10013                   "see equivalent section in SUMA_MarkLineSurfaceIntersect");
10014       SUMA_S_Warn("Weird, coords all zero");
10015       /* print nodes about the closets faceset*/
10016       fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
10017       fprintf(SUMA_STDOUT, "Selected cutplane surface %d .\n"
10018                            "FaceSet %d, Closest Node %d\n",
10019          imin, MTI->ifacemin, MTI->inodemin);
10020       fprintf(SUMA_STDOUT, "Nodes forming closest FaceSet:\n");
10021       fprintf(SUMA_STDOUT, "%d, %d, %d\n", \
10022       SO->FaceSetList[ip], SO->FaceSetList[ip+1],SO->FaceSetList[ip+2]);
10023 
10024       fprintf (SUMA_STDOUT,"Coordinates of Nodes forming closest FaceSet:\n"
10025                            "SO->NodeDim = %d \n", SO->NodeDim);
10026       for (it=0; it < 3; ++it) {
10027 
10028          id = SO->NodeDim * SO->FaceSetList[ip+it];
10029          fprintf(SUMA_STDOUT, "%f, %f, %f\n", SO->NodeList[id],
10030                                                 SO->NodeList[id+1],
10031                                                 SO->NodeList[id+2]);
10032       }
10033       fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
10034 
10035 
10036 
10037       /* Now set the cross hair position at the intersection*/
10038       if (!list) list = SUMA_CreateList();
10039       ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
10040       if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
10041                                              SEF_fv3, (void*)MTI->P,
10042                                              SES_Suma, (void *)sv, NOPE,
10043                                              SEI_Head, NULL))) {
10044          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10045          SUMA_RETURN (-1);
10046       }
10047       /* and add the SO with this location, needed for VisX business*/
10048       SUMA_RegisterEngineListCommand (  list, ED,
10049                                         SEF_vp, (void *)SO,
10050                                         SES_Suma, (void *)sv, NOPE,
10051                                         SEI_In, Location);
10052 
10053       if (!SUMA_Engine (&list)) {
10054          fprintf( SUMA_STDERR,
10055                   "Error %s: SUMA_Engine call failed.\n", FuncName);
10056          SUMA_RETURN (-1);
10057       }
10058       /* check to see if AFNI needs to be notified */
10059       /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
10060          Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
10061       if (  SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
10062             sv->LinkAfniCrossHair) {
10063          if (LocalHead)
10064             fprintf(SUMA_STDERR,
10065                      "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
10066          /* register a call to SetAfniCrossHair */
10067          if (!list) list = SUMA_CreateList();
10068          it = 0; /* Might want someday: SUMA_ShftCont_Event(PR->evr); */
10069          ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
10070          if (!SUMA_RegisterEngineListCommand (  list, ED,
10071                                              SEF_i, (void*)&it,
10072                                              SES_Suma, (void *)sv, NOPE,
10073                                              SEI_Tail, NULL)) {
10074             SUMA_S_Err("Failed to register element\n");
10075             SUMA_RETURN (-1);
10076          }
10077          if (!SUMA_Engine (&list)) {
10078             fprintf( SUMA_STDERR,
10079                      "Error %s: SUMA_Engine call failed.\n", FuncName);
10080             SUMA_RETURN (-1);
10081          }
10082       }else {
10083          if (LocalHead)
10084             fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
10085       }
10086 
10087       /* put in a request for GICOR if need be */
10088       if (  !NodeIgnored &&
10089             SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
10090             SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
10091          if (LocalHead)
10092             fprintf(SUMA_STDERR,
10093                      "%s: Notifying GICOR of node selection\n", FuncName);
10094          /* register a call to SetGICORnode */
10095          if (!list) list = SUMA_CreateList();
10096          SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
10097                                              SES_Suma, sv);
10098          if (!SUMA_Engine (&list)) {
10099             fprintf( SUMA_STDERR,
10100                      "Error %s: SUMA_Engine call failed.\n", FuncName);
10101             SUMA_RETURN (-1);
10102          }
10103       }else {
10104          if (LocalHead)
10105             fprintf(SUMA_STDERR,"%s: No Notification to GICOR.\n", FuncName);
10106       }
10107 
10108 
10109 
10110    }
10111    /* clear MTI */
10112    if (MTI) {
10113       MTI = SUMA_Free_MT_intersect_triangle(MTI);
10114    }
10115 
10116    SUMA_free(SOv); SOv = NULL;
10117 
10118    if (imin >= 0) {
10119       SUMA_RETURN (1); /* hit */
10120    } else {
10121       SUMA_RETURN (0); /* no hit */
10122    }
10123 }/* determine intersection with cutplanes*/
10124 
SUMA_MarkLineVOslicesIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)10125 int SUMA_MarkLineVOslicesIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
10126                                     int IgnoreSameNode)
10127 {/* determine intersection */
10128    static char FuncName[]={"SUMA_MarkLineVOslicesIntersect"};
10129    SUMA_PICK_RESULT *PR = NULL;
10130    SUMA_ALL_DO *ado = NULL;
10131    int ans;
10132 
10133    SUMA_ENTRY;
10134 
10135    // fprintf(stderr, "%s\n", FuncName);
10136    SUMA_S_Warn("Do not call me anymore. Follow the new selection logic");
10137    ans = SUMA_ComputeLineVOslicesIntersect(sv, dov, IgnoreSameNode, &ado);
10138    if (ans <= 0) {
10139       SUMA_RETURN(ans);
10140    }
10141    /* just for temporary testing, get PR back from list and apply it */
10142    PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
10143    ans = SUMA_Apply_PR(sv, &PR);
10144    SUMA_RETURN(ans);
10145 }
10146 
10147 #if 0
10148 /* BEFORE you start using this MACRO everywhere, including with the,
10149    other ThrMode values, make sure you write a function version of it
10150    which can be used as a sanity check. For now, this seems OK */
10151 #define SUMA_VAL_MEETS_THRESH(val, ThreshRange, ThrMode) (\
10152       ((ThrMode) == SUMA_LESS_THAN && (val) >= ThreshRange[0])?1: \
10153      (((ThrMode) == SUMA_ABS_LESS_THAN && ( (val) >=  ThreshRange[0] ||   \
10154                                             (val) <= -ThreshRange[0]))?1:0) )
10155 #endif
SUMA_Val_Meets_Thresh(float val,double * ThreshRange,SUMA_THRESH_MODE ThrMode)10156 byte SUMA_Val_Meets_Thresh(float val, double *ThreshRange,
10157                            SUMA_THRESH_MODE ThrMode)
10158 {
10159    static char FuncName[]={"SUMA_Val_Meets_Thresh"};
10160 
10161    // fprintf(stderr, "%s\n", FuncName);
10162   switch(ThrMode){
10163       case SUMA_LESS_THAN:
10164          return((val >= ThreshRange[0]));
10165          break;
10166       case SUMA_ABS_LESS_THAN:
10167          return((val >=  ThreshRange[0]) || (val <=  -ThreshRange[0]));
10168          break;
10169       case SUMA_THRESH_OUTSIDE_RANGE:
10170          return((val <  ThreshRange[0]) || (val > ThreshRange[1]));
10171          break;
10172       case SUMA_THRESH_INSIDE_RANGE:
10173          return((val >=  ThreshRange[0]) && (val <= ThreshRange[1]));
10174          break;
10175       case SUMA_NO_THRESH:
10176          return(1);
10177       default:
10178          SUMA_S_Warn("Bad thresh mode %d", ThrMode);
10179          return(1);
10180          break;
10181    }
10182    SUMA_S_Warn("Should not be here %d", ThrMode);
10183    return(1);
10184 }
10185 
10186 /*
10187    This function is almost identical to SUMA_ComputeLineVOvrIntersect()
10188    They could be merged quite readily but for some reason this feels
10189    cleaner to me.
10190    Make sure that any change here is mirrored verbatim (to the degree possible)
10191    in SUMA_ComputeLineVOvrIntersect() .
10192 
10193    Consider merging SUMA_ComputeLineVOvrIntersect() into
10194    SUMA_ComputeLineVOslicesIntersect() in the future if maintenance is a problem
10195 */
SUMA_ComputeLineVOslicesIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)10196 int SUMA_ComputeLineVOslicesIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
10197                                        int IgnoreSameNode, SUMA_ALL_DO **pado)
10198 {/* determine intersection */
10199    static char FuncName[]={"SUMA_ComputeLineVOslicesIntersect"};
10200    float P0f[3], P1f[3], pinter[3], I[3];
10201    int NP, N_Hit, okinten=0;
10202    float delta_t_tmp, dmin, val;
10203    struct timeval tt_tmp;
10204    int ip, it, id, ii, imin, I1d, Irw, Hit, ive, icolplane, indef=-1;
10205    int *MembDOs=NULL, N_MembDOs, UseAlphaTresh=1;
10206    float valpha=0.0;
10207    SUMA_DO_Types ttv[12];
10208    char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
10209    SUMA_VolumeObject *VO=NULL;
10210    SUMA_Boolean NodeIgnored = NOPE;
10211    SUMA_RENDERED_SLICE *rslc;
10212    SUMA_ALL_DO *ado = NULL;
10213    SUMA_DSET *dset = NULL;
10214    SUMA_OVERLAYS *colplane=NULL;
10215    SUMA_VOL_SAUX *VSaux = NULL;
10216    SUMA_PICK_RESULT *PR=NULL;
10217    DListElmt *el=NULL;
10218    SUMA_Boolean LocalHead = NOPE;
10219 
10220    SUMA_ENTRY;
10221 
10222    // fprintf(stderr, "%s\n", FuncName);
10223 
10224    P0f[0] = sv->Pick0[0];
10225    P0f[1] = sv->Pick0[1];
10226    P0f[2] = sv->Pick0[2];
10227    P1f[0] = sv->Pick1[0];
10228    P1f[1] = sv->Pick1[1];
10229    P1f[2] = sv->Pick1[2];
10230 
10231    ttv[0] = VO_type; ttv[1] = NOT_SET_type;
10232    MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
10233    SUMA_LHv("Searching for hit: %f %f %f --> %f %f %f\n",
10234             P0f[0], P0f[1], P0f[2], P1f[0], P1f[1], P1f[2]);
10235    N_Hit = 0;
10236    for (ii=0; ii<N_MembDOs; ++ii) {
10237       {
10238          VO = (SUMA_VolumeObject *)(dov[MembDOs[ii]].OP);
10239          ado = (SUMA_ALL_DO *)VO;
10240          if (!(VSaux = SUMA_ADO_VSaux(ado))) continue;
10241          SUMA_LH("%d slices on %s", dlist_size(VSaux->slcl), ADO_LABEL(ado));
10242          if (!dlist_size(VSaux->slcl)) continue;
10243          /* now compute intersection from the top down */
10244          Hit = 0;
10245          el = NULL;
10246          do {
10247             if (!el) el = dlist_head(VSaux->slcl);
10248             else el = dlist_next(el);
10249             rslc = (SUMA_RENDERED_SLICE *)el->data;
10250             /* does line intersect this plane? */
10251             SUMA_SEGMENT_PLANE_INTERSECT(P0f, P1f, rslc->Eq, Hit, pinter);
10252             if (Hit) {/* is the intersection point in the volume? */
10253                Hit = 0; /* demote, real hit decided on below */
10254                ive = 0;
10255                while (VO->VE && VO->VE[ive]) {
10256                   AFF44_MULT_I(I, VO->VE[ive]->X2I, pinter);
10257                   SUMA_LH("On %s: Inter at X=[%f %f %f] --> ijk=[%f %f %f]",
10258                            SUMA_VE_Headname(VO->VE, ive),
10259                            pinter[0], pinter[1], pinter[2], I[0], I[1], I[2]);
10260                   I[0] = (int)I[0]; I[1] = (int)I[1]; I[2] = (int)I[2];
10261                   if (I[0] >= 0.0f && I[1] >= 0.0f && I[2] >= 0.0f &&
10262                       I[0] < VO->VE[ive]->Ni &&  I[1] < VO->VE[ive]->Nj &&
10263                       I[2] < VO->VE[ive]->Nk) {
10264                       dset = SUMA_VE_dset(VO->VE, ive);
10265                       colplane =  SUMA_Fetch_OverlayPointerByDset(
10266                                           (SUMA_ALL_DO *)VO, dset, &icolplane);
10267                       /* here you check on the value at I in the dataset */
10268                       I1d = I[2]*VO->VE[ive]->Ni*VO->VE[ive]->Nj +
10269                             I[1]*VO->VE[ive]->Ni+I[0];
10270                       Irw = SUMA_GetNodeRow_FromNodeIndex_eng(dset, I1d,-1);
10271                       if (!colplane->V) {
10272                         SUMA_S_Err("Need SUMA_GetDsetValInCol to get vals");
10273                         SUMA_RETURN(NOPE);
10274                       } else {
10275                         val = colplane->V[Irw];
10276                       }
10277                       SUMA_LH("Have intersection on ive %d inside VE %s\n"
10278                               "IJK [%d %d %d], I1d=%d, Irw=%d, \n"
10279                               "val %f, thr [%f %f]\n",
10280                               ive, SUMA_VE_Headname(VO->VE, ive),
10281                               (int)I[0], (int)I[1], (int)I[2],
10282                               I1d, Irw, val,
10283                               colplane->OptScl->ThreshRange[0],
10284                               colplane->OptScl->ThreshRange[1]);
10285 
10286                       /* Do we meet intensity thresholds? */
10287                       okinten = 0;
10288                       if ( SUMA_Val_Meets_Thresh(val,
10289                                     colplane->OptScl->ThreshRange,
10290                                     colplane->OptScl->ThrMode ) &&
10291                            (val != 0.0f || !colplane->OptScl->MaskZero)) {
10292                         okinten = 1;
10293                       }
10294 
10295                       indef = -1;
10296                       UseAlphaTresh = 1;/* control from interface someday */
10297                       valpha = 2.0; /* no masking */
10298                       if (UseAlphaTresh && okinten && colplane->ColAlpha) {
10299                         /* Also mask if value is below alpha thresh
10300                            This is a slow search... So you may not want
10301                            to use it all the time.
10302                            Problem is finding the row of the voxel in
10303                            NodeDef, and that's too slow for a big
10304                            volume to be run repeatedly...Would
10305                            be easier if I had a function to recompute
10306                            a voxel's alpha, rather than search for it
10307                            in ColAlpha. Oh, well, someday I guess. For
10308                            now we search*/
10309                         if ((indef=SUMA_GetSortedNodeOverInd(colplane, I1d))>=0){
10310                            valpha = colplane->ColAlpha[indef]/255.0;
10311                         }
10312                       }
10313 
10314                       if ( okinten && (valpha > colplane->AlphaThresh) ) {
10315                         SUMA_LH("FOUND IT, on VE %s, IJK [%d %d %d], val %f,"
10316                                "thresh[%f %f], UseAlphaTresh = %d, "
10317                                "valpha=%f, ColAlphaThresh=%f\n",
10318                                    SUMA_VE_Headname(VO->VE, ive),
10319                                    (int)I[0], (int)I[1], (int)I[2], val,
10320                                    colplane->OptScl->ThreshRange[0],
10321                                    colplane->OptScl->ThreshRange[1],
10322                                    UseAlphaTresh,
10323                                    valpha, colplane->AlphaThresh*255);
10324                            PR = SUMA_New_Pick_Result(NULL);
10325                            PR->ado_idcode_str = SUMA_replace_string(
10326                                            PR->ado_idcode_str, ADO_ID(ado));
10327                            if (pado) *pado = ado; /* user wants it */
10328                            PR->primitive = SUMA_replace_string(
10329                                                          PR->primitive,"voxel");
10330                            PR->primitive_index = -1;
10331                            PR->PickXYZ[0] = pinter[0];
10332                            PR->PickXYZ[1] = pinter[1];
10333                            PR->PickXYZ[2] = pinter[2];
10334                            PR->ignore_same_datum = IgnoreSameNode;
10335                            PR->datum_index = I1d;
10336                            PR->iAltSel[SUMA_VOL_I] = I[0];
10337                            PR->iAltSel[SUMA_VOL_J] = I[1];
10338                            PR->iAltSel[SUMA_VOL_K] = I[2];
10339                            PR->iAltSel[SUMA_VOL_IJK] = I1d;
10340                            PR->iAltSel[SUMA_VOL_SLC_NUM] = rslc->slc_num;
10341                            PR->iAltSel[SUMA_VOL_SLC_VARIANT] =
10342                                  (int)SUMA_SlcVariantToCode(rslc->variant);
10343                            PR->dAltSel[SUMA_VOL_SLC_EQ0] = rslc->Eq[0];
10344                            PR->dAltSel[SUMA_VOL_SLC_EQ1] = rslc->Eq[1];
10345                            PR->dAltSel[SUMA_VOL_SLC_EQ2] = rslc->Eq[2];
10346                            PR->dAltSel[SUMA_VOL_SLC_EQ3] = rslc->Eq[3];
10347                            PR->dset_idcode_str = SUMA_replace_string(
10348                                            PR->dset_idcode_str, SDSET_ID(dset));
10349                            if (!SUMA_Add_To_PickResult_List(sv, ado,
10350                                                             "voxel", &PR)) {
10351                               SUMA_S_Err("Failed to add selected ado");
10352                               SUMA_RETURN(0);
10353                            }
10354                            Hit = 1;
10355                            ++N_Hit;
10356                            /* You could leave at the first hit IF:
10357                            you only have one direction of slices in the
10358                            entire stack, AND if they are properly
10359                            ordered for rendering.
10360                            Should speed be an issue you can check for
10361                            this condition and bolt with the line below */
10362                            /* goto GOT_IT; */
10363                       }
10364                   }
10365                   ++ive;
10366                }
10367             }
10368             SUMA_LH("el now %p,\n"
10369                     "tail = %p, N_Hit = %d",
10370                     el, dlist_tail(VSaux->slcl), N_Hit);
10371          } while(el != dlist_tail(VSaux->slcl));
10372       }
10373    }
10374 
10375 
10376    GOT_IT:
10377    SUMA_RETURN(N_Hit);
10378 }/* determine intersection with slices of VO*/
10379 
10380 /*
10381    This function is almost identical to SUMA_ComputeLineVOslicesIntersect()
10382    They could be merged quite readily but for some reason this feels
10383    cleaner to me.
10384    Make sure that any change here is mirrored verbatim (to the degree possible)
10385    in SUMA_ComputeLineVOslicesIntersect() .
10386 
10387    Consider merging SUMA_ComputeLineVOvrIntersect() into
10388    SUMA_ComputeLineVOslicesIntersect() in the future if maintenance is a problem
10389 
10390 
10391 */
SUMA_ComputeLineVOvrIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)10392 int SUMA_ComputeLineVOvrIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
10393                                    int IgnoreSameNode, SUMA_ALL_DO **pado)
10394 {/* determine intersection */
10395    static char FuncName[]={"SUMA_ComputeLineVOvrIntersect"};
10396    float P0f[3], P1f[3], pinter[3], I[3];
10397    int NP, N_Hit, okinten=0;
10398    float delta_t_tmp, dmin, val;
10399    struct timeval tt_tmp;
10400    int ip, it, id, ii, imin, I1d, Irw, Hit, ive, icolplane, indef=-1;
10401    int *MembDOs=NULL, N_MembDOs, UseAlphaTresh=1;
10402    float valpha=0.0;
10403    SUMA_DO_Types ttv[12];
10404    char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
10405    SUMA_VolumeObject *VO=NULL;
10406    SUMA_Boolean NodeIgnored = NOPE;
10407    SUMA_RENDERED_SLICE *rslc;
10408    SUMA_ALL_DO *ado = NULL;
10409    SUMA_DSET *dset = NULL;
10410    SUMA_OVERLAYS *colplane=NULL;
10411    SUMA_VOL_SAUX *VSaux = NULL;
10412    SUMA_PICK_RESULT *PR=NULL;
10413    DListElmt *el=NULL;
10414    SUMA_Boolean LocalHead = NOPE;
10415 
10416    SUMA_ENTRY;
10417 
10418    // fprintf(stderr, "%s\n", FuncName);
10419 
10420    P0f[0] = sv->Pick0[0];
10421    P0f[1] = sv->Pick0[1];
10422    P0f[2] = sv->Pick0[2];
10423    P1f[0] = sv->Pick1[0];
10424    P1f[1] = sv->Pick1[1];
10425    P1f[2] = sv->Pick1[2];
10426 
10427    ttv[0] = VO_type; ttv[1] = NOT_SET_type;
10428    MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
10429    SUMA_LHv("Searching for hit: %f %f %f --> %f %f %f\n",
10430             P0f[0], P0f[1], P0f[2], P1f[0], P1f[1], P1f[2]);
10431    N_Hit = 0;
10432    for (ii=0; ii<N_MembDOs; ++ii) {
10433       {
10434          VO = (SUMA_VolumeObject *)(dov[MembDOs[ii]].OP);
10435          ado = (SUMA_ALL_DO *)VO;
10436          if (!(VSaux = SUMA_ADO_VSaux(ado))) continue;
10437          SUMA_LH("%d VR slices on %s, show=%d, VrSelect=%d",
10438                               dlist_size(VSaux->vrslcl),
10439                               ADO_LABEL(ado), VSaux->ShowVrSlc,
10440                               VSaux->VrSelect);
10441          if (!VSaux->ShowVrSlc || !VSaux->VrSelect) continue;
10442          if (!dlist_size(VSaux->vrslcl)) continue;
10443          /* now compute intersection from the top down */
10444          Hit = 0;
10445          el = NULL;
10446          do {
10447             if (!el) el = dlist_head(VSaux->vrslcl);
10448             else el = dlist_next(el);
10449             rslc = (SUMA_RENDERED_SLICE *)el->data;
10450             /* does line intersect this plane? */
10451             SUMA_SEGMENT_PLANE_INTERSECT(P0f, P1f, rslc->Eq, Hit, pinter);
10452             if (Hit) {/* is the intersection point in the volume? */
10453                Hit = 0; /* demote, real hit decided on below */
10454                ive = 0;
10455                while (VO->VE && VO->VE[ive]) {
10456                   AFF44_MULT_I(I, VO->VE[ive]->X2I, pinter);
10457                   SUMA_LH("On %s: Inter at X=[%f %f %f] --> ijk=[%f %f %f]",
10458                            SUMA_VE_Headname(VO->VE, ive),
10459                            pinter[0], pinter[1], pinter[2], I[0], I[1], I[2]);
10460                   I[0] = (int)I[0]; I[1] = (int)I[1]; I[2] = (int)I[2];
10461                   if (I[0] >= 0.0f && I[1] >= 0.0f && I[2] >= 0.0f &&
10462                       I[0] < VO->VE[ive]->Ni &&  I[1] < VO->VE[ive]->Nj &&
10463                       I[2] < VO->VE[ive]->Nk) {
10464                       dset = SUMA_VE_dset(VO->VE, ive);
10465                       colplane =  SUMA_Fetch_OverlayPointerByDset(
10466                                           (SUMA_ALL_DO *)VO, dset, &icolplane);
10467                       /* here you check on the value at I in the dataset */
10468                       I1d = I[2]*VO->VE[ive]->Ni*VO->VE[ive]->Nj +
10469                             I[1]*VO->VE[ive]->Ni+I[0];
10470                       Irw = SUMA_GetNodeRow_FromNodeIndex_eng(dset, I1d,-1);
10471                       if (!colplane->V) {
10472                         SUMA_S_Err("Need SUMA_GetDsetValInCol to get vals");
10473                         SUMA_RETURN(NOPE);
10474                       } else {
10475                         val = colplane->V[Irw];
10476                       }
10477                       SUMA_LH("Have intersection on ive %d inside VE %s\n"
10478                               "IJK [%d %d %d], I1d=%d, Irw=%d, \n"
10479                               "val %f, thr [%f %f]\n",
10480                               ive, SUMA_VE_Headname(VO->VE, ive),
10481                               (int)I[0], (int)I[1], (int)I[2],
10482                               I1d, Irw, val,
10483                               colplane->OptScl->ThreshRange[0],
10484                               colplane->OptScl->ThreshRange[1]);
10485 
10486                       /* Do we meet intensity thresholds? */
10487                       okinten = 0;
10488                       if ( SUMA_Val_Meets_Thresh(val,
10489                                     colplane->OptScl->ThreshRange,
10490                                     colplane->OptScl->ThrMode ) &&
10491                            (val != 0.0f || !colplane->OptScl->MaskZero)) {
10492                         okinten = 1;
10493                       }
10494 
10495                       indef = -1;
10496                       UseAlphaTresh = 1;/* control from interface someday */
10497                       valpha = 2.0; /* no masking */
10498                       if (UseAlphaTresh && okinten && colplane->ColAlpha) {
10499                         /* Also mask if value is below alpha thresh
10500                            This is a slow search... So you may not want
10501                            to use it all the time.
10502                            Problem is finding the row of the voxel in
10503                            NodeDef, and that's too slow for a big
10504                            volume to be run repeatedly...Would
10505                            be easier if I had a function to recompute
10506                            a voxel's alpha, rather than search for it
10507                            in ColAlpha. Oh, well, someday I guess. For
10508                            now we search*/
10509                         if ((indef=SUMA_GetSortedNodeOverInd(colplane, I1d))>=0){
10510                            valpha = colplane->ColAlpha[indef]/255.0;
10511                         }
10512                       }
10513 
10514                       if ( okinten && (valpha > colplane->AlphaThresh) ) {
10515                         SUMA_LH("FOUND IT, on VE %s, IJK [%d %d %d], val %f,"
10516                                "thresh[%f %f], UseAlphaTresh = %d, "
10517                                "valpha=%f, ColAlphaThresh=%f\n",
10518                                    SUMA_VE_Headname(VO->VE, ive),
10519                                    (int)I[0], (int)I[1], (int)I[2], val,
10520                                    colplane->OptScl->ThreshRange[0],
10521                                    colplane->OptScl->ThreshRange[1],
10522                                    UseAlphaTresh,
10523                                    valpha, colplane->AlphaThresh*255);
10524                            PR = SUMA_New_Pick_Result(NULL);
10525                            PR->ado_idcode_str = SUMA_replace_string(
10526                                            PR->ado_idcode_str, ADO_ID(ado));
10527                            if (pado) *pado = ado; /* user wants it */
10528                            PR->primitive = SUMA_replace_string(
10529                                                          PR->primitive,"voxel");
10530                            PR->primitive_index = -1;
10531                            PR->PickXYZ[0] = pinter[0];
10532                            PR->PickXYZ[1] = pinter[1];
10533                            PR->PickXYZ[2] = pinter[2];
10534                            PR->ignore_same_datum = IgnoreSameNode;
10535                            PR->datum_index = I1d;
10536                            PR->iAltSel[SUMA_VOL_I] = I[0];
10537                            PR->iAltSel[SUMA_VOL_J] = I[1];
10538                            PR->iAltSel[SUMA_VOL_K] = I[2];
10539                            PR->iAltSel[SUMA_VOL_IJK] = I1d;
10540                            PR->iAltSel[SUMA_VOL_SLC_NUM] = rslc->slc_num;
10541                            PR->iAltSel[SUMA_VOL_SLC_VARIANT] =
10542                                  (int)SUMA_SlcVariantToCode(rslc->variant);
10543                            PR->dAltSel[SUMA_VOL_SLC_EQ0] = rslc->Eq[0];
10544                            PR->dAltSel[SUMA_VOL_SLC_EQ1] = rslc->Eq[1];
10545                            PR->dAltSel[SUMA_VOL_SLC_EQ2] = rslc->Eq[2];
10546                            PR->dAltSel[SUMA_VOL_SLC_EQ3] = rslc->Eq[3];
10547                            PR->dset_idcode_str = SUMA_replace_string(
10548                                            PR->dset_idcode_str, SDSET_ID(dset));
10549                            if (!SUMA_Add_To_PickResult_List(sv, ado,
10550                                                             "voxel", &PR)) {
10551                               SUMA_S_Err("Failed to add selected ado");
10552                               SUMA_RETURN(0);
10553                            }
10554                            Hit = 1;
10555                            ++N_Hit;
10556                            /* You could leave at the first hit IF:
10557                            you only have one direction of slices in the
10558                            entire stack, AND if they are properly
10559                            ordered for rendering.
10560                            Should speed be an issue you can check for
10561                            this condition and bolt with the line below */
10562                            /* goto GOT_IT; */
10563                       }
10564                   }
10565                   ++ive;
10566                }
10567             }
10568             SUMA_LH("el now %p,\n"
10569                     "tail = %p, N_Hit = %d",
10570                     el, dlist_tail(VSaux->vrslcl), N_Hit);
10571          } while(el != dlist_tail(VSaux->vrslcl));
10572       }
10573    }
10574 
10575 
10576    GOT_IT:
10577    SUMA_RETURN(N_Hit);
10578 }/* determine intersection with 3D rendering of VO*/
10579 
SUMA_Apply_PR_VO(SUMA_SurfaceViewer * sv,SUMA_VolumeObject * VO,SUMA_PICK_RESULT ** PRi)10580 int SUMA_Apply_PR_VO(SUMA_SurfaceViewer *sv, SUMA_VolumeObject *VO,
10581                      SUMA_PICK_RESULT **PRi)
10582 {
10583    static char FuncName[]={"SUMA_Apply_PR_VO"};
10584    SUMA_ALL_DO *ado=NULL;
10585    int iv3[3], iv15[15];
10586    float fv15[15];
10587    DList *list = NULL;
10588    SUMA_Boolean NodeIgnored = NOPE;
10589    SUMA_PICK_RESULT *PR;
10590    SUMA_EngineData *ED = NULL;
10591    SUMA_DSET *dset=NULL;
10592    DListElmt *Location=NULL, *el=NULL, *SetNodeElem = NULL;
10593    SUMA_Boolean LocalHead = NOPE;
10594 
10595    SUMA_ENTRY;
10596 
10597    // fprintf(stderr, "%s\n", FuncName);
10598 
10599    SUMA_LH("Here");
10600    if (!sv || !VO || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
10601 
10602    /* Mark intersection Facsets */
10603    ado = (SUMA_ALL_DO *)VO;
10604 
10605    PR = *PRi;   /* Keep local copy */
10606    /* Store the PR in ado, hide it from return potential */
10607    SUMA_ADO_StorePickResult(ado, PRi);
10608 
10609    if (!(dset = SUMA_FindDset_s(PR->dset_idcode_str, SUMAg_CF->DsetList))) {
10610       SUMA_S_Err("NULL dset?");
10611       SUMA_RETURN(0);
10612    }
10613 
10614    sv->Focus_DO_ID = ADO_iDO(ado);
10615    SUMA_UpdateViewerTitle(sv);
10616 
10617    /* if the surface controller is open, update it */
10618    if (SUMA_isADO_Cont_Realized(ado))
10619       SUMA_Init_SurfCont_SurfParam(ado);
10620 
10621    fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
10622    fprintf(SUMA_STDOUT, "Selected voxel RAI [%.3f %.3f %.3f]mm \n"
10623                         "               IJK [%ld %ld %ld] on volume %s.\n",
10624       PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2],
10625       PR->iAltSel[SUMA_VOL_I], PR->iAltSel[SUMA_VOL_J], PR->iAltSel[SUMA_VOL_K],
10626       SDSET_FILENAME(dset));
10627    fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
10628 
10629 
10630    /* Set the voxel selection */
10631    if (!list) list = SUMA_CreateList();
10632    if (PR->ignore_same_datum &&
10633         SUMA_ADO_SelectedDatum(ado, NULL, NULL) == PR->datum_index) {
10634       SUMA_LHv("Ignoring identical voxel selection %d on volume %s\n",
10635                SUMA_ADO_SelectedDatum(ado, NULL, NULL), SUMA_ADO_Label(ado));
10636       NodeIgnored = YUP;
10637    } else {
10638       ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
10639       SetNodeElem = SUMA_RegisterEngineListCommand (  list, ED,
10640                                              SEF_i, (void*)&PR->datum_index,
10641                                              SES_Suma, (void *)sv, NOPE,
10642                                              SEI_Head, NULL);
10643       if (!SetNodeElem) {
10644          fprintf( SUMA_STDERR,
10645                   "Error %s: Failed to register SetNodeElem\n", FuncName);
10646          SUMA_RETURN (-1);
10647       } else {
10648          SUMA_RegisterEngineListCommand (  list, ED,
10649                                            SEF_ngr, NULL,
10650                                            SES_Suma, (void *)sv, NOPE,
10651                                            SEI_In, SetNodeElem);
10652       }
10653 
10654       iv15[SUMA_VOL_I] = (int)PR->iAltSel[SUMA_VOL_I];
10655       iv15[SUMA_VOL_J] = (int)PR->iAltSel[SUMA_VOL_J];
10656       iv15[SUMA_VOL_K] = (int)PR->iAltSel[SUMA_VOL_K];
10657       iv15[SUMA_VOL_IJK] = (int)PR->iAltSel[SUMA_VOL_IJK];
10658 
10659       fv15[SUMA_VOL_SLC_EQ0] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ0];
10660       fv15[SUMA_VOL_SLC_EQ1] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ1];
10661       fv15[SUMA_VOL_SLC_EQ2] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ2];
10662       fv15[SUMA_VOL_SLC_EQ3] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ3];
10663 
10664       SUMA_RegisterEngineListCommand (  list, ED,
10665                                         SEF_iv15, (void *)iv15,
10666                                         SES_Suma, (void *)sv, NOPE,
10667                                         SEI_In, SetNodeElem);
10668       SUMA_RegisterEngineListCommand (  list, ED,
10669                                         SEF_fv15, (void *)fv15,
10670                                         SES_Suma, (void *)sv, NOPE,
10671                                         SEI_In, SetNodeElem);
10672    }
10673 
10674 
10675    /* Now set the cross hair position at the selected node*/
10676    if (!list) list = SUMA_CreateList();
10677    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
10678    if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
10679                                           SEF_fv3, (void*)PR->PickXYZ,
10680                                           SES_Suma, (void *)sv, NOPE,
10681                                           SEI_Head, NULL))) {
10682       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10683       SUMA_RETURN(-1);
10684    }
10685    /* and add the object with this location */
10686    SUMA_RegisterEngineListCommand (  list, ED,
10687                                      SEF_vp, (void *)dset,
10688                                      SES_Suma, (void *)sv, NOPE,
10689                                      SEI_In, Location);
10690 
10691    /* attach the cross hair to the selected object
10692    Note that binding here is to voxel of dset */
10693    iv3[0] = ADO_iDO(ado);
10694    iv3[1] = PR->iAltSel[SUMA_VOL_IJK];
10695    iv3[2] = -1;
10696 
10697    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
10698    if (!SUMA_RegisterEngineListCommand (  list, ED,
10699                                           SEF_iv3, (void*)iv3,
10700                                           SES_Suma, (void *)sv, NOPE,
10701                                           SEI_Head, NULL)) {
10702       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10703       SUMA_RETURN(-1);
10704    }
10705 
10706    /* call with the list */
10707    if (!SUMA_Engine (&list)) {
10708       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
10709       SUMA_RETURN(-1);
10710    }
10711 
10712    /* check to see if AFNI needs to be notified */
10713    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
10714        sv->LinkAfniCrossHair) {
10715       int it;
10716       SUMA_LH("Notifying Afni of CrossHair XYZ");
10717       /* register a call to SetAfniCrossHair */
10718       if (!list) list = SUMA_CreateList();
10719       it = SUMA_ShftCont_Event(PR->evr);
10720       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
10721       if (!SUMA_RegisterEngineListCommand (  list, ED,
10722                                           SEF_i, (void*)&it,
10723                                           SES_Suma, (void *)sv, NOPE,
10724                                           SEI_Tail, NULL)) {
10725          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10726          SUMA_RETURN (-1);
10727       }
10728       if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
10729          SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
10730          DListElmt *Location=NULL;
10731          if (ado && ado->do_type == MASK_type) {
10732             SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
10733             ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
10734             if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
10735                                                 SEF_fv3, (void*)mdo->cen,
10736                                                 SES_Suma, (void *)sv, NOPE,
10737                                                 SEI_Tail, NULL))) {
10738                SUMA_S_Err("Failed to register element\n");
10739                SUMA_RETURN (-1);
10740             }
10741             SUMA_RegisterEngineListCommand (  list, ED,
10742                                            SEF_s, (void *)(ADO_ID(ado)),
10743                                            SES_Suma, (void *)sv, NOPE,
10744                                            SEI_In, Location);
10745          }
10746       }
10747       if (!SUMA_Engine (&list)) {
10748          fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
10749          SUMA_RETURN(-1);
10750       }
10751    }
10752 
10753    SUMA_RETURN(1);
10754 }
10755 
10756 /*!
10757    \brief Show the contents of a brush stroke
10758    SUMA_ShowBrushStroke (sv, Out);
10759 
10760 */
SUMA_ShowBrushStroke(SUMA_SurfaceViewer * sv,FILE * out)10761 void SUMA_ShowBrushStroke (SUMA_SurfaceViewer *sv, FILE *out)
10762 {
10763    static char FuncName[]={"SUMA_ShowBrushStroke"};
10764    int i, k, N=0;
10765    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
10766    DListElmt *Next_Elm = NULL;
10767 
10768    SUMA_ENTRY;
10769 
10770    // fprintf(stderr, "%s\n", FuncName);
10771 
10772    if (!out) out = SUMA_STDERR;
10773 
10774    if (!sv->BS) {
10775       fprintf(out, "%s: NULL sv->BS\n", FuncName);
10776       SUMA_RETURNe;
10777    }
10778 
10779    N = dlist_size(sv->BS);
10780    if (!N) {
10781       fprintf(out, "%s: Empty sv->BS. (N = 0)\n", FuncName);
10782       SUMA_RETURNe;
10783    }
10784 
10785    fprintf(out, "%s: Brush stroke has %d elements:\n", FuncName, N);
10786 
10787    i = 0;
10788    do {
10789       if (Next_Elm==NULL) Next_Elm = dlist_head(sv->BS);
10790       else Next_Elm = Next_Elm->next;
10791       if (!Next_Elm->data) {
10792          fprintf(out, "%s: Element->data %d is NULL!\n", FuncName, i);
10793       }else {
10794          bsd = (SUMA_BRUSH_STROKE_DATUM *)Next_Elm->data;
10795          fprintf(out, "%d: (%f %f) [%.2f, %.2f, %.2f <--> %.2f, %.2f, %.2f]\t Node  %d, Tri %d\n",
10796                      i, bsd->x, bsd->y,
10797                      bsd->NP[0], bsd->NP[1], bsd->NP[2],
10798                      bsd->FP[0], bsd->FP[1], bsd->FP[2],
10799                      bsd->SurfNode, bsd->SurfTri);
10800       }
10801       ++i;
10802    }while (dlist_tail(sv->BS) != Next_Elm);
10803 
10804    fprintf(out, "\n");
10805 
10806    SUMA_RETURNe;
10807 }
10808 
10809 /*!
10810    \brief Clear the contents of sv->BS and sets it to NULL
10811 
10812    SUMA_ClearBrushStroke (sv);
10813 
10814 
10815    \sa SUMA_CreateBrushStroke
10816 */
SUMA_ClearBrushStroke(SUMA_SurfaceViewer * sv)10817 void  SUMA_ClearBrushStroke (SUMA_SurfaceViewer *sv)
10818 {
10819    static char FuncName[]={"SUMA_ClearBrushStroke"};
10820 
10821    SUMA_ENTRY;
10822 
10823    // fprintf(stderr, "%s\n", FuncName);
10824 
10825    /* THE NEW VERSION */
10826    if (sv->BS) {
10827       SUMA_EmptyDestroyList(sv->BS);
10828       sv->BS = NULL;
10829    }
10830 
10831    SUMA_RETURNe;
10832 }
10833 /*!
10834    \brief Creates the BrushStroke structure inside sv structure
10835    success = SUMA_CreateBrushStroke (sv);
10836 
10837    \param sv (SUMA_SurfaceViewer *) Surface viewer structure
10838    \return YUP/NOPE
10839 
10840    sv->BS must be null before this function is called.
10841    The liat and its components are then allocated for.
10842 
10843    \sa SUMA_ClearBrushStroke
10844 */
SUMA_CreateBrushStroke(SUMA_SurfaceViewer * sv)10845 SUMA_Boolean  SUMA_CreateBrushStroke (SUMA_SurfaceViewer *sv)
10846 {
10847    static char FuncName[]={"SUMA_CreateBrushStroke"};
10848 
10849    SUMA_ENTRY;
10850 
10851    // fprintf(stderr, "%s\n", FuncName);
10852 
10853    /* New Version */
10854    if (sv->BS) {  /* bad news, this should be NULL to begin with */
10855       SUMA_RegisterMessage (SUMAg_CF->MessageList,
10856                             "Brush Stroke not NULL.", FuncName,
10857                             SMT_Critical, SMA_LogAndPopup);
10858       SUMA_RETURN(NOPE);
10859 
10860    }
10861    sv->BS = (DList *)SUMA_calloc(1,sizeof(DList));
10862    dlist_init(sv->BS, SUMA_FreeBSDatum);
10863 
10864    SUMA_RETURN (YUP);
10865 }
10866 
SUMA_CreateBSDatum(void)10867 SUMA_BRUSH_STROKE_DATUM * SUMA_CreateBSDatum(void)
10868 {
10869    static char FuncName[]={"SUMA_CreateBSDatum"};
10870    SUMA_BRUSH_STROKE_DATUM *bsd = NULL;
10871 
10872    SUMA_ENTRY;
10873 
10874    // fprintf(stderr, "%s\n", FuncName);
10875 
10876    bsd = (SUMA_BRUSH_STROKE_DATUM *)
10877             SUMA_calloc(1,sizeof(SUMA_BRUSH_STROKE_DATUM));
10878    if (!bsd) {
10879       SUMA_RegisterMessage (SUMAg_CF->MessageList,
10880                             "Failed to allocate.", FuncName,
10881                             SMT_Critical, SMA_LogAndPopup);
10882       SUMA_RETURN(NULL);
10883    }
10884    /* setup defaults */
10885    bsd->x = bsd->y = 0.0;
10886    bsd->NP[0] = bsd->NP[1] = bsd->NP[2] = 0.0;
10887    bsd->FP[0] = bsd->FP[1] = bsd->FP[2] = 0.0;
10888    bsd->SurfNode = -1;
10889    bsd->SurfTri = -1;
10890    bsd->Decimated = NOPE;
10891 
10892    SUMA_RETURN(bsd);
10893 }
10894 
10895 /*!
10896    \brief free a brush stroke datum that is contained inside the doubly linked BS
10897 */
SUMA_FreeBSDatum(void * bsd)10898 void SUMA_FreeBSDatum (void *bsd)
10899 {
10900    static char FuncName[]={"SUMA_FreeBSDatum"};
10901 
10902    SUMA_ENTRY;
10903 
10904    // fprintf(stderr, "%s\n", FuncName);
10905 
10906    /* nothing is allocated for inside bsd */
10907    if (bsd) SUMA_free(bsd);
10908 
10909    SUMA_RETURNe;
10910 }
10911 
10912 
10913 
10914 /*!
10915    \brief Adds, new point to the brush stroke
10916    success = SUMA_AddToBrushStroke ( sv,  x,  y, Show);
10917 
10918    \param sv (SUMA_SurfaceViewer *) pointer to surface viewer where stroke is occuring
10919    \param x (int) X coordinate of mouse
10920    \param y (int) Y coordinate of mouse
10921    \param NP (GLdouble *) vector of XYZ coordinates of Near Plane intersection point
10922    \param FP (GLdouble *) vector of XYZ coordinates of Far Plane intersection point.
10923    \param Show (SUMA_Boolean) if YUP: Then trace is drawn as you move the mouse
10924    \return YUP/NOPE, success indicator
10925 
10926 */
SUMA_AddToBrushStroke(SUMA_SurfaceViewer * sv,int x,int y,GLdouble * NP,GLdouble * FP,SUMA_Boolean Show)10927 SUMA_Boolean  SUMA_AddToBrushStroke (SUMA_SurfaceViewer *sv, int x, int y, GLdouble *NP, GLdouble *FP, SUMA_Boolean Show)
10928 {
10929    static char FuncName[]={"SUMA_AddToBrushStroke"};
10930    int ip;
10931    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
10932 
10933    SUMA_ENTRY;
10934 
10935    // fprintf(stderr, "%s\n", FuncName);
10936 
10937    /* New version */
10938    bsd = SUMA_CreateBSDatum();
10939    bsd->x = (float)x;
10940    bsd->y = (float)y;
10941    bsd->NP[0] = NP[0]; bsd->NP[1] = NP[1]; bsd->NP[2] = NP[2];
10942    bsd->FP[0] = FP[0]; bsd->FP[1] = FP[1]; bsd->FP[2] = FP[2];
10943    dlist_ins_next (sv->BS, dlist_tail(sv->BS), (void*)bsd);
10944 
10945    /* incremental draw */
10946    if (Show) SUMA_DrawBrushStroke (sv, YUP);
10947 
10948    SUMA_RETURN (YUP);
10949 }
10950 
10951 /*!
10952    Sets the foreground color of the drawing area
10953 */
SUMA_SetSVForegroundColor(SUMA_SurfaceViewer * sv,const char * Color)10954 void SUMA_SetSVForegroundColor (SUMA_SurfaceViewer *sv, const char *Color)
10955 {
10956    static char FuncName[]={"SUMA_SetSVForegroundColor"};
10957    XColor col, unused;
10958 
10959    SUMA_ENTRY;
10960 
10961    // fprintf(stderr, "%s\n", FuncName);
10962 
10963    #ifdef DARWIN
10964       SUMA_S_Warn("Calling this function from OS X seems to cause trouble");
10965    #endif
10966 
10967    /* using sv->X->CMAP instead of
10968             DefaultColormapOfScreen(XtScreen(sv->X->GLXAREA))
10969       is useless */
10970    if (!XAllocNamedColor (sv->X->DPY,
10971                DefaultColormapOfScreen(XtScreen(sv->X->GLXAREA)),
10972                Color, &col, &unused)) {
10973       fprintf (SUMA_STDERR,
10974             "Error %s: Can't allocate for %s color.\n", FuncName, Color);
10975       SUMA_RETURNe;
10976    }
10977    XSetForeground (sv->X->DPY, sv->X->gc, col.pixel);
10978 
10979    SUMA_RETURNe;
10980 }
10981 
10982 /*!
10983    \brief Draws the brushstroke
10984 
10985    \param sv (SUMA_SurfaceViewer *) pointer to surface viewer structure
10986    \param incremental (SUMA_Boolean) YUP: draw a line between the last two points
10987                                      NOPE: draw the whole thing
10988 
10989    - NB: This function used to crash when run on SGI if display is not
10990    in TrueColor mode.
10991    This happens even though the visual chosen by SUMA does not change.
10992    To put the SGI in true color mode, you need to add to /var/X11/xdm/Xservers
10993    the following:  -class TrueColor -depth 24
10994    and then restart X or the system.
10995    The bug was that the graphics context (sv->X->gc) was created using the
10996    Screen's root window and not the GLX visual's window.
10997 */
SUMA_DrawBrushStroke(SUMA_SurfaceViewer * sv,SUMA_Boolean incr)10998 void SUMA_DrawBrushStroke (SUMA_SurfaceViewer *sv, SUMA_Boolean incr)
10999 {
11000    static char FuncName[]={"SUMA_DrawBrushStroke"};
11001    int i, N;
11002    DListElmt *NE=NULL, *NEn=NULL;
11003    SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *bsdn = NULL;
11004 
11005    SUMA_ENTRY;
11006 
11007    // fprintf(stderr, "%s\n", FuncName);
11008 
11009    if (!sv->BS) SUMA_RETURNe;
11010 
11011    N = dlist_size(sv->BS);
11012    if (N < 2) SUMA_RETURNe;
11013 
11014    if (!incr) {
11015       do {
11016          if (!NE) NE = dlist_head(sv->BS);
11017          else NE = NE->next;
11018 
11019          NEn = NE->next;
11020 
11021          bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
11022          bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
11023 
11024          SUMA_DrawWindowLine( sv, (int)bsd->x, (int)bsd->y,
11025                               (int)bsdn->x, (int)bsdn->y, 1);
11026       } while (NEn != dlist_tail(sv->BS));
11027 
11028    } else {
11029       NEn = dlist_tail(sv->BS);
11030       NE = NEn->prev;
11031 
11032       bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
11033       bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
11034 
11035       SUMA_DrawWindowLine( sv,
11036                            (int)bsd->x, (int)bsd->y,
11037                            (int)bsdn->x, (int)bsdn->y, 1 );
11038 
11039    }
11040    SUMA_RETURNe;
11041 
11042 }
11043 
11044 /*!
11045    \brief Processes the brushstroke sent from a viewer
11046 
11047 */
SUMA_ProcessBrushStroke(SUMA_SurfaceViewer * sv,SUMA_BRUSH_STROKE_ACTION BsA)11048 SUMA_DRAWN_ROI * SUMA_ProcessBrushStroke
11049                   (SUMA_SurfaceViewer *sv, SUMA_BRUSH_STROKE_ACTION BsA)
11050 {
11051    static char FuncName[]={"SUMA_ProcessBrushStroke"};
11052    SUMA_DRAWN_ROI *DrawnROI = NULL;
11053    SUMA_ROI_DATUM *ROIstroke = NULL, *ROIlink=NULL, *ROIfill=NULL;
11054    SUMA_SurfaceObject *SO = NULL;
11055    int ii=0, TailNode = -1, FirstSurfNode = -1, ft = -1, N_SurfNode = 0;
11056    int HeadNode = -1, *ROI_Mask=NULL, N_ROI_Mask = 0;
11057    DListElmt *El = NULL;
11058    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11059    char *sbuf;
11060    SUMA_ROI_ACTION_STRUCT *ROIA;
11061    DListElmt *tmpStackPos=NULL;
11062    SUMA_Boolean Shaded = NOPE, LocalHead = NOPE;
11063 
11064    SUMA_ENTRY;
11065 
11066    // fprintf(stderr, "%s\n", FuncName);
11067 
11068    SO = SUMA_SV_Focus_SO(sv);
11069 
11070    if (!SO) {
11071       fprintf (SUMA_STDERR,
11072                "%s: No surface object in focus, nothing to do.\n", FuncName);
11073       SUMA_RETURN (DrawnROI);
11074    }
11075 
11076    if (!sv->BS) {
11077       fprintf (SUMA_STDERR,
11078                "%s: No Brushstroke (BS), nothing to do.\n", FuncName);
11079       SUMA_RETURN (DrawnROI);
11080    }
11081 
11082    if (!SUMAg_CF->ROI_mode) {
11083       fprintf (SUMA_STDERR, "%s: Not in ROI mode, nothing to do.\n", FuncName);
11084       SUMA_RETURN (DrawnROI);
11085    }
11086 
11087    /* We are in ROI mode,
11088       is there an ROI in curDrawnROI that works with the current surface ? */
11089    if (SUMAg_CF->X->DrawROI->curDrawnROI) {
11090       if (  SUMA_isdROIrelated(SUMAg_CF->X->DrawROI->curDrawnROI,
11091                                                    (SUMA_ALL_DO *)SO) &&
11092             SUMAg_CF->X->DrawROI->curDrawnROI->DrawStatus != SUMA_ROI_Finished){
11093          if (LocalHead)
11094             fprintf (SUMA_STDERR,"%s: using currDrawnROI.\n", FuncName);
11095          DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
11096       }else {
11097          if (LocalHead)
11098             fprintf (SUMA_STDERR,
11099                      "%s: No match between currDrawnROI and SO.\n", FuncName);
11100          DrawnROI = NULL;
11101       }
11102    }
11103    if (!DrawnROI) { /* try some more */
11104       if ((DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv, SUMAg_N_DOv))){
11105          if (LocalHead)
11106             fprintf (SUMA_STDERR,"%s: using ROI in creation.\n", FuncName);
11107          /* There is an ROI being created on this surface,
11108             initialize DrawROI window*/
11109          SUMA_InitializeDrawROIWindow(DrawnROI);
11110       } else {
11111          /* wait till later */
11112          if (LocalHead)
11113             fprintf (SUMA_STDERR,"%s: will create a new ROI.\n", FuncName);
11114       }
11115    }
11116 
11117    if (!DrawnROI && BsA == SUMA_BSA_JoinEnds) {
11118       SUMA_SLP_Err ("NO ROI to close.");
11119       SUMA_RETURN (DrawnROI);
11120    }
11121 
11122    if (!DrawnROI) { /* No ROI found, create one */
11123       if (LocalHead)
11124          fprintf (SUMA_STDERR,
11125                   "%s: No ROI found, creating a new one.\n", FuncName);
11126       SUMA_GET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIlbl->textfield, sbuf);
11127       DrawnROI = SUMA_AllocateDrawnROI (SO->idcode_str, SUMA_ROI_InCreation,
11128                                         SUMA_ROI_OpenPath,
11129                                         sbuf,
11130                                         SUMAg_CF->X->DrawROI->ROIval->value);
11131       if (!DrawnROI) {
11132          SUMA_RegisterMessage (SUMAg_CF->MessageList,
11133                                "Failed to allocate for DrawnROI.", FuncName,
11134                                SMT_Critical, SMA_LogAndPopup);
11135          SUMA_RETURN (NULL);
11136       }
11137 
11138       /* Although ROIs are stored as DOs,
11139          they are dependent on the surfaces they are related to
11140          ROIs at this stage are node indices only (and perhaps the mesh) but the          coordinates of the indices
11141          come from the surface onto which they are displayed. So when you are
11142          drawing a surface, using CreateMesh,
11143          you will search DOv for ROIs related to the surface displayed and
11144          overlay them accordingly */
11145       /* Add the ROI to DO */
11146       if (!SUMA_AddDO ( SUMAg_DOv, &SUMAg_N_DOv,
11147                         (void *)DrawnROI, ROIdO_type, SUMA_WORLD)) {
11148          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
11149       }
11150 
11151       /* is the Switch ROI window open ? */
11152       SUMA_IS_DRAW_ROI_SWITCH_ROI_SHADED(Shaded);
11153       if (!Shaded) {
11154          SUMA_cb_DrawROI_SwitchROI (
11155                NULL,
11156                (XtPointer) SUMAg_CF->X->DrawROI->SwitchROIlst,
11157                NULL);
11158       }
11159 
11160 
11161    } else {
11162       if (LocalHead)
11163          fprintf( SUMA_STDOUT,
11164                   "%s: ROI %p fetched. Status %d.\n",
11165                   FuncName, DrawnROI, DrawnROI->DrawStatus);
11166    }
11167 
11168    if (BsA == SUMA_BSA_AppendStrokeOrFill) {
11169       if (  DrawnROI->Type == SUMA_ROI_ClosedPath ||
11170             DrawnROI->Type == SUMA_ROI_FilledArea)
11171          BsA = SUMA_BSA_FillArea;
11172       else if (DrawnROI->Type == SUMA_ROI_OpenPath)
11173          BsA = SUMA_BSA_AppendStroke;
11174    }
11175    if (  DrawnROI->Type == SUMA_ROI_ClosedPath &&
11176          BsA != SUMA_BSA_FillArea) {
11177       SUMA_SLP_Err ( "You can only fill a closed path.\n"
11178                      "You cannot append more paths to it.");
11179       SUMA_RETURN (DrawnROI);
11180    }
11181    if (  DrawnROI->Type == SUMA_ROI_FilledArea &&
11182          BsA != SUMA_BSA_FillArea) {
11183       SUMA_SLP_Err ("You cannot add paths to a filled ROI.");
11184       SUMA_RETURN (DrawnROI);
11185    }
11186 
11187    /* Good, now initialize the DrawROI widget, if needed */
11188    if (SUMAg_CF->X->DrawROI->curDrawnROI != DrawnROI) {
11189       if (!SUMA_InitializeDrawROIWindow (DrawnROI)) {
11190          SUMA_SL_Err("Failed to initialize DrawWindow.");
11191       }
11192    }
11193 
11194    /* Now you must transform the brushstroke to a series of nodes
11195       (not necessarily connected)*/
11196    if (LocalHead)
11197       fprintf (SUMA_STDERR,
11198                "%s: Turning BrushStroke to NodeStroke ...\n", FuncName);
11199    if (!SUMA_BrushStrokeToNodeStroke (sv)) {
11200       SUMA_RegisterMessage (SUMAg_CF->MessageList,
11201                          "Failed in SUMA_BrushStrokeToNodeStroke.", FuncName,
11202                          SMT_Error, SMA_LogAndPopup);
11203       SUMA_RETURN(NULL);
11204    }
11205 
11206    switch (BsA) {
11207       case SUMA_BSA_AppendStroke:
11208          /* Turn the brush stroke into a series of connected nodes */
11209          if (LocalHead)
11210             fprintf (SUMA_STDERR,
11211                      "%s: Turning NodeStroke to ROIStroke ...\n", FuncName);
11212          if (!(ROIstroke = SUMA_NodeStrokeToConnectedNodes (sv))) {
11213             SUMA_RegisterMessage (SUMAg_CF->MessageList,
11214                                   "Failed in SUMA_NodeStrokeToConnectedNodes.",
11215                                   FuncName,
11216                                   SMT_Critical, SMA_LogAndPopup);
11217             if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink);
11218             ROIlink = NULL;
11219             if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke);
11220             ROIstroke = NULL;
11221             SUMA_RETURN(NULL);
11222          }
11223 
11224          if (LocalHead)
11225             fprintf (SUMA_STDERR,
11226                      "%s: Turning NodeStroke to ROIStroke . DONE.\n",
11227                      FuncName);
11228          /* if this is the first element of ROI,
11229             create the first ROIdatum and get out */
11230          if (dlist_size(DrawnROI->ROIstrokelist)) {
11231             /* Not the beginning of an ROI */
11232             if (LocalHead)
11233                fprintf (SUMA_STDERR,
11234                         "%s: Adding ROIstroke to previous ones ...\n",
11235                         FuncName);
11236             /* make sure new brushstroke is not just one node that is
11237                the tail of the ROI*/
11238             SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI,TailNode);
11239 
11240             SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
11241             SUMA_BS_COUNT_SURF_NODES(sv->BS, N_SurfNode);
11242             if (FirstSurfNode == TailNode && N_SurfNode == 1) {
11243                /* nothing to do here */
11244                fprintf (SUMA_STDERR,
11245                         "%s: New stroke has one node that is \n"
11246                         "identical to tail node. Dumping element.\n", FuncName);
11247                SUMA_RETURN(DrawnROI);
11248             }
11249 
11250             /* Connect this chunk to the last open Node in ROI */
11251             if (FirstSurfNode != TailNode) {
11252                if (LocalHead)
11253                   fprintf (SUMA_STDERR,
11254                            "%s: linking Tail Node to New stroke.\n", FuncName);
11255 
11256                ROIlink = SUMA_LinkTailNodeToNodeStroke (sv, DrawnROI);
11257                if (!ROIlink) {
11258                   SUMA_SL_Err("Failed to connect Tail node to Node stroke\n"
11259                               ", try again.");
11260                   SUMA_RETURN(NULL);
11261                }
11262                if (LocalHead) {
11263                   fprintf (SUMA_STDERR,
11264                            "%s: RIOlink, before prepending:\n", FuncName);
11265                   SUMA_ShowDrawnROIDatum (ROIlink, NULL, NOPE);
11266                }
11267 
11268                /* connect the ROIlink with the ROIstroke */
11269                if (LocalHead) {
11270                   fprintf (SUMA_STDERR,
11271                            "%s: RIOstroke, before prepending:\n", FuncName);
11272                   SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
11273                }
11274                if (!SUMA_PrependToROIdatum (ROIlink, ROIstroke)) {
11275                   SUMA_RegisterMessage (SUMAg_CF->MessageList,
11276                                      "Failed to merge ROIs.", FuncName,
11277                                      SMT_Critical, SMA_LogAndPopup);
11278                   if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink);
11279                   ROIlink = NULL;
11280                   if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke);
11281                   ROIstroke = NULL;
11282                   SUMA_RETURN(NULL);
11283                }
11284 
11285                if (LocalHead) {
11286                   fprintf (SUMA_STDERR,
11287                            "%s: RIOstroke, after prepending:\n", FuncName);
11288                   SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
11289                }
11290               /* now free ROIlink, not needed anymore */
11291                if (ROIlink) SUMA_FreeROIDatum ((void *)ROIlink); ROIlink = NULL;
11292             }
11293          }else{
11294             if (LocalHead)
11295                fprintf (SUMA_STDERR, "%s: First ROIStroke of ROI.\n", FuncName);
11296          }
11297          break;
11298       case SUMA_BSA_JoinEnds:
11299          /* Join ends here */
11300          if (DrawnROI) { /*   close ROI */
11301             SUMA_DRAWN_ROI_HEAD_NODE(DrawnROI,HeadNode);
11302             SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
11303             bsd = (SUMA_BRUSH_STROKE_DATUM *)El->data;
11304             if (LocalHead)
11305                fprintf( SUMA_STDERR,
11306                         "%s: Trying to join node %d to node %d.\n",
11307                         FuncName, FirstSurfNode, HeadNode);
11308             /* Now compute the intersection of the surface with the plane */
11309             ROIstroke = SUMA_Surf_Plane_Intersect_ROI (  SO, FirstSurfNode,
11310                                                          HeadNode, bsd->NP);
11311 
11312             if (!ROIstroke) {
11313                SUMA_SL_Err ("Failed to close path. Repeat new stroke.");
11314                SUMA_RETURN(DrawnROI);
11315             }
11316             /* what is the last node of ROIstroke ?
11317             It is possible that the returned ROIstroke
11318             was not a successful closure (a partial success), investigate*/
11319             if (LocalHead)
11320                fprintf( SUMA_STDERR,
11321                         "%s: Last node of ROIstroke is %d\n",
11322                         FuncName, ROIstroke->nPath[ROIstroke->N_n-1]);
11323             if (ROIstroke->nPath[ROIstroke->N_n-1] != HeadNode) {
11324                /* pretend this is not a JoinEnds exercice */
11325                BsA = SUMA_BSA_AppendStroke;
11326                SUMA_SL_Err ("Failed to close path. Continue with stroke.");
11327                SUMA_RETURN(DrawnROI);
11328             }else {
11329                /* Do not remove the last point from ROIstroke,
11330                   otherwise it will make drawing a closed ROI painful */
11331             }
11332          } else {
11333             /* tremors, nothing to do */
11334          }
11335          break;
11336       case SUMA_BSA_FillArea:
11337          SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
11338          if (LocalHead)
11339             fprintf (SUMA_STDERR,
11340                      "%s: Should be filling from node %d\n",
11341                      FuncName, FirstSurfNode);
11342 
11343          /* create the mask from ROIs on this surface */
11344          switch (SUMAg_CF->ROI_FillMode) {
11345             case SUMA_ROI_FILL_TO_ALLROI:
11346                ROI_Mask = SUMA_Build_Mask_AllROI ( SUMAg_DOv, SUMAg_N_DOv,
11347                                                    SO, NULL, &N_ROI_Mask);
11348                break;
11349             case SUMA_ROI_FILL_TO_THISROI:
11350                ROI_Mask = (int *)SUMA_calloc (SO->N_Node, sizeof(int));
11351                if (!ROI_Mask) {
11352                   SUMA_SLP_Crit("Failed to allocate");
11353                   SUMA_RETURN(DrawnROI);
11354                }
11355                SUMA_Build_Mask_DrawnROI (DrawnROI, ROI_Mask);
11356                break;
11357             default:
11358                SUMA_SLP_Err("No such mode.");
11359                SUMA_RETURN(DrawnROI);
11360                break;
11361          }
11362 
11363          /* Now fill it up */
11364          ROIfill = SUMA_FillToMask (SO, ROI_Mask, FirstSurfNode);
11365          if (ROI_Mask) SUMA_free(ROI_Mask); ROI_Mask = NULL;
11366          if (!ROIfill) {
11367             SUMA_SLP_Err(  "Failed to fill area:\n"
11368                            "Perhaps seed on edge\nor nothing to fill.");
11369             SUMA_RETURN(DrawnROI);
11370          }
11371 
11372          break;
11373       default:
11374          fprintf (SUMA_STDERR,
11375                   "Error %s: Why are you doing this to me ?.\n", FuncName);
11376          break;
11377    }
11378 
11379 
11380    /* Another switch on BsA,
11381       it is possible that its value changed within this function */
11382 
11383    switch (BsA) {
11384       case SUMA_BSA_AppendStroke:
11385          /* store the action */
11386          ROIstroke->action = SUMA_BSA_AppendStroke;
11387          /*now add the ROIdatum to the list of ROIs */
11388          if (LocalHead)
11389             fprintf (SUMA_STDERR,
11390                      "%s: Adding ROIStroke to DrawnROI->ROIstrokelist\n",
11391                      FuncName);
11392          ROIA = (SUMA_ROI_ACTION_STRUCT *)
11393                    SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
11394                    /* this structure is freed in SUMA_DestroyROIActionData */
11395          ROIA->DrawnROI = DrawnROI;
11396          ROIA->ROId = ROIstroke;
11397          tmpStackPos = SUMA_PushActionStack (
11398                            DrawnROI->ActionStack,
11399                            DrawnROI->StackPos, SUMA_AddToTailROIDatum,
11400                            (void *)ROIA, SUMA_DestroyROIActionData);
11401          if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
11402          else {
11403             fprintf (SUMA_STDERR,
11404                      "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
11405             SUMA_RETURN (DrawnROI);
11406          }
11407          if (  SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||
11408                SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll)
11409             SUMA_ReportDrawnROIDatumLength(  SO, ROIA->ROId, NULL,
11410                                              SUMAg_CF->X->DrawROI->WhatDist);
11411          break;
11412       case SUMA_BSA_JoinEnds:
11413          /* store the action */
11414          ROIstroke->action = SUMA_BSA_JoinEnds;
11415          if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing path.\n", FuncName);
11416          ROIA = (SUMA_ROI_ACTION_STRUCT *)
11417                    SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
11418                      /* this structure is freed in SUMA_DestroyROIActionData */
11419          ROIA->DrawnROI = DrawnROI;
11420          ROIA->ROId = ROIstroke;
11421          tmpStackPos = SUMA_PushActionStack (
11422                            DrawnROI->ActionStack, DrawnROI->StackPos,
11423                            SUMA_AddToTailJunctionROIDatum,
11424                            (void *)ROIA, SUMA_DestroyROIActionData);
11425          if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
11426          else {
11427             fprintf (SUMA_STDERR,
11428                      "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
11429             SUMA_RETURN (DrawnROI);
11430          }
11431          if (  SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||
11432                SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll)
11433             SUMA_ReportDrawnROIDatumLength(  SO, ROIA->ROId, NULL,
11434                                              SUMAg_CF->X->DrawROI->WhatDist);
11435          break;
11436       case SUMA_BSA_FillArea:
11437          /* store the action */
11438          ROIfill->action = SUMA_BSA_FillArea;
11439          /* Now add ROIdatum to stack */
11440          ROIA = (SUMA_ROI_ACTION_STRUCT *)
11441                    SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
11442                      /* this structure is freed in SUMA_DestroyROIActionData */
11443          ROIA->DrawnROI = DrawnROI;
11444          ROIA->ROId = ROIfill;
11445          tmpStackPos = SUMA_PushActionStack (
11446                            DrawnROI->ActionStack, DrawnROI->StackPos,
11447                            SUMA_AddFillROIDatum,
11448                            (void *)ROIA, SUMA_DestroyROIActionData);
11449          if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
11450          else {
11451             fprintf (SUMA_STDERR,
11452                "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
11453             SUMA_RETURN (DrawnROI);
11454          }
11455          break;
11456       default:
11457          fprintf (SUMA_STDERR,
11458             "Error %s: Why are you doing this to me ??.\n", FuncName);
11459          break;
11460    }
11461 
11462    /* Now update the Paint job on the ROI plane */
11463    if (!SUMA_Paint_SO_ROIplanes_w (SO, SUMAg_DOv, SUMAg_N_DOv)) {
11464       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
11465       SUMA_RETURN(DrawnROI);
11466    }
11467    if (BsA == SUMA_BSA_FillArea) {   /*  ZSS Sept 29 06 */
11468       SUMA_OVERLAYS *Overlay=NULL;
11469       int junk;
11470       /* If you're drawing, and have just filled an area,
11471          better pop the dset to the top so it is visible */
11472       if (!(Overlay = SUMA_Fetch_OverlayPointer((SUMA_ALL_DO *)SO,
11473                                                 DrawnROI->ColPlaneName,
11474                                                 &junk))) {
11475          SUMA_S_Err("Unexpected! Could not find overlay pointer");
11476       } else {
11477          /* if the current col plane is not the same as this one,
11478             do the switching please */
11479          SUMA_InitializeColPlaneShell((SUMA_ALL_DO *)SO, Overlay);
11480          SUMA_UpdateColPlaneShellAsNeeded((SUMA_ALL_DO *)SO);
11481                                           /* update other open
11482                                              ColPlaneShells */
11483       }
11484    }
11485 
11486    SUMA_RETURN(DrawnROI);
11487 }
11488 
11489 /*!
11490    Function that turns a brushstroke to a series of nodes on the surface.
11491 
11492    No surface paths are created from one node to the next yet.
11493 
11494    It is not always the case that BrushStroke->N_SurfNodes is equal
11495    to BrushStroke->N
11496 */
SUMA_BrushStrokeToNodeStroke(SUMA_SurfaceViewer * sv)11497 SUMA_Boolean SUMA_BrushStrokeToNodeStroke (SUMA_SurfaceViewer *sv)
11498 {
11499    static char FuncName[]={"SUMA_BrushStrokeToNodeStroke"};
11500    DList * NS=NULL;
11501    SUMA_SurfaceObject *SO=NULL;
11502    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
11503    float delta_t_tmp;
11504    struct timeval tt_tmp;
11505    int N = -1;
11506    SUMA_Boolean LocalHead=NOPE;
11507    SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *obsd=NULL;
11508    DListElmt *Elmt = NULL, *oElmt=NULL;
11509 
11510    SUMA_ENTRY;
11511 
11512    // fprintf(stderr, "%s\n", FuncName);
11513 
11514    if (!(SO = SUMA_SV_Focus_SO(sv))) {
11515       SUMA_S_Err("No surface in focus");
11516       SUMA_RETURN(NOPE);
11517    }
11518 
11519    /* ONLY WORK ON FocusSO */
11520    if (SO->FaceSetDim != 3) {
11521       SUMA_S_Err("SUMA_MT_intersect_triangle only works for triangular meshes.");
11522       SUMA_RETURN(NOPE);
11523    }
11524 
11525    N = dlist_size(sv->BS);
11526    if (!N) {
11527       fprintf (SUMA_STDERR, "%s: Empty brushstroke, nothing to do.\n", FuncName);
11528       SUMA_RETURN(NOPE);
11529    }else SUMA_LHv("%d element(s) in sv->BS.\n", N);
11530 
11531    /* the first node of the brushstroke is stored as the cross hair's node id,
11532       just copy it */
11533    Elmt = dlist_head(sv->BS);
11534    bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
11535 
11536    bsd->SurfNode = SO->SelectedNode;
11537    bsd->SurfTri = SO->SelectedFaceSet;
11538 
11539    #ifdef DISASTER_LOOP
11540       /* Now as a brute force method, do all the remaing nodes in the path.
11541       In the future, you want to downsample the path is some clever fashion */
11542       if (N > 1) {
11543          if (LocalHead) {
11544             fprintf (SUMA_STDERR, "%s: Disaster loop, hold on .\n", FuncName);
11545             SUMA_etime (&tt_tmp, 0);
11546          }
11547 
11548          MTI = NULL;
11549          do {
11550             Elmt = Elmt->next;
11551             bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
11552 
11553             MTI = SUMA_MT_intersect_triangle(   bsd->NP, bsd->FP,
11554                                                 SO->NodeList, SO->N_Node,
11555                                                 SO->FaceSetList, SO->N_FaceSet,
11556                                                 MTI,0);
11557 
11558             if (!MTI) {
11559                fprintf(SUMA_STDERR,"Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
11560                SUMA_RETURN (NOPE);
11561             }
11562 
11563             if (MTI->N_hits) { /* There is a hit, store it if useful */
11564                oElmt = Elmt->prev;
11565                obsd = (SUMA_BRUSH_STROKE_DATUM *)oElmt->data;
11566                if (obsd->SurfNode != MTI->inodemin) { /* a new one, bring it on */
11567                   bsd->SurfNode = MTI->inodemin;
11568                   bsd->SurfTri = MTI->ifacemin;
11569                }else {
11570                   /* destroy Elmt, it is redundant */
11571                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing redundant BS element.\n", FuncName);
11572                   dlist_remove (sv->BS, Elmt, (void*)(&bsd));
11573                   SUMA_FreeBSDatum (bsd);
11574                   Elmt = oElmt;
11575                }
11576             }
11577 
11578          }while (Elmt != dlist_tail(sv->BS));
11579 
11580          /* free MTI */
11581          MTI = SUMA_Free_MT_intersect_triangle(MTI);
11582 
11583          if (LocalHead) {
11584             delta_t_tmp = SUMA_etime (&tt_tmp, 1);
11585             if (LocalHead) fprintf (SUMA_STDERR, "Local Debug %s: Intersections took %f seconds.\n", FuncName, delta_t_tmp);
11586          }
11587 
11588       }
11589    #else
11590    if (N > 1) { /* new, faster method */
11591       DListElmt *Eli=NULL, *Eln=NULL;
11592       float ip[3], d[3];
11593       int IncTri[100], N_IncTri=0, n1=-1, n2=-1, n3=-1, ni = -1,
11594           ti = -1, N_Neighb=0,DeciLevel = 0, i, j, Removed=0;
11595       int DeciReentry=0, UsedNode[3]={ 0 , 0, 0 };
11596       SUMA_BRUSH_STROKE_DATUM *bsdi=NULL, *bsdn=NULL, *bsd_deci=NULL;
11597       SUMA_Boolean  DoesInters=NOPE; /* flag for Decimation mode */
11598       SUMA_Boolean  TrackOscillation = YUP; /* flag to tracking
11599                                                algorithm oscillation */
11600       SUMA_Boolean  TryBruteForce = NOPE;
11601       int *Visited = NULL;
11602 
11603       if (TrackOscillation) {
11604          Visited = (int *)SUMA_calloc(SO->N_Node, sizeof(int));
11605          if (!Visited) {
11606             SUMA_SLP_Err("Failed to allocate for Visited.\n");
11607             SUMA_RETURN(NOPE);
11608          }
11609       }
11610 
11611       Eli = Elmt; /* initialize current element to the
11612                      very fist in the brushstroke */
11613       MTI = NULL;
11614       TryBruteForce = NOPE;
11615       do {
11616          bsdi = (SUMA_BRUSH_STROKE_DATUM *)Eli->data;
11617          n1 = bsdi->SurfNode;
11618 
11619          Eln = Eli->next; /* get the next element in line */
11620          bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
11621 
11622          if (LocalHead)
11623             fprintf(SUMA_STDERR,"%s: Working from node %d.\n", FuncName, n1);
11624 
11625          if (!TryBruteForce) { /* try the fast method */
11626             N_Neighb = SO->FN->N_Neighb[n1];
11627             if (N_Neighb < 3) {
11628                /* nothing found */
11629                SUMA_SLP_Err ("Node has less than 3 neighbors.\n"
11630                              "This method will not apply.");
11631                SUMA_RETURN(NOPE);
11632             }
11633 
11634             /* does the ray formed by Eln's NP and FP hit any of
11635                the triangles incident to bsdi->SurfNode (or n1) ? */
11636             if (LocalHead)
11637                fprintf (SUMA_STDERR,
11638                         "%s: Searching incident triangles:\n", FuncName);
11639             i=0;
11640             DoesInters = NOPE;
11641             while ((i < N_Neighb ) && (!DoesInters)) {
11642                n2 = SO->FN->FirstNeighb[n1][i];
11643                if ( i+1 == N_Neighb) n3 = SO->FN->FirstNeighb[n1][0];
11644                else n3 = SO->FN->FirstNeighb[n1][i+1];
11645                #if 0
11646                   if (LocalHead) {
11647                      fprintf (SUMA_STDERR, " %d: [%d %d %d] Tri %d\n",
11648                         i, n1, n2, n3, SUMA_whichTri(SO->EL, n1, n2, n3, 1));
11649                      fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
11650                         n1, SO->NodeList[3*n1],
11651                             SO->NodeList[3*n1+1], SO->NodeList[3*n1+2]);
11652                      fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
11653                         n2, SO->NodeList[3*n2],
11654                             SO->NodeList[3*n2+1], SO->NodeList[3*n2+2]);
11655                      fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
11656                         n3, SO->NodeList[3*n3],
11657                             SO->NodeList[3*n3+1], SO->NodeList[3*n3+2]);
11658                      fprintf (SUMA_STDERR,
11659                         " NP: [%.2f, %.2f, %.2f] FP: [%.3f, %.2f, %.2f]\n",
11660                               bsdn->NP[0], bsdn->NP[1], bsdn->NP[2],
11661                               bsdn->FP[0], bsdn->FP[1], bsdn->FP[2]);
11662                   }
11663                #endif
11664                DoesInters = SUMA_MT_isIntersect_Triangle (bsdn->NP, bsdn->FP,
11665                                  &(SO->NodeList[3*n1]),
11666                                  &(SO->NodeList[3*n2]),
11667                                  &(SO->NodeList[3*n3]), ip, d, &ni);
11668                if (DoesInters) {
11669                   if (ni == 0) ni = n1;
11670                   else if (ni == 1) ni = n2;
11671                   else ni = n3;
11672 
11673                   ti = SUMA_whichTri(SO->EL, n1, n2, n3, 1, 0);
11674                }
11675 
11676                #if 0
11677                   if (LocalHead)
11678                      fprintf (SUMA_STDERR,
11679                               "%s: DoesInters = %d, ni = %d\n",
11680                               FuncName, DoesInters, ni);
11681                   {
11682                      /* for debuging */
11683                      MTI = NULL;MTI =
11684                         SUMA_MT_intersect_triangle(   bsdn->NP, bsdn->FP,
11685                                                       SO->NodeList, SO->N_Node,
11686                                                       SO->FaceSetList,
11687                                                       SO->N_FaceSet,
11688                                                       MTI, 0);
11689                      fprintf (SUMA_STDERR,
11690                         "%s: Intersection would be with triangle %d, node %d\n",
11691                               FuncName, MTI->ifacemin, MTI->inodemin);
11692                   }
11693                #endif
11694                ++i;
11695             }
11696             if (LocalHead) fprintf (SUMA_STDERR, "\n");
11697 
11698          } else  { /* try brute force flag has been set*/
11699 
11700             if (LocalHead) fprintf (SUMA_STDERR, "%s: Trying brute force here \n", FuncName);
11701             /* Now skip and remove decimated elements */
11702             SUMA_REMOVE_NEXT_NON_DECIMATED (sv->BS, Eli, Eln);
11703             DeciLevel = 0;
11704             DeciReentry = 0;
11705             if (!Eln) {
11706              SUMA_SL_Err ("I tried hard to figure out your trace.\nI failed, now you try again.");
11707              SUMA_RETURN(YUP);
11708             }
11709 
11710             bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
11711             MTI = SUMA_MT_intersect_triangle(   bsdn->NP, bsdn->FP,
11712                                     SO->NodeList, SO->N_Node,
11713                                     SO->FaceSetList, SO->N_FaceSet,
11714                                     MTI, 0);
11715 
11716             if (!MTI) {
11717                SUMA_SL_Err ("I tried harder to figure out your trace.\nI failed, do try again.");
11718                SUMA_RETURN (YUP);
11719             }
11720 
11721             if (MTI->N_hits) { /* There is a hit, store it if useful */
11722                DoesInters = YUP;
11723                if (bsdi->SurfNode != MTI->inodemin) { /* a new one, bring it on */
11724                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at new node %d.\n", FuncName, MTI->inodemin);
11725                   ni = MTI->inodemin;
11726                   ti = MTI->ifacemin;
11727                }else {
11728                   /* set ni to n1 and let the element be destroyed */
11729                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at n1 = %d!.\n", FuncName, MTI->inodemin);
11730                   ni = n1;
11731                }
11732             } else {
11733                /* No hits at all, get out of this business */
11734                SUMA_SL_Err ("Why are you drawing out of bounds ?");
11735                SUMA_RETURN (YUP);
11736             }
11737             /* reset the TryBruteForce flag */
11738             TryBruteForce = NOPE;
11739          }
11740 
11741          if (!DoesInters) { /* no intersection found, insert an element between Eli and Eln and try again */
11742             ++DeciLevel;
11743             if (LocalHead) fprintf (SUMA_STDERR, "%s: No intersection found. Decimating, level %d.\n", FuncName, DeciLevel);
11744 
11745             if (DeciLevel > 3000) { /* this condition is only here to keep things from going awry. */
11746                if (LocalHead) fprintf (SUMA_STDERR,"%s: Decimation method failed. Trying from brute force", FuncName);
11747                TryBruteForce = YUP;
11748             } else {
11749                bsd_deci = SUMA_CreateBSDatum();
11750                bsd_deci->Decimated = YUP;
11751                bsd_deci->x = (bsdi->x + bsdn->x)/2.0;
11752                bsd_deci->y = (bsdi->y + bsdn->y)/2.0;
11753                for (j=0; j < 3; ++j) bsd_deci->NP[j] = (bsdi->NP[j] + bsdn->NP[j])/2.0;
11754                for (j=0; j < 3; ++j) bsd_deci->FP[j] = (bsdi->FP[j] + bsdn->FP[j])/2.0;
11755                bsd_deci->SurfNode = -1;
11756                bsd_deci->SurfTri = -1;
11757 
11758                dlist_ins_next (sv->BS, Eli, bsd_deci);
11759             }
11760          } else {
11761             /* intersection found */
11762             if (ni == n1 && !DeciLevel) {
11763                /* same node reached, not during decimation, perhaps path was too densely sampled, delete Eln */
11764                ++Removed;
11765                if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached without decimation, deleting for the %dth time.\n",
11766                    FuncName, Removed);
11767                dlist_remove(sv->BS, Eln, (void*)&bsdn);
11768                SUMA_FreeBSDatum(bsdn);
11769             } else {
11770                if (ni == n1 && DeciLevel) {
11771                   /* back to the starting point during decimation  */
11772                   if (DeciLevel) { /* user went out of bounds or drawing over cuts in surface */
11773                      #if 0
11774                         /* same node reached during decimation, to hell with it, use brute force intersection: YOU PAY PRICE IN TIME MISTER*/
11775                         TryBruteForce = YUP;
11776                         /* cancel the find */
11777                         DoesInters = NOPE;
11778                      #else
11779                         /* same node reached during decimation, try othernode in triangle */
11780                         if (!DeciReentry) {
11781                            UsedNode[0] = n1;
11782                            if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached during decimation.\n Switching to second closest node.\n", FuncName);
11783                            if (d[1] < d[2]) {
11784                               ni = n2;
11785                               UsedNode[1] = n2;
11786                            } else {
11787                               ni = n3;
11788                               UsedNode[1] = n3;
11789                            }
11790                         } else if (DeciReentry == 1){
11791                            /* been there before, one last node is left */
11792                            if (LocalHead) fprintf (SUMA_STDERR, "%s: Last chance!\n", FuncName);
11793                            if (n2 != UsedNode[0] && n2 != UsedNode[1]) ni = n2;
11794                            else if (n3 != UsedNode[0] && n3 != UsedNode[1]) ni = n3;
11795                         } else {
11796                            /* Decimation failed, Do intersection with entire surface */
11797                            TryBruteForce = YUP;
11798                            /* cancel the find */
11799                            DoesInters = NOPE;
11800                         }
11801                      #endif
11802                      ++DeciReentry;
11803                   }
11804                }else {
11805                   /* ni != n1  Reset DeciLevel */
11806                   DeciLevel = 0;
11807                   DeciReentry = 0;
11808                }
11809 
11810                /* algorithm might fall into oscillatory patterns, keep track of nodes visited.
11811                   It is possible that a node is visited multiple times when users go over the
11812                   same region over and over and over.*/
11813                if (TrackOscillation) {
11814                   ++Visited[ni];
11815                   if (Visited[ni] == 9) {
11816                      DoesInters = NOPE;
11817                      TryBruteForce = YUP;
11818                      SUMA_SL_Err ("Path tracing oscillation. Trying with brute force.");
11819                   }
11820                   if (Visited[ni] > 9) {
11821                      SUMA_SL_Err ("Path tracing oscillation remaining. Quitting tracing.");
11822                      SUMA_RETURN(YUP);
11823                   }
11824                }
11825 
11826                if (DoesInters) { /* it is possible that the find is cancelled */
11827                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Found new node.\n", FuncName);
11828                   /* good, new node is useful*/
11829                   bsdn->SurfNode = ni;
11830                   bsdn->SurfTri = ti;
11831                   /* set Eli to Eln */
11832                   Eli = Eln;
11833                }
11834             }
11835          }
11836          /* repeat until you have no more element */
11837       } while (Eli != dlist_tail(sv->BS));
11838 
11839       if (MTI) MTI = SUMA_Free_MT_intersect_triangle(MTI);
11840       if (TrackOscillation) {
11841          if (Visited) SUMA_free(Visited);
11842       }
11843    }/* new, faster method */
11844    #endif
11845    SUMA_RETURN(YUP);
11846 }
11847 
11848 
11849 /*!
11850    \brief Function to link a node on the surface to a certain node in NodeStroke
11851 
11852    \param sv (SUMA_SurfaceViewer *) with a valid BrushStroke in it
11853    \param NonSurf (int) index of node on surface to connect to NinStroke
11854    \param ELinStroke (DListElmt *) sv->BS element containing in SurfNode the index of the node  to connect NonSurf to
11855    \sa SUMA_LinkTailNodeToNodeStroke
11856 */
SUMA_LinkThisNodeToNodeInStroke(SUMA_SurfaceViewer * sv,int NonSurf,DListElmt * ELinStroke)11857 SUMA_ROI_DATUM *SUMA_LinkThisNodeToNodeInStroke (SUMA_SurfaceViewer *sv,
11858                                           int NonSurf, DListElmt *ELinStroke)
11859 {
11860    static char FuncName[]={"SUMA_LinkThisNodeToNodeInStroke"};
11861    SUMA_Boolean LocalHead = NOPE;
11862    SUMA_ROI_DATUM *ROId=NULL;
11863    SUMA_SurfaceObject *SO=NULL;
11864    int Nfrom, Nto;
11865    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11866 
11867    SUMA_ENTRY;
11868 
11869    // fprintf(stderr, "%s\n", FuncName);
11870 
11871    if (!(SO = SUMA_SV_Focus_SO(sv))) {
11872       SUMA_S_Err("No SO in focus");
11873       SUMA_RETURN(NULL);
11874    }
11875 
11876    Nfrom = NonSurf;
11877    bsd = (SUMA_BRUSH_STROKE_DATUM *)ELinStroke->data;
11878    Nto = bsd->SurfNode;
11879 
11880    /* Now compute the intersection of the surface with the plane */
11881    ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
11882 
11883    if (!ROId) {
11884       SUMA_S_Err("Failed to link tail node to first node in new stroke.\n"
11885                  "Repeat new stroke.");
11886       SUMA_RETURN(NULL);
11887    }
11888 
11889    SUMA_RETURN(ROId);
11890 }
11891 
11892 /*!
11893    \brief Function to link a node on the surface to the first node
11894    of a NodeStroke
11895 
11896    -This function returns an ROI_datum that represents the link between
11897    the last node visited and the first node of the Nodestroke
11898 
11899    \sa SUMA_LinkThisNodeToNodeInStroke
11900 */
SUMA_LinkTailNodeToNodeStroke(SUMA_SurfaceViewer * sv,SUMA_DRAWN_ROI * DrawnROI)11901 SUMA_ROI_DATUM *SUMA_LinkTailNodeToNodeStroke ( SUMA_SurfaceViewer *sv,
11902                                                 SUMA_DRAWN_ROI *DrawnROI)
11903 {
11904 
11905    static char FuncName[]={"SUMA_LinkTailNodeToNodeStroke"};
11906    SUMA_ROI_DATUM *ROId=NULL;
11907    SUMA_SurfaceObject *SO=NULL;
11908    SUMA_Boolean LocalHead = NOPE;
11909    int Nfrom=-1, Nto=-1, Trito=-1;
11910    DListElmt *Elm=NULL;
11911    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11912 
11913    SUMA_ENTRY;
11914 
11915    // fprintf(stderr, "%s\n", FuncName);
11916 
11917    if (!(SO = SUMA_SV_Focus_SO(sv))) {
11918       SUMA_S_Err("No SO in focus");
11919       SUMA_RETURN(NULL);
11920    }
11921 
11922    /* get the equation of the plane fromed by TailNode,
11923       FirstNodeinBrushStroke and its NearPlanePoint */
11924    SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI, Nfrom);
11925    if (Nfrom < 0) {
11926       fprintf (SUMA_STDERR, "Error %s: No tail node found.\n", FuncName);
11927       SUMA_RETURN(NULL);
11928    }
11929 
11930    /* get the first node in the stroke */
11931    SUMA_BS_FIRST_SURF_NODE(sv->BS, Nto, Trito, Elm);
11932    if (Nto < 0 || !Elm) {
11933       SUMA_SLP_Err ("Failed in SUMA_BS_FIRST_SURF_NODE macro.");
11934       SUMA_RETURN(NULL);
11935    }
11936    bsd = (SUMA_BRUSH_STROKE_DATUM *)Elm->data;
11937 
11938    /* Now compute the intersection of the surface with the plane */
11939    ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
11940 
11941    if (!ROId) {
11942       SUMA_S_Err("Failed to link tail node to first node in new stroke.\n"
11943                  "Repeat new stroke.");
11944       SUMA_RETURN(NULL);
11945    }
11946 
11947    SUMA_RETURN(ROId);
11948 }
11949 
11950 
11951 /*!
11952    This function turns the NodeStroke into a datum of connected nodes
11953 */
SUMA_NodeStrokeToConnectedNodes(SUMA_SurfaceViewer * sv)11954 SUMA_ROI_DATUM *SUMA_NodeStrokeToConnectedNodes (SUMA_SurfaceViewer *sv)
11955 {
11956    static char FuncName[]={"SUMA_NodeStrokeToConnectedNodes"};
11957    SUMA_Boolean LocalHead = NOPE;
11958    SUMA_ROI_DATUM *ROId=NULL, *ROIlink = NULL;
11959    int i=0;
11960    SUMA_SurfaceObject *SO=NULL;
11961    DListElmt *Elmt = NULL, *oElmt = NULL;
11962    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11963 
11964    SUMA_ENTRY;
11965 
11966    // fprintf(stderr, "%s\n", FuncName);
11967 
11968    if (!(SO = SUMA_SV_Focus_SO(sv))) {
11969       SUMA_S_Err("No SO in focus");
11970       SUMA_RETURN(NULL);
11971    }
11972 
11973    ROId = SUMA_AllocROIDatum();
11974 
11975    /* fill up node series here */
11976    ROId->N_n = 1;
11977    ROId->N_t = 1;
11978    ROId->nPath = (int *) SUMA_calloc (ROId->N_n, sizeof(int));
11979    ROId->tPath = (int *) SUMA_calloc (ROId->N_t, sizeof(int));
11980 
11981    SUMA_BS_FIRST_SURF_NODE(sv->BS, ROId->nPath[0], ROId->tPath[0], Elmt);
11982    ROId->Type = SUMA_ROI_NodeSegment;
11983 
11984    /* try filling up the rest */
11985    oElmt = Elmt;
11986    do {
11987       /* get the next element with a surfnode */
11988      SUMA_BS_NEXT_SURF_NODE(sv->BS, oElmt, Elmt);
11989 
11990      if (!Elmt) {
11991       /* perhaps reached end of list without success */
11992       SUMA_S_Note("Reached EOL without finding Elmt.\n"
11993                   "Not necessarily a bad thing.");
11994       SUMA_RETURN(ROId);
11995      } else {
11996       if (LocalHead) {
11997          fprintf (SUMA_STDERR, "%s: Working with element %p.\n", FuncName, Elmt);
11998       }
11999      }
12000      bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
12001      SUMA_LHv("%d %d\nWill look for edge %d %d\n",
12002                ROId->N_n, bsd->SurfNode,
12003                ROId->nPath[ROId->N_n-1], bsd->SurfNode);
12004      if (SUMA_FindEdge(SO->EL, ROId->nPath[ROId->N_n-1], bsd->SurfNode) < 0) {
12005          /* Not found, link nodes together*/
12006          SUMA_LH("Edge not found, linking together.");
12007          if (!(ROIlink = SUMA_LinkThisNodeToNodeInStroke (sv,
12008                                  ROId->nPath[ROId->N_n-1],  Elmt))) {
12009             SUMA_SLP_Err ("Failed to connect nodes in stroke.");
12010             SUMA_RETURN (ROId);
12011          }
12012          /* merge ROIlink with ROId */
12013          SUMA_LH("Merging ROIs together.");
12014          if (!SUMA_AppendToROIdatum (ROIlink, ROId)) {
12015                SUMA_RegisterMessage (SUMAg_CF->MessageList,
12016                                   "Failed to merge ROIs.", FuncName,
12017                                   SMT_Critical, SMA_LogAndPopup);
12018                if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
12019                SUMA_RETURN(ROId);
12020          }
12021          if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
12022       }else {
12023          SUMA_LH("Nodes connected.");
12024          /* nodes are connected, just add to path */
12025          ++ROId->N_n;
12026          ROId->nPath = (int *) SUMA_realloc (ROId->nPath, sizeof(int)*ROId->N_n);
12027          ROId->nPath[ROId->N_n-1] = bsd->SurfNode;
12028       }
12029 
12030       oElmt = Elmt;
12031    } while (Elmt != dlist_tail(sv->BS));
12032 
12033    SUMA_RETURN (ROId);
12034 }
12035 
12036 
12037 /*!
12038 Executes an action
12039 Adds it to the action stack
12040 Update the action stack pointer
12041 DO not do StckPos = SUMA_PushActionStack (..., StackPos, ....);
12042 that is because the function might return NULL if something failed and you'd lose the current stack position for good.
12043 */
SUMA_PushActionStack(DList * ActionStack,DListElmt * StackPos,SUMA_ACTION_RESULT (* ActionFunction)(void * ActionData,SUMA_ACTION_POLARITY Pol),void * ActionData,void (* ActionDataDestructor)(void * Actiondata))12044 DListElmt * SUMA_PushActionStack (DList *ActionStack, DListElmt *StackPos,
12045                                   SUMA_ACTION_RESULT (*ActionFunction)(void *ActionData, SUMA_ACTION_POLARITY Pol),
12046                                   void *ActionData,
12047                                   void (*ActionDataDestructor)(void *Actiondata))
12048 {
12049    static char FuncName[]={"SUMA_PushActionStack"};
12050    SUMA_Boolean LocalHead = NOPE;
12051    SUMA_ACTION_STACK_DATA *AS_data=NULL;
12052    SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
12053 
12054    SUMA_ENTRY;
12055 
12056    // fprintf(stderr, "%s\n", FuncName);
12057 
12058    /* execute action */
12059    if (LocalHead) fprintf (SUMA_STDERR, "%s: Executing Action.\n", FuncName);
12060    ActionResult = ActionFunction (ActionData, SAP_Do);
12061    switch (ActionResult) {
12062       case SAR_Fail:
12063          SUMA_SLP_Err("Action failed.");
12064          SUMA_RETURN(NULL);
12065          break;
12066       case SAR_Succeed:
12067          break;
12068       default:
12069          SUMA_SLP_Err("Action result not understood.");
12070          SUMA_RETURN(NULL);
12071          break;
12072    }
12073 
12074    /* remove all elements above the position in the stack */
12075    if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing Action Stack Elements above current position.\n", FuncName);
12076    while (StackPos != dlist_tail(ActionStack)) {
12077       void *asdata=NULL;
12078 
12079       dlist_remove(ActionStack, dlist_tail(ActionStack), &asdata);
12080 
12081       /* now free the asdata */
12082       SUMA_FreeActionStackData(asdata);
12083    }
12084 
12085    /* Pushing the action and its data onto the stack */
12086    if (LocalHead) fprintf (SUMA_STDERR, "%s: Pushing the action and its data onto the stack.\n", FuncName);
12087    AS_data = (SUMA_ACTION_STACK_DATA *)
12088                   SUMA_calloc(1,sizeof(SUMA_ACTION_STACK_DATA));
12089    AS_data->ActionDataDestructor = ActionDataDestructor;
12090    AS_data->ActionFunction = ActionFunction;
12091    AS_data->ActionData = ActionData;
12092    dlist_ins_next (ActionStack, dlist_tail(ActionStack), (void*)AS_data);
12093    if (LocalHead) fprintf (SUMA_STDERR, "%s: Updating StackPos ...\n", FuncName);
12094    StackPos = dlist_tail(ActionStack);
12095 
12096    SUMA_RETURN(StackPos);
12097 }
12098 
12099 /*!
12100    Redo an action of the ActionStack
12101    If StackPos is NULL, it is assumed that you are at the bottom of the stack
12102 */
SUMA_RedoAction(DList * ActionStack,DListElmt * StackPos)12103 DListElmt * SUMA_RedoAction (DList *ActionStack, DListElmt *StackPos)
12104 {
12105    static char FuncName[]={"SUMA_RedoAction"};
12106    SUMA_ACTION_STACK_DATA *AS_data=NULL;
12107    SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
12108    SUMA_Boolean LocalHead = NOPE;
12109 
12110    SUMA_ENTRY;
12111 
12112    // fprintf(stderr, "%s\n", FuncName);
12113 
12114    if (!StackPos) {
12115       if (LocalHead) fprintf (SUMA_STDERR, "%s: At bottom of stack. Working up.\n", FuncName);
12116       StackPos = dlist_head(ActionStack);
12117    } else if (StackPos == dlist_tail(ActionStack)) {
12118       SUMA_SLP_Err("At top of stack, nothing to do.");
12119       SUMA_RETURN(StackPos);
12120    } else {
12121       StackPos = dlist_next(StackPos);
12122    }
12123 
12124    /* execute action above StackPos again */
12125    AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
12126    ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Redo);
12127    switch (ActionResult) {
12128       case SAR_Fail:
12129          SUMA_SLP_Err("Action failed.");
12130          SUMA_RETURN(NULL);
12131          break;
12132       case SAR_Succeed:
12133          break;
12134       default:
12135          SUMA_SLP_Err("Action result not understood.");
12136          SUMA_RETURN(NULL);
12137          break;
12138    }
12139 
12140    SUMA_RETURN(StackPos);
12141 }
12142 /*!
12143    Undo an action on the ActionStack
12144 
12145    \returns StackNewPos = StackPos if reached the bottom of the stack.
12146                      It is your job to make sure this function is not called again.
12147                         = StackPos->prev if all went well
12148                         =NULL if trouble
12149 
12150 */
SUMA_UndoAction(DList * ActionStack,DListElmt * StackPos)12151 DListElmt * SUMA_UndoAction (DList *ActionStack, DListElmt *StackPos)
12152 {
12153    static char FuncName[]={"SUMA_UndoAction"};
12154    SUMA_ACTION_STACK_DATA *AS_data=NULL;
12155    SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
12156    SUMA_Boolean LocalHead = NOPE;
12157 
12158    SUMA_ENTRY;
12159 
12160    // fprintf(stderr, "%s\n", FuncName);
12161 
12162    if (!StackPos) {
12163       SUMA_SLP_Err("At bottom of stack.");
12164       SUMA_RETURN(StackPos);
12165    }
12166 
12167    AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
12168 
12169    /* execute reverse of action */
12170    ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Undo);
12171    switch (ActionResult) {
12172       case SAR_Fail:
12173          SUMA_SLP_Err("Action failed.");
12174          SUMA_RETURN(NULL);
12175          break;
12176       case SAR_Succeed:
12177          break;
12178       default:
12179          SUMA_SLP_Err("Action result not understood.");
12180          SUMA_RETURN(NULL);
12181          break;
12182    }
12183 
12184    /* now move StackPos down */
12185    if (StackPos == dlist_head(ActionStack)) {
12186       /* do nothing to StackPos */
12187    } else {
12188       StackPos = dlist_prev(StackPos);
12189    }
12190 
12191    SUMA_RETURN(StackPos);
12192 }
12193 
12194 /*!
12195    \brief Mark an ROI as finished
12196 */
SUMA_FinishedROI(void * data,SUMA_ACTION_POLARITY Pol)12197 SUMA_ACTION_RESULT SUMA_FinishedROI (void *data, SUMA_ACTION_POLARITY Pol)
12198 {
12199    static char FuncName[]={"SUMA_FinishedROI"};
12200    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12201    SUMA_SurfaceObject *SOparent=NULL;
12202    SUMA_Boolean LocalHead = NOPE;
12203 
12204    SUMA_ENTRY;
12205 
12206    // fprintf(stderr, "%s\n", FuncName);
12207 
12208    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12209 
12210    switch (Pol) {
12211       case SAP_Do:
12212       case SAP_Redo:
12213          if (LocalHead)
12214             fprintf (SUMA_STDERR, "%s: Marking as finished...\n", FuncName);
12215          /* set the drawing status */
12216          ROIA->DrawnROI->DrawStatus = SUMA_ROI_Finished;
12217 
12218          SOparent = SUMA_findSOp_inDOv(ROIA->DrawnROI->Parent_idcode_str,
12219                                        SUMAg_DOv, SUMAg_N_DOv);
12220          if (!SOparent) {
12221             SUMA_SLP_Warn( "Parent surface\n"
12222                            "not found for ROI\n"
12223                            "No contour will\n"
12224                            "be determined." );
12225             SUMA_RETURN(SAR_Succeed);
12226          }else {
12227             /* calculate the contours */
12228             if (!ROIA->DrawnROI->CE) { /* must create contour */
12229                int *Nodes, N_Nodes;
12230                SUMA_Boolean Unique = NOPE;
12231 
12232                SUMA_LH("Getting Contour ");
12233                N_Nodes = 0;
12234                Unique = YUP; /* Set to YUP if you have node
12235                                  indices listed more than once. */
12236                Nodes = SUMA_NodesInROI (ROIA->DrawnROI, &N_Nodes, Unique);
12237                if (Nodes) {
12238                   ROIA->DrawnROI->CE = SUMA_GetContour (
12239                                  SOparent,
12240                                  Nodes, N_Nodes, &(ROIA->DrawnROI->N_CE),
12241                                  0, NULL, NULL, 1);
12242                   if (!ROIA->DrawnROI->CE) { SUMA_LH("Null DrawnROI->CE"); }
12243                   else { SUMA_LH("Good DrawnROI->CE"); }
12244                   SUMA_free(Nodes);
12245                }
12246             }else {
12247                SUMA_SLP_Err("Unexpected Contour");
12248                SUMA_RETURN(SAR_Fail);
12249             }
12250          }
12251 
12252          break;
12253       case SAP_Undo:
12254          if (LocalHead)
12255             fprintf (SUMA_STDERR, "%s: Marking as InCreation...\n", FuncName);
12256          ROIA->DrawnROI->DrawStatus = SUMA_ROI_InCreation;
12257          /* remove any contour if present */
12258          if (ROIA->DrawnROI->CE) SUMA_free(ROIA->DrawnROI->CE);
12259          ROIA->DrawnROI->CE = NULL;
12260          ROIA->DrawnROI->N_CE = -1;
12261          break;
12262       default:
12263          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12264          break;
12265    }
12266 
12267    SUMA_RETURN(SAR_Succeed);
12268 }
12269 
12270 /*!
12271    \brief This function is like SUMA_AddToTailROIDatum, except that it also updates the type of the ROI
12272    to be a filled one. You call this function when you are adding an ROIDatum that fills a closed  path
12273    \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12274    \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
12275 */
12276 
SUMA_AddFillROIDatum(void * data,SUMA_ACTION_POLARITY Pol)12277 SUMA_ACTION_RESULT SUMA_AddFillROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
12278 {
12279    static char FuncName[]={"SUMA_AddFillROIDatum"};
12280    SUMA_Boolean LocalHead = NOPE;
12281    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12282    void *eldata=NULL;
12283    DListElmt *tail_elm=NULL;
12284    SUMA_ROI_DATUM *ROId=NULL;
12285 
12286    SUMA_ENTRY;
12287 
12288    // fprintf(stderr, "%s\n", FuncName);
12289 
12290    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12291 
12292    switch (Pol) {
12293       case SAP_Do:
12294       case SAP_Redo:
12295          if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
12296          dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
12297          ROIA->DrawnROI->Type = SUMA_ROI_FilledArea;
12298          break;
12299       case SAP_Undo:
12300          if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
12301          dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
12302          /* eldata contains the ROIdatum that has been removed from the list. It should not be freed here
12303          This structure is to remain in the stack for later usage.*/
12304          /* if the tail is a segment, then turn the ROI type to a closedpath */
12305          tail_elm = dlist_tail(ROIA->DrawnROI->ROIstrokelist);
12306          ROId = (SUMA_ROI_DATUM *)tail_elm->data;
12307          if (ROId->Type == SUMA_ROI_NodeSegment) { /* we are no longer dealing with filled ROI */
12308             ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
12309          }
12310          break;
12311       default:
12312          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12313          break;
12314    }
12315 
12316    SUMA_RETURN(SAR_Succeed);
12317 }
12318 
12319 /*!
12320    \brief This function is like SUMA_AddToTailROIDatum, except that it also updates the type of the ROI
12321    to be a closed one. You call this function when you are addind the last ROIDatum that closes the path
12322    \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12323    \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
12324 */
SUMA_AddToTailJunctionROIDatum(void * data,SUMA_ACTION_POLARITY Pol)12325 SUMA_ACTION_RESULT SUMA_AddToTailJunctionROIDatum (void *data,
12326                                                    SUMA_ACTION_POLARITY Pol)
12327 {
12328    static char FuncName[]={"SUMA_AddToTailJunctionROIDatum"};
12329    SUMA_Boolean LocalHead = NOPE;
12330    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12331    void *eldata=NULL;
12332 
12333    SUMA_ENTRY;
12334 
12335    // fprintf(stderr, "%s\n", FuncName);
12336 
12337    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12338 
12339    switch (Pol) {
12340       case SAP_Do:
12341       case SAP_Redo:
12342          if (ROIA->DrawnROI->Type == SUMA_ROI_ClosedPath) {
12343             SUMA_SLP_Err ("Trying to close a closed path!");
12344             SUMA_RETURN(SAR_Fail);
12345          }
12346          if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
12347          dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
12348          ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
12349          break;
12350       case SAP_Undo:
12351          if (ROIA->DrawnROI->Type == SUMA_ROI_OpenPath) {
12352             SUMA_SLP_Err ("Trying to open an open path!");
12353             SUMA_RETURN(SAR_Fail);
12354          }
12355          if (LocalHead)
12356             fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n",
12357                                              FuncName);
12358          dlist_remove(ROIA->DrawnROI->ROIstrokelist,
12359                       dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
12360          /* eldata contains the ROIdatum that has been removed from the list.
12361             It should not be freed here
12362             This structure is to remain in the stack for later usage.*/
12363          ROIA->DrawnROI->Type = SUMA_ROI_OpenPath;
12364          break;
12365       default:
12366          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12367          break;
12368    }
12369 
12370    SUMA_RETURN(SAR_Succeed);
12371 }
12372 
12373 
12374 /*!
12375    \brief Adds (or removes) an ROIdatum to the tail of the ROI list
12376 
12377    \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12378    \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
12379 */
SUMA_AddToTailROIDatum(void * data,SUMA_ACTION_POLARITY Pol)12380 SUMA_ACTION_RESULT SUMA_AddToTailROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
12381 {
12382    static char FuncName[]={"SUMA_AddToTailROIDatum"};
12383    SUMA_Boolean LocalHead = NOPE;
12384    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12385    void *eldata=NULL;
12386 
12387    SUMA_ENTRY;
12388 
12389    // fprintf(stderr, "%s\n", FuncName);
12390 
12391    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12392 
12393    switch (Pol) {
12394       case SAP_Do:
12395       case SAP_Redo:
12396          if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
12397          dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
12398          break;
12399       case SAP_Undo:
12400          if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
12401          dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
12402          /* eldata contains the ROIdatum that has been removed from the list. It should not be freed here
12403          This structure is to remain in the stack for later usage.*/
12404          break;
12405       default:
12406          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12407          break;
12408    }
12409 
12410    SUMA_RETURN(SAR_Succeed);
12411 }
12412 
12413 /*!
12414    A function to destroy the ROI action data structure.
12415 
12416    \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12417 
12418    -  Only  ROIA->ROId and ROIA are freed. ROIA->DrawnROI should be freed when the DrawnROI list is destroyed.
12419 */
12420 
SUMA_DestroyROIActionData(void * data)12421 void SUMA_DestroyROIActionData (void *data)
12422 {
12423    static char FuncName[]={"SUMA_DestroyROIActionData"};
12424    SUMA_Boolean LocalHead = NOPE;
12425    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12426 
12427    SUMA_ENTRY;
12428 
12429    // fprintf(stderr, "%s\n", FuncName);
12430 
12431    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12432 
12433    if (!ROIA) SUMA_RETURNe;
12434 
12435    if (ROIA->ROId) { /* free the ROI datum */
12436       SUMA_FreeROIDatum ((void *)ROIA->ROId);
12437       ROIA->ROId = NULL;
12438    }
12439 
12440    ROIA->DrawnROI = NULL; /* this should not be freed here, it is freed when the function for destroying DrawnROI is called */
12441    SUMA_free(ROIA);
12442 
12443    SUMA_RETURNe;
12444 }
12445 
12446 /*!
12447    \brief set the position of light0
12448    \param s (char *) a strng containing X, Y, Z coordinates
12449    \param data (void *) a typecast of the pointer to the surface viewer to be affected
12450 
12451 */
SUMA_SetLight0(char * s,void * data)12452 void SUMA_SetLight0 (char *s, void *data)
12453 {
12454    static char FuncName[]={"SUMA_SetLight0"};
12455    DList *list=NULL;
12456    SUMA_EngineData *ED = NULL;
12457    SUMA_SurfaceViewer *sv = NULL;
12458    float fv3[3];
12459    SUMA_Boolean LocalHead = NOPE;
12460 
12461    SUMA_ENTRY;
12462 
12463    // fprintf(stderr, "%s\n", FuncName);
12464 
12465    if (!s) SUMA_RETURNe;
12466 
12467    sv = (SUMA_SurfaceViewer *)data;
12468 
12469    /* parse s */
12470    if (SUMA_StringToNum (s, (void*)fv3, 3, 1) != 3) {/*problem,beep and ignore */
12471       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12472       SUMA_RETURNe;
12473    }
12474 
12475    /* register fv3 with ED */
12476    if (!list) list = SUMA_CreateList();
12477    ED = SUMA_InitializeEngineListData (SE_SetLight0Pos);
12478    if (!SUMA_RegisterEngineListCommand (  list, ED,
12479                                           SEF_fv3, (void *)fv3,
12480                                           SES_Suma, (void *)sv, NOPE,
12481                                           SEI_Tail, NULL )) {
12482       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12483       SUMA_RETURNe;
12484    }
12485 
12486    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
12487 
12488    if (!SUMA_Engine (&list)) {
12489       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12490    }
12491 
12492    SUMA_RETURNe;
12493 }
12494 
12495 /*!
12496    \brief sets the number of smoothing operations to perform on foreground colors
12497    before display
12498 */
SUMA_SetNumForeSmoothing(char * s,void * data)12499 void SUMA_SetNumForeSmoothing (char *s, void *data)
12500 {
12501    static char FuncName[]={"SUMA_SetNumForeSmoothing"};
12502    DList *list=NULL;
12503    SUMA_EngineData *ED = NULL;
12504    SUMA_SurfaceViewer *sv = NULL;
12505    float fv3[3];
12506    SUMA_Boolean LocalHead = NOPE;
12507 
12508    SUMA_ENTRY;
12509 
12510    // fprintf(stderr, "%s\n", FuncName);
12511 
12512    if (!s) SUMA_RETURNe;
12513 
12514    sv = (SUMA_SurfaceViewer *)data;
12515 
12516    /* parse s */
12517    if (SUMA_StringToNum (s, (void *)fv3, 1,1) != 1) {/*problem,beep and ignore */
12518       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12519       SUMA_RETURNe;
12520    }
12521 
12522    /* set sv */
12523 
12524    if ((int)fv3[0] < 0) {
12525       SUMA_SLP_Err("Only positive integer\nvalues are valid.\n");
12526       SUMA_RETURNe;
12527    }
12528    SUMAg_CF->X->NumForeSmoothing = (int)fv3[0];
12529 
12530    /* flag surfaces for remix */
12531    SUMA_SetAllRemixFlag(SUMAg_SVv, SUMAg_N_SVv);
12532 
12533    /* register a redisplay for sv*/
12534    if (!list) list = SUMA_CreateList();
12535    SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
12536                                        SES_Suma, sv);
12537    if (!SUMA_Engine (&list)) {
12538       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12539    }
12540 
12541    SUMA_RETURNe;
12542 
12543 }
12544 
SUMA_SetNumFinalSmoothing(char * s,void * data)12545 void SUMA_SetNumFinalSmoothing (char *s, void *data)
12546 {
12547    static char FuncName[]={"SUMA_SetNumFinalSmoothing"};
12548    DList *list=NULL;
12549    SUMA_EngineData *ED = NULL;
12550    SUMA_SurfaceViewer *sv = NULL;
12551    float fv3[3];
12552    SUMA_Boolean LocalHead = NOPE;
12553 
12554    SUMA_ENTRY;
12555 
12556    // fprintf(stderr, "%s\n", FuncName);
12557 
12558    if (!s) SUMA_RETURNe;
12559 
12560    sv = (SUMA_SurfaceViewer *)data;
12561 
12562    /* parse s */
12563    if (SUMA_StringToNum (s, (void *)fv3, 1,1) != 1) {/*problem,beep and ignore */
12564       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12565       SUMA_RETURNe;
12566    }
12567 
12568    /* set sv */
12569 
12570    if ((int)fv3[0] < 0) {
12571       SUMA_SLP_Err("Only positive integer\nvalues are valid.\n");
12572       SUMA_RETURNe;
12573    }
12574    SUMAg_CF->X->NumFinalSmoothing = (int)fv3[0];
12575 
12576    /* flag surfaces for remix */
12577    SUMA_SetAllRemixFlag(SUMAg_SVv, SUMAg_N_SVv);
12578 
12579    /* register a redisplay for sv*/
12580    if (!list) list = SUMA_CreateList();
12581    SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
12582                                        SES_Suma, sv);
12583    if (!SUMA_Engine (&list)) {
12584       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12585    }
12586 
12587    SUMA_RETURNe;
12588 
12589 }
12590 
12591 /*!
12592    \brief Sets the screen clipping plane
12593 
12594    \param s (char *) a strng containing a,b,c,d parameters of plane equation
12595    \param data (void *) a typecast of the pointer to the surface viewer to be affected
12596 
12597 */
SUMA_SetScreenClip(char * s,void * data)12598 void SUMA_SetScreenClip (char *s, void *data)
12599 {
12600    SUMA_SetClip(s,(SUMA_SurfaceViewer *)data, SUMA_SCREEN_CLIP);
12601 }
SUMA_SetObjectClip(char * s,void * data)12602 void SUMA_SetObjectClip (char *s, void *data)
12603 {
12604    SUMA_SetClip(s,(SUMA_SurfaceViewer *)data, SUMA_ALL_OBJECT_CLIP);
12605 }
12606 
SUMA_SetClip(char * s,SUMA_SurfaceViewer * sv,SUMA_CLIP_PLANE_TYPES tp)12607 void SUMA_SetClip (char *s, SUMA_SurfaceViewer *sv, SUMA_CLIP_PLANE_TYPES tp)
12608 {
12609    static char FuncName[]={"SUMA_SetScreenClip"};
12610    DList *list=NULL;
12611    SUMA_EngineData *ED = NULL;
12612    float fv15[15];
12613    int npar=0;
12614    char *sn;
12615    char namebuf[24];
12616    int itmp, ii, it=0;
12617    DListElmt *NextElm= NULL;
12618    SUMA_Boolean LocalHead = NOPE;
12619 
12620    SUMA_ENTRY;
12621 
12622    // fprintf(stderr, "%s\n", FuncName);
12623 
12624    if (!s) {
12625       SUMA_Show_Clip_Planes(SUMAg_CF, NULL);
12626       SUMA_RETURNe;
12627    }
12628 
12629    /* Get the name, if any */
12630    if ((sn = strstr(s,":"))) {/* found name */
12631       if (sn - s > 7) {
12632          SUMA_SLP_Err("Plane label too long!");
12633          SUMA_RETURNe;
12634       }
12635       ii=0;
12636       while (s[ii] != ':') { namebuf[ii] = s[ii]; ++ii; }/* copy name */
12637       namebuf[ii] = '\0';
12638       itmp = 0; ++ii;
12639       while (s[ii] != '\0') { s[itmp] = s[ii]; ++ii; ++itmp; } /* copy rest */
12640       s[itmp] = '\0';
12641       /* get the equation */
12642       npar = SUMA_StringToNum (s, (void *)fv15, 4, 1);
12643       if (npar != 4 && npar != 2  && npar != 0) { /* problem, beep and ignore */
12644          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12645          SUMA_RETURNe;
12646       }
12647       if (npar == 2) { /* the z game */
12648          fv15[2] = fv15[0];
12649          fv15[3] = fv15[1];
12650          fv15[0] = 0.0;
12651          fv15[1] = 0.0;
12652       } else if (npar == 0) { /* the nothing */
12653          fv15[0] = 0.0;
12654          fv15[1] = 0.0;
12655          fv15[2] = 0.0;
12656          fv15[3] = 0.0;
12657       }
12658    }else {
12659       SUMA_SLP_Err("Must provide plane label!");
12660       SUMA_RETURNe;
12661    }
12662 
12663 
12664    /* register fv15 with ED */
12665    if (!list) list = SUMA_CreateList();
12666    ED = SUMA_InitializeEngineListData (SE_SetClip);
12667    if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
12668                                           SEF_fv15, (void *)fv15,
12669                                           SES_Suma, (void *)sv, NOPE,
12670                                           SEI_Head, NULL ))) {
12671       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12672       SUMA_RETURNe;
12673    }
12674    /* register type expected */
12675    it = (int)tp;
12676    if (!(SUMA_RegisterEngineListCommand (  list, ED,
12677                                           SEF_i, (void*)(&it),
12678                                           SES_Suma, (void *)sv, NOPE,
12679                                           SEI_In, NextElm ))) {
12680       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12681       SUMA_RETURNe;
12682    }
12683    /* register name of plane */
12684    if (!(SUMA_RegisterEngineListCommand (  list, ED,
12685                                           SEF_s, (void*)(namebuf),
12686                                           SES_Suma, (void *)sv, NOPE,
12687                                           SEI_In, NextElm ))) {
12688       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12689       SUMA_RETURNe;
12690    }
12691    if (!SUMA_Engine (&list)) {
12692       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12693    }
12694 
12695    SUMA_RETURNe;
12696 }
12697 
12698 /*!
12699    \brief Sets the rotation center
12700 
12701    \param s (char *) a strng containing X, Y, Z coordinates
12702    \param data (void *) a typecast of the pointer to the surface viewer to
12703                         be affected
12704 
12705    NOTE: This is a bit ugly because there is a jump in surface location with
12706    the change in center of rotation. Something also needs updating to keep this
12707    from happening ...
12708 */
12709 
SUMA_SetRotCenter(char * s,void * data)12710 void SUMA_SetRotCenter (char *s, void *data)
12711 {
12712    static char FuncName[]={"SUMA_SetRotCenter"};
12713    DList *list=NULL;
12714    SUMA_EngineData *ED = NULL;
12715    SUMA_SurfaceViewer *sv = NULL;
12716    float fv3[3];
12717    SUMA_Boolean LocalHead = NOPE;
12718 
12719    SUMA_ENTRY;
12720 
12721    // fprintf(stderr, "%s\n", FuncName);
12722 
12723    sv = (SUMA_SurfaceViewer *)data;
12724    if (!sv) {
12725       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12726       SUMA_RETURNe;
12727    }
12728 
12729    if (!s) {
12730       if (!SUMA_UpdateRotaCenter(sv, SUMAg_DOv, SUMAg_N_DOv)) {
12731          fprintf (SUMA_STDERR,
12732                   "Error %s: Failed to update center of rotation", FuncName);
12733          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12734          SUMA_RETURNe;
12735       }
12736       SUMA_RETURNe;
12737    }
12738 
12739    /* parse s */
12740    if (SUMA_StringToNum (s, (void*)fv3, 3,1) != 3) {/*problem, beep and ignore */
12741       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12742       SUMA_RETURNe;
12743    }
12744 
12745    sv->GVS[sv->StdView].RotaCenter[0] = fv3[0];
12746    sv->GVS[sv->StdView].RotaCenter[1] = fv3[1];
12747    sv->GVS[sv->StdView].RotaCenter[2] = fv3[2];
12748 
12749 
12750    SUMA_RETURNe;
12751 }
12752 
12753 /*!
12754    \brief rotates surface to face a certain coordinate
12755 
12756    \param s (char *) a strng containing X, Y, Z coordinates
12757    \param data (void *) a typecast of the pointer to the surface viewer to be affected
12758 
12759 */
SUMA_LookAtCoordinates(char * s,void * data)12760 void SUMA_LookAtCoordinates (char *s, void *data)
12761 {
12762    static char FuncName[]={"SUMA_LookAtCoordinates"};
12763    DList *list=NULL;
12764    SUMA_EngineData *ED = NULL;
12765    SUMA_SurfaceViewer *sv = NULL;
12766    float fv3[3];
12767    SUMA_Boolean LocalHead = NOPE;
12768 
12769    SUMA_ENTRY;
12770 
12771    // fprintf(stderr, "%s\n", FuncName);
12772 
12773    if (!s) SUMA_RETURNe;
12774 
12775    sv = (SUMA_SurfaceViewer *)data;
12776 
12777    /* parse s */
12778    if (SUMA_StringToNum (s, (void *)fv3, 3,1) != 3) {/*problem,beep and ignore */
12779       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12780       SUMA_RETURNe;
12781    }
12782 
12783    /* register fv3 with ED */
12784    if (!list) list = SUMA_CreateList();
12785    ED = SUMA_InitializeEngineListData (SE_SetLookAt);
12786    if (!SUMA_RegisterEngineListCommand (  list, ED,
12787                                           SEF_fv3, (void *)fv3,
12788                                           SES_Suma, (void *)sv, NOPE,
12789                                           SEI_Head, NULL )) {
12790       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12791       SUMA_RETURNe;
12792    }
12793    if (!SUMA_Engine (&list)) {
12794       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12795    }
12796 
12797    SUMA_RETURNe;
12798 }
12799 
SUMA_SV_SetRenderOrder(char * s,void * data)12800 void SUMA_SV_SetRenderOrder(char *s, void *data)
12801 {
12802    static char FuncName[]={"SUMA_SV_SetRenderOrder"};
12803    SUMA_SurfaceViewer *sv = NULL;
12804    SUMA_Boolean LocalHead = NOPE;
12805 
12806    SUMA_ENTRY;
12807 
12808    // fprintf(stderr, "%s\n", FuncName);
12809 
12810    if (!s) SUMA_RETURNe;
12811 
12812    sv = (SUMA_SurfaceViewer *)data;
12813    if (!sv) {
12814       SUMA_S_Err("Null sv");
12815       SUMA_RETURNe;
12816    }
12817 
12818    sv->N_otseq = SUMA_SetObjectDisplayOrder(s, sv->otseq);
12819 
12820    SUMA_RETURNe;
12821 }
12822 
SUMA_JumpIndex(char * s,void * data)12823 void SUMA_JumpIndex (char *s, void *data)
12824 {
12825    static char FuncName[]={"SUMA_JumpIndex"};
12826    SUMA_SurfaceViewer *sv = NULL;
12827    SUMA_ALL_DO *ado=NULL;
12828    char *variant = NULL;
12829    SUMA_Boolean LocalHead = NOPE;
12830 
12831    SUMA_ENTRY;
12832 
12833    // fprintf(stderr, "%s\n", FuncName);
12834 
12835    if (!s) SUMA_RETURNe;
12836 
12837    sv = (SUMA_SurfaceViewer *)data;
12838    if (!(ado = SUMA_SV_Focus_ADO(sv))) {
12839       SUMA_S_Err("No ado in focus");
12840       SUMA_RETURNe;
12841    }
12842 
12843    switch (ado->do_type) {
12844       case SO_type:
12845          SUMA_JumpIndex_SO (s, sv, (SUMA_SurfaceObject *)ado);
12846          break;
12847       case GDSET_type:
12848          SUMA_JumpIndex_GDSET (s, sv, (SUMA_DSET *)ado, variant);
12849          break;
12850       case CDOM_type:
12851          SUMA_JumpIndex_CO (s, sv, (SUMA_CIFTI_DO *)ado);
12852          break;
12853       case GRAPH_LINK_type: {
12854          SUMA_GraphLinkDO *gldo=(SUMA_GraphLinkDO *)ado;
12855          SUMA_DSET *dset=NULL;
12856          if (!(dset=SUMA_find_GLDO_Dset(gldo))) {
12857             SUMA_S_Errv("Failed to find dset for gldo %s!!!\n",
12858                         SUMA_ADO_Label(ado));
12859             break;
12860          }
12861          SUMA_JumpIndex_GDSET (s, sv, dset, gldo->variant);
12862          break; }
12863       case TRACT_type: {
12864          SUMA_JumpIndex_TDO (s, sv, (SUMA_TractDO *)ado);
12865          break; }
12866       case MASK_type: {
12867          SUMA_JumpIndex_MDO (s, sv, (SUMA_MaskDO *)ado);
12868          break; }
12869       case VO_type: {
12870          SUMA_JumpIndex_VO (s, sv, (SUMA_VolumeObject *)ado);
12871          break; }
12872       default:
12873          SUMA_S_Errv("For %s nothing my dear\n",
12874             SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type));
12875          break;
12876    }
12877    SUMA_RETURNe;
12878 }
12879 
12880 /*!
12881    \brief sends the cross hair to a certain node index
12882    \param s (char *) a string containing node index
12883    \param data (void *) a typecast of the pointer to the surface
12884                         viewer to be affected
12885 
12886 */
SUMA_JumpIndex_SO(char * s,SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO)12887 void SUMA_JumpIndex_SO (char *s, SUMA_SurfaceViewer *sv, SUMA_SurfaceObject *SO)
12888 {
12889    static char FuncName[]={"SUMA_JumpIndex_SO"};
12890    DList *list=NULL;
12891    SUMA_EngineData *ED = NULL;
12892    DListElmt *el=NULL, *Location=NULL;
12893    SUMA_SurfaceObject  *SOc=NULL;
12894    SUMA_SO_SIDE sd=SUMA_NO_SIDE;
12895    float fv3[3];
12896    int it, iv3[3];
12897    SUMA_Boolean LocalHead = NOPE;
12898 
12899    SUMA_ENTRY;
12900 
12901    // fprintf(stderr, "%s\n", FuncName);
12902 
12903    if (!s || !sv || !SO) SUMA_RETURNe;
12904 
12905   /* HERE you should check if you have an L or R at the beginning
12906    or end of s.
12907    If you do, then first see if the side of SO (the focus surface)
12908    is the same as the letter. If it is, proceed. If it is not,
12909    try to get the contralateral surface with SUMA_Contralateral_SO
12910    then set the contralateral as the focus surface, then proceed
12911    with setting the focus node. Needs more work
12912    */
12913    /* parse s */
12914    SUMA_LHv("Parsing %s\n", s);
12915    if (SUMA_StringToNumSide(s, (void*)fv3, 1,1, &sd) != 1) {
12916                                     /*problem, beep and ignore */
12917       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12918       SUMA_RETURNe;
12919    }
12920 
12921    /* do we have side match with Focus node? */
12922    SUMA_LHv("Side of jump is %d, SO %s side %d\n", sd, SO->Label, SO->Side);
12923    if (sd == SUMA_RIGHT || sd == SUMA_LEFT) {
12924       if ((SO->Side == SUMA_RIGHT || SO->Side == SUMA_LEFT) &&
12925             SO->Side != sd) {
12926          /* Need to swith sides */
12927          if ((SOc = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
12928             sv->Focus_DO_ID = SUMA_findSO_inDOv(SOc->idcode_str,
12929                                              SUMAg_DOv, SUMAg_N_DOv);
12930             SUMA_LHv("Jumping to %s (contralateral of %s)\n",
12931                   SOc->Label, SO->Label);
12932             SO = SOc;
12933          } else {
12934             SUMA_S_Errv("Failed to find contralateral surface to %s\n"
12935                         "Ignoring jump to node's side marker\n",
12936                         SO->Label);
12937          }
12938       }
12939    }
12940 
12941 
12942    /* Set the Nodeselection  */
12943    it = (int) fv3[0];
12944    if (!list) list = SUMA_CreateList ();
12945    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
12946    if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
12947                                           SEF_i, (void*)(&it),
12948                                           SES_Suma, (void *)sv, NOPE,
12949                                           SEI_Head, NULL))) {
12950       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12951       SUMA_RETURNe;
12952    } else {
12953       SUMA_RegisterEngineListCommand (  list, ED,
12954                                           SEF_ngr, NULL,
12955                                           SES_Suma, (void *)sv, NOPE,
12956                                           SEI_In, el);
12957    }
12958 
12959 
12960    /* Now set the cross hair position at the selected node*/
12961    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
12962    if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
12963                                           SEF_fv3, (void*)&(SO->NodeList[3*it]),
12964                                           SES_Suma, (void *)sv, NOPE,
12965                                           SEI_Head, NULL))) {
12966       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12967       SUMA_RETURNe;
12968    }
12969    /* and add the SO with this location, needed for VisX business*/
12970    SUMA_RegisterEngineListCommand (  list, ED,
12971                                            SEF_vp, (void *)SO,
12972                                            SES_Suma, (void *)sv, NOPE,
12973                                            SEI_In, Location);
12974 
12975    /* attach the cross hair to the selected surface */
12976    iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
12977    iv3[1] = it;
12978    iv3[2] = -1;
12979    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
12980    if (!SUMA_RegisterEngineListCommand (  list, ED,
12981                                           SEF_iv3, (void*)iv3,
12982                                           SES_Suma, (void *)sv, NOPE,
12983                                           SEI_Head, NULL)) {
12984       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12985       SUMA_RETURNe;
12986    }
12987 
12988    /* check to see if AFNI needs to be notified */
12989    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
12990       if (LocalHead)
12991          fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
12992       /* register a call to SetAfniCrossHair */
12993       it = 0; /* Set to 1 if you want instacorr notice to AFNI */
12994       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
12995       if (!SUMA_RegisterEngineListCommand (  list, ED,
12996                                           SEF_i, (void*)&it,
12997                                           SES_Suma, (void *)sv, NOPE,
12998                                           SEI_Tail, NULL)) {
12999          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13000          SUMA_RETURNe;
13001       }
13002 
13003    }
13004 
13005    /* and if GICOR needs some love */
13006    if (  SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
13007          SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
13008       if (LocalHead)
13009          fprintf(SUMA_STDERR,
13010                   "%s: Notifying GICOR of node selection\n", FuncName);
13011       /* register a call to SetGICORnode */
13012       SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
13013                                           SES_Suma, sv);
13014    }else {
13015       SUMA_LHv("No Notification to GICOR. %d %p\n",
13016                   SUMAg_CF->Connected_v[SUMA_GICORR_LINE], SUMAg_CF->giset);
13017    }
13018 
13019    /* call with the list */
13020    if (!SUMA_Engine (&list)) {
13021       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13022       SUMA_RETURNe;
13023    }
13024 
13025    /* now put in a request for locking cross hair but you must do this
13026    after the node selection has been executed
13027    NOTE: You do not always have SetNodeElem because the list might get emptied in
13028    the call to AFNI notification.
13029    You should just put the next call at the end of the list.*/
13030    if (!list) list = SUMA_CreateList();
13031    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13032    if (!SUMA_RegisterEngineListCommand (  list, ED,
13033                                           SEF_iv3, (void*)iv3,
13034                                           SES_Suma, (void *)sv, NOPE,
13035                                           SEI_Tail, NULL)) {
13036       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13037       SUMA_RETURNe;
13038    }
13039 
13040    /* call with the list */
13041    if (!SUMA_Engine (&list)) {
13042       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13043       SUMA_RETURNe;
13044    }
13045 
13046    /* redisplay curent only*/
13047    sv->ResetGLStateVariables = YUP;
13048    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13049 
13050    SUMA_RETURNe;
13051 
13052 }
13053 
13054 /* Jump to a certain edge on a graph dset */
SUMA_JumpIndex_GDSET(char * s,SUMA_SurfaceViewer * sv,SUMA_DSET * dset,char * variant)13055 void SUMA_JumpIndex_GDSET (char *s, SUMA_SurfaceViewer *sv,
13056                            SUMA_DSET *dset, char *variant)
13057 {
13058    static char FuncName[]={"SUMA_JumpIndex_GDSET"};
13059    DList *list=NULL;
13060    DListElmt *el=NULL, *Location=NULL;
13061    SUMA_EngineData *ED = NULL;
13062    float fv3[3];
13063    int it, iv3[3];
13064    SUMA_Boolean LocalHead = NOPE;
13065 
13066    SUMA_ENTRY;
13067 
13068    // fprintf(stderr, "%s\n", FuncName);
13069 
13070    if (!s || !sv) SUMA_RETURNe;
13071 
13072    /* parse s */
13073    SUMA_LHv("Parsing %s\n", s);
13074    if (SUMA_StringToNum(s, (void*)fv3, 1,1) != 1) {
13075                                     /*problem, beep and ignore */
13076       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13077       SUMA_RETURNe;
13078    }
13079 
13080    /* Set the Nodeselection  */
13081    it = (int) fv3[0];
13082    if (!list) list = SUMA_CreateList ();
13083    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13084    if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
13085                                           SEF_i, (void*)(&it),
13086                                           SES_Suma, (void *)sv, NOPE,
13087                                           SEI_Head, NULL))) {
13088       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13089       SUMA_RETURNe;
13090    } else {
13091       SUMA_RegisterEngineListCommand (  list, ED,
13092                                           SEF_ngr, NULL,
13093                                           SES_Suma, (void *)sv, NOPE,
13094                                           SEI_In, el);
13095    }
13096 
13097 
13098    /* Now set the cross hair position at the selected node*/
13099    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13100    if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
13101                                           SEF_fv3,
13102                             (void*)(SUMA_GDSET_NodeXYZ(dset, it, variant, NULL)),
13103                                           SES_Suma, (void *)sv, NOPE,
13104                                           SEI_Head, NULL))) {
13105       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13106       SUMA_RETURNe;
13107    }
13108    /* and add the object with this location */
13109    SUMA_RegisterEngineListCommand (  list, ED,
13110                                            SEF_vp, (void *)dset,
13111                                            SES_Suma, (void *)sv, NOPE,
13112                                            SEI_In, Location);
13113 
13114    /* attach the cross hair to the selected object
13115       Note that binding here is to edge of graph and not to a node*/
13116    SUMA_find_Dset_GLDO(dset,variant, iv3); /* this will set iv3[0] */
13117    iv3[1] = it;
13118    iv3[2] = -1;
13119    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13120    if (!SUMA_RegisterEngineListCommand (  list, ED,
13121                                           SEF_iv3, (void*)iv3,
13122                                           SES_Suma, (void *)sv, NOPE,
13123                                           SEI_Head, NULL)) {
13124       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13125       SUMA_RETURNe;
13126    }
13127 
13128    /* check to see if AFNI needs to be notified */
13129    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13130       if (LocalHead)
13131          fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13132       it = 0;
13133       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13134       if (!SUMA_RegisterEngineListCommand (  list, ED,
13135                                           SEF_i, (void*)&it,
13136                                           SES_Suma, (void *)sv, NOPE,
13137                                           SEI_Tail, NULL)) {
13138          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13139          SUMA_RETURNe;
13140       }
13141 
13142    }
13143 
13144    /* call with the list */
13145    if (!SUMA_Engine (&list)) {
13146       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13147       SUMA_RETURNe;
13148    }
13149 
13150    /* now put in a request for locking cross hair but you must do this
13151    after the node selection has been executed
13152    NOTE: You do not always have SetNodeElem because the list might get emptied in
13153    the call to AFNI notification.
13154    You should just put the next call at the end of the list.*/
13155    if (!list) list = SUMA_CreateList();
13156    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13157    if (!SUMA_RegisterEngineListCommand (  list, ED,
13158                                           SEF_iv3, (void*)iv3,
13159                                           SES_Suma, (void *)sv, NOPE,
13160                                           SEI_Tail, NULL)) {
13161       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13162       SUMA_RETURNe;
13163    }
13164 
13165    /* call with the list */
13166    if (!SUMA_Engine (&list)) {
13167       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13168       SUMA_RETURNe;
13169    }
13170 
13171    /* redisplay curent only*/
13172    sv->ResetGLStateVariables = YUP;
13173    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13174 
13175    SUMA_RETURNe;
13176 
13177 }
13178 
13179 /* Jump to a certain point on a tract object */
SUMA_JumpIndex_TDO(char * s,SUMA_SurfaceViewer * sv,SUMA_TractDO * tdo)13180 void SUMA_JumpIndex_TDO (char *s, SUMA_SurfaceViewer *sv,
13181                            SUMA_TractDO *tdo)
13182 {
13183    static char FuncName[]={"SUMA_JumpIndex_TDO"};
13184    DList *list=NULL;
13185    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)tdo;
13186    DListElmt *el=NULL, *Location=NULL;
13187    SUMA_EngineData *ED = NULL;
13188    float fv3[3];
13189    int it, iv15[15], iv3[3], nv = 0;
13190    char stmp[64];
13191    SUMA_Boolean revert_on_err = YUP;
13192    SUMA_Boolean LocalHead = NOPE;
13193 
13194    SUMA_ENTRY;
13195 
13196    // fprintf(stderr, "%s\n", FuncName);
13197 
13198    if (!s || !sv || !tdo || !tdo->net) SUMA_RETURNe;
13199 
13200    /* parse s */
13201    if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
13202        nv != 3) {
13203                                     /*problem, beep and ignore */
13204       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13205       SUMA_RETURNe;
13206    }
13207    SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
13208    if (nv == 3) {/* bundle, tract, point */
13209       iv15[SUMA_NET_BUN] = (int)fv3[SUMA_NET_BUN];
13210       iv15[SUMA_BUN_TRC] = (int)fv3[SUMA_BUN_TRC];
13211       iv15[SUMA_TRC_PNT] = (int)fv3[SUMA_TRC_PNT];
13212       iv15[SUMA_NET_TRC] =
13213          Network_TB_to_1T(tdo->net, iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]);
13214       it = Network_PTB_to_1P(tdo->net,
13215                iv15[SUMA_TRC_PNT], iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]);
13216       if (it < 0) { /* no good */
13217          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13218          SUMA_LH("BTP %d %d %d could not be parsed\n",
13219                  iv15[SUMA_NET_BUN],   iv15[SUMA_BUN_TRC], iv15[SUMA_TRC_PNT]);
13220          if (revert_on_err) {
13221             sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
13222             SUMA_JumpIndex_TDO(stmp, sv, tdo);
13223          }
13224          SUMA_RETURNe;
13225       }
13226       SUMA_LHv("Point ID %d from B%d T%d P%d (tract in net %d)\n",
13227                it, iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC],
13228                iv15[SUMA_TRC_PNT], iv15[SUMA_NET_TRC]);
13229    } else {
13230       /* Set the point selection  */
13231       it = (int) fv3[0];
13232       if (!Network_1P_to_PTB(tdo->net, it,
13233                iv15+SUMA_TRC_PNT, iv15+SUMA_BUN_TRC,
13234                iv15+SUMA_NET_BUN, iv15+SUMA_NET_TRC)) {
13235          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13236          SUMA_RETURNe;
13237       }
13238       SUMA_LHv("Point ID %d yielded B%d T%d P%d (tract in net %d) \n"
13239                "  (which yields back %d)\n",
13240                it, iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC], iv15[SUMA_TRC_PNT],
13241                iv15[SUMA_NET_TRC],
13242                Network_PTB_to_1P(tdo->net,
13243                   iv15[SUMA_TRC_PNT], iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]));
13244    }
13245 
13246    SUMA_TDO_PointXYZ(tdo, it, iv15, fv3);
13247    SUMA_LH("   Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
13248 
13249    if (!list) list = SUMA_CreateList ();
13250    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13251    if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
13252                                           SEF_i, (void*)(&it),
13253                                           SES_Suma, (void *)sv, NOPE,
13254                                           SEI_Head, NULL))) {
13255       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13256       SUMA_RETURNe;
13257    } else {
13258       SUMA_RegisterEngineListCommand (  list, ED,
13259                                           SEF_ngr, NULL,
13260                                           SES_Suma, (void *)sv, NOPE,
13261                                           SEI_In, el);
13262       SUMA_RegisterEngineListCommand (  list, ED,
13263                                           SEF_iv15, (void *)iv15,
13264                                           SES_Suma, (void *)sv, NOPE,
13265                                           SEI_In, el);
13266    }
13267 
13268 
13269    /* Now set the cross hair position at the selected point*/
13270    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13271    if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
13272                                           SEF_fv3, (void*)fv3,
13273                                           SES_Suma, (void *)sv, NOPE,
13274                                           SEI_Head, NULL))) {
13275       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13276       SUMA_RETURNe;
13277    }
13278    /* and add the DO with this location, needed for VisX business*/
13279    SUMA_RegisterEngineListCommand (  list, ED,
13280                                            SEF_vp, (void *)tdo,
13281                                            SES_Suma, (void *)sv, NOPE,
13282                                            SEI_In, Location);
13283 
13284    /* attach the cross hair to the selected object
13285       Note that binding here is to edge of graph and not to a node*/
13286    iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
13287    iv3[1] = it;
13288    iv3[2] = -1;
13289    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13290    if (!SUMA_RegisterEngineListCommand (  list, ED,
13291                                           SEF_iv3, (void*)iv3,
13292                                           SES_Suma, (void *)sv, NOPE,
13293                                           SEI_Head, NULL)) {
13294       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13295       SUMA_RETURNe;
13296    }
13297 
13298    /* check to see if AFNI needs to be notified */
13299    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13300       if (LocalHead)
13301          fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13302       it = 0;
13303       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13304       if (!SUMA_RegisterEngineListCommand (  list, ED,
13305                                           SEF_i, (void*)&it,
13306                                           SES_Suma, (void *)sv, NOPE,
13307                                           SEI_Tail, NULL)) {
13308          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13309          SUMA_RETURNe;
13310       }
13311 
13312    }
13313 
13314    /* call with the list */
13315    if (!SUMA_Engine (&list)) {
13316       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13317       SUMA_RETURNe;
13318    }
13319 
13320    /* now put in a request for locking cross hair but you must do this
13321    after the node selection has been executed
13322    NOTE: You do not always have SetNodeElem because the list might get emptied in
13323    the call to AFNI notification.
13324    You should just put the next call at the end of the list.*/
13325    if (!list) list = SUMA_CreateList();
13326    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13327    if (!SUMA_RegisterEngineListCommand (  list, ED,
13328                                           SEF_iv3, (void*)iv3,
13329                                           SES_Suma, (void *)sv, NOPE,
13330                                           SEI_Tail, NULL)) {
13331       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13332       SUMA_RETURNe;
13333    }
13334 
13335    /* call with the list */
13336    if (!SUMA_Engine (&list)) {
13337       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13338       SUMA_RETURNe;
13339    }
13340 
13341    /* redisplay curent only*/
13342    sv->ResetGLStateVariables = YUP;
13343    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13344 
13345    SUMA_RETURNe;
13346 
13347 }
13348 
13349 /* Jump to a certain datum on a CIFTI object */
SUMA_JumpIndex_CO(char * s,SUMA_SurfaceViewer * sv,SUMA_CIFTI_DO * co)13350 void SUMA_JumpIndex_CO (char *s, SUMA_SurfaceViewer *sv,
13351                         SUMA_CIFTI_DO *co)
13352 {
13353    static char FuncName[]={"SUMA_JumpIndex_CO"};
13354    DList *list=NULL;
13355    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)co;
13356    DListElmt *el=NULL, *Location=NULL;
13357    SUMA_EngineData *ED = NULL;
13358    float fv3[3], fv15[15];
13359    int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
13360    char stmp[64];
13361    SUMA_DSET *dset=NULL;
13362    SUMA_Boolean revert_on_err = YUP;
13363    SUMA_Boolean LocalHead = NOPE;
13364 
13365    SUMA_ENTRY;
13366 
13367    // fprintf(stderr, "%s\n", FuncName);
13368 
13369    SUMA_LH("Called");
13370 
13371    SUMA_S_Err("Not implemented, see SUMA_JumpIndex_VO and SUMA_JumpIndex_SO "
13372               "for inspiration. You will need to determine the domain of "
13373               "the index before jumping anyway");
13374 
13375    SUMA_RETURNe;
13376 }
13377 
13378 /* Jump to a certain point on a volume object */
SUMA_JumpIndex_VO(char * s,SUMA_SurfaceViewer * sv,SUMA_VolumeObject * vo)13379 void SUMA_JumpIndex_VO (char *s, SUMA_SurfaceViewer *sv,
13380                         SUMA_VolumeObject *vo)
13381 {
13382    static char FuncName[]={"SUMA_JumpIndex_VO"};
13383    DList *list=NULL;
13384    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)vo;
13385    DListElmt *el=NULL, *Location=NULL;
13386    SUMA_EngineData *ED = NULL;
13387    float fv3[3], fv15[15];
13388    int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
13389    char stmp[64];
13390    SUMA_DSET *dset=NULL;
13391    SUMA_Boolean revert_on_err = YUP;
13392    SUMA_Boolean LocalHead = NOPE;
13393 
13394    SUMA_ENTRY;
13395 
13396    // fprintf(stderr, "%s\n", FuncName);
13397 
13398    SUMA_LH("Called");
13399    if (!s || !sv || !vo ||
13400        !(dset = SUMA_VO_dset(vo)) ||
13401        !(dims = SUMA_GetDatasetDimensions(dset))) SUMA_RETURNe;
13402 
13403    /* parse s */
13404    if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
13405        nv != 3) {
13406                                     /*problem, beep and ignore */
13407       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13408       SUMA_RETURNe;
13409    }
13410    SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
13411    if (nv == 3) {/* i j k */
13412       iv15[SUMA_VOL_I] = (int)fv3[SUMA_VOL_I];
13413       iv15[SUMA_VOL_J] = (int)fv3[SUMA_VOL_J];
13414       iv15[SUMA_VOL_K] = (int)fv3[SUMA_VOL_K];
13415       if (iv15[SUMA_VOL_I] < 0 || iv15[SUMA_VOL_I] >= dims[0] ||
13416           iv15[SUMA_VOL_J] < 0 || iv15[SUMA_VOL_J] >= dims[1] ||
13417           iv15[SUMA_VOL_K] < 0 || iv15[SUMA_VOL_K] >= dims[2] ) {
13418          /* no good */
13419          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13420          SUMA_LH("IJK %d %d %d could not be parsed or out of range\n",
13421                  iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13422          if (revert_on_err) {
13423             sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
13424             SUMA_JumpIndex_VO(stmp, sv, vo);
13425          }
13426          SUMA_RETURNe;
13427       }
13428 
13429       iv15[SUMA_VOL_IJK] =
13430          SUMA_3D_2_1D_index(iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K],
13431          dims[0], dims[0]*dims[1] );
13432 
13433       it = iv15[SUMA_VOL_IJK];
13434 
13435       SUMA_LHv("Voxel ID %d from I%d J%d K%d\n",
13436                iv15[SUMA_VOL_IJK], iv15[SUMA_VOL_I], iv15[SUMA_VOL_J],
13437                iv15[SUMA_VOL_K]);
13438    } else {
13439       /* Set the point selection  */
13440       it = (int) fv3[0];
13441       if (it < 0 || it >= SDSET_NVOX(dset)) {
13442          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13443          SUMA_RETURNe;
13444       }
13445       Vox1D2Vox3D(it, dims[0], dims[0]*dims[1], (iv15+SUMA_VOL_I));
13446       SUMA_LHv("Point ID %d yielded I%d J%d K%d \n",
13447                it, iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13448    }
13449 
13450    SUMA_VO_PointXYZ(vo, it, iv15, fv3);
13451    SUMA_LH("   Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
13452    SUMA_MARK_PLANE_NOT_SET(fv15+SUMA_VOL_SLC_EQ0); /* No cigar */
13453 
13454    if (!list) list = SUMA_CreateList ();
13455    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13456    if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
13457                                           SEF_i, (void*)(&it),
13458                                           SES_Suma, (void *)sv, NOPE,
13459                                           SEI_Head, NULL))) {
13460       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13461       SUMA_RETURNe;
13462    } else {
13463       SUMA_RegisterEngineListCommand (  list, ED,
13464                                           SEF_ngr, NULL,
13465                                           SES_Suma, (void *)sv, NOPE,
13466                                           SEI_In, el);
13467       SUMA_RegisterEngineListCommand (  list, ED,
13468                                           SEF_iv15, (void *)iv15,
13469                                           SES_Suma, (void *)sv, NOPE,
13470                                           SEI_In, el);
13471       SUMA_RegisterEngineListCommand (  list, ED,
13472                                           SEF_fv15, (void *)fv15,
13473                                           SES_Suma, (void *)sv, NOPE,
13474                                           SEI_In, el);
13475    }
13476 
13477 
13478    /* Now set the cross hair position at the selected point*/
13479    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13480    if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
13481                                           SEF_fv3, (void*)fv3,
13482                                           SES_Suma, (void *)sv, NOPE,
13483                                           SEI_Head, NULL))) {
13484       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13485       SUMA_RETURNe;
13486    }
13487    /* and add the DO with this location, needed for VisX business*/
13488    SUMA_RegisterEngineListCommand (  list, ED,
13489                                            SEF_vp, (void *)vo,
13490                                            SES_Suma, (void *)sv, NOPE,
13491                                            SEI_In, Location);
13492 
13493    /* attach the cross hair to the selected object
13494       Note that binding here is to edge of graph and not to a node*/
13495    iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
13496    iv3[1] = it;
13497    iv3[2] = -1;
13498    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13499    if (!SUMA_RegisterEngineListCommand (  list, ED,
13500                                           SEF_iv3, (void*)iv3,
13501                                           SES_Suma, (void *)sv, NOPE,
13502                                           SEI_Head, NULL)) {
13503       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13504       SUMA_RETURNe;
13505    }
13506 
13507    /* check to see if AFNI needs to be notified */
13508    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13509       if (LocalHead)
13510          fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13511       it = 0;
13512       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13513       if (!SUMA_RegisterEngineListCommand (  list, ED,
13514                                           SEF_i, (void*)&it,
13515                                           SES_Suma, (void *)sv, NOPE,
13516                                           SEI_Tail, NULL)) {
13517          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13518          SUMA_RETURNe;
13519       }
13520 
13521    }
13522 
13523    /* call with the list */
13524    if (!SUMA_Engine (&list)) {
13525       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13526       SUMA_RETURNe;
13527    }
13528 
13529    /* now put in a request for locking cross hair but you must do this
13530    after the node selection has been executed
13531    NOTE: You do not always have SetNodeElem because the list might get emptied in
13532    the call to AFNI notification.
13533    You should just put the next call at the end of the list.*/
13534    if (!list) list = SUMA_CreateList();
13535    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13536    if (!SUMA_RegisterEngineListCommand (  list, ED,
13537                                           SEF_iv3, (void*)iv3,
13538                                           SES_Suma, (void *)sv, NOPE,
13539                                           SEI_Tail, NULL)) {
13540       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13541       SUMA_RETURNe;
13542    }
13543 
13544    /* call with the list */
13545    if (!SUMA_Engine (&list)) {
13546       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13547       SUMA_RETURNe;
13548    }
13549 
13550    /* redisplay curent only*/
13551    sv->ResetGLStateVariables = YUP;
13552    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13553 
13554    SUMA_RETURNe;
13555 
13556 }
13557 
13558 /* Jump to a certain point on a mask object */
SUMA_JumpIndex_MDO(char * s,SUMA_SurfaceViewer * sv,SUMA_MaskDO * mo)13559 void SUMA_JumpIndex_MDO (char *s, SUMA_SurfaceViewer *sv, SUMA_MaskDO *mo)
13560 {
13561    static char FuncName[]={"SUMA_JumpIndex_MDO"};
13562    DList *list=NULL;
13563    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)mo;
13564    DListElmt *el=NULL, *Location=NULL;
13565    SUMA_EngineData *ED = NULL;
13566    float fv3[3];
13567    int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
13568    char stmp[64];
13569    SUMA_DSET *dset=NULL;
13570    SUMA_Boolean revert_on_err = YUP;
13571    SUMA_Boolean LocalHead = NOPE;
13572 
13573    SUMA_ENTRY;
13574 
13575    // fprintf(stderr, "%s\n", FuncName);
13576 
13577    if (!s || !sv) SUMA_RETURNe;
13578 
13579    SUMA_S_Err("Not ready for action");
13580    SUMA_RETURNe;
13581 
13582    /* parse s */
13583    if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
13584        nv != 3) {
13585                                     /*problem, beep and ignore */
13586       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13587       SUMA_RETURNe;
13588    }
13589    SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
13590    if (nv == 3) {/* i j k */
13591       iv15[SUMA_VOL_I] = (int)fv3[SUMA_VOL_I];
13592       iv15[SUMA_VOL_J] = (int)fv3[SUMA_VOL_J];
13593       iv15[SUMA_VOL_K] = (int)fv3[SUMA_VOL_K];
13594       if (iv15[SUMA_VOL_I] < 0 || iv15[SUMA_VOL_I] >= dims[0] ||
13595           iv15[SUMA_VOL_J] < 0 || iv15[SUMA_VOL_J] >= dims[1] ||
13596           iv15[SUMA_VOL_K] < 0 || iv15[SUMA_VOL_K] >= dims[2] ) {
13597          /* no good */
13598          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13599          SUMA_LH("IJK %d %d %d could not be parsed or out of range\n",
13600                  iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13601          if (revert_on_err) {
13602             sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
13603             SUMA_JumpIndex_MDO(stmp, sv, mo);
13604          }
13605          SUMA_RETURNe;
13606       }
13607 
13608       iv15[SUMA_VOL_IJK] =
13609          SUMA_3D_2_1D_index(iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K],
13610          dims[0], dims[0]*dims[1] );
13611 
13612 
13613       SUMA_LHv("Voxel ID %d from I%d J%d K%d\n",
13614                iv15[SUMA_VOL_IJK], iv15[SUMA_VOL_I], iv15[SUMA_VOL_J],
13615                iv15[SUMA_VOL_K]);
13616    } else {
13617       /* Set the point selection  */
13618       it = (int) fv3[0];
13619       if (it < 0 || it >= SDSET_NVOX(dset)) {
13620          XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13621          SUMA_RETURNe;
13622       }
13623       Vox1D2Vox3D(it, dims[0], dims[0]*dims[1], (iv15+SUMA_VOL_I));
13624       SUMA_LHv("Point ID %d yielded I%d J%d K%d \n",
13625                it, iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13626    }
13627 
13628    SUMA_MDO_PointXYZ(mo, it, iv15, fv3);
13629    SUMA_LH("   Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
13630 
13631    if (!list) list = SUMA_CreateList ();
13632    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13633    if (!(el = SUMA_RegisterEngineListCommand (  list, ED,
13634                                           SEF_i, (void*)(&it),
13635                                           SES_Suma, (void *)sv, NOPE,
13636                                           SEI_Head, NULL))) {
13637       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13638       SUMA_RETURNe;
13639    } else {
13640       SUMA_RegisterEngineListCommand (  list, ED,
13641                                           SEF_ngr, NULL,
13642                                           SES_Suma, (void *)sv, NOPE,
13643                                           SEI_In, el);
13644       SUMA_RegisterEngineListCommand (  list, ED,
13645                                           SEF_iv15, (void *)iv15,
13646                                           SES_Suma, (void *)sv, NOPE,
13647                                           SEI_In, el);
13648    }
13649 
13650 
13651    /* Now set the cross hair position at the selected point*/
13652    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13653    if (!(Location=SUMA_RegisterEngineListCommand (  list, ED,
13654                                           SEF_fv3, (void*)fv3,
13655                                           SES_Suma, (void *)sv, NOPE,
13656                                           SEI_Head, NULL))) {
13657       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13658       SUMA_RETURNe;
13659    }
13660    /* and add the DO with this location, needed for VisX business*/
13661    SUMA_RegisterEngineListCommand (  list, ED,
13662                                            SEF_vp, (void *)mo,
13663                                            SES_Suma, (void *)sv, NOPE,
13664                                            SEI_In, Location);
13665 
13666    /* attach the cross hair to the selected object
13667       Note that binding here is to edge of graph and not to a node*/
13668    iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
13669    iv3[1] = it;
13670    iv3[2] = -1;
13671    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13672    if (!SUMA_RegisterEngineListCommand (  list, ED,
13673                                           SEF_iv3, (void*)iv3,
13674                                           SES_Suma, (void *)sv, NOPE,
13675                                           SEI_Head, NULL)) {
13676       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13677       SUMA_RETURNe;
13678    }
13679 
13680    /* check to see if AFNI needs to be notified */
13681    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13682       if (LocalHead)
13683          fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13684       it = 0;
13685       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13686       if (!SUMA_RegisterEngineListCommand (  list, ED,
13687                                           SEF_i, (void*)&it,
13688                                           SES_Suma, (void *)sv, NOPE,
13689                                           SEI_Tail, NULL)) {
13690          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13691          SUMA_RETURNe;
13692       }
13693 
13694    }
13695 
13696    /* call with the list */
13697    if (!SUMA_Engine (&list)) {
13698       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13699       SUMA_RETURNe;
13700    }
13701 
13702    /* now put in a request for locking cross hair but you must do this
13703    after the node selection has been executed
13704    NOTE: You do not always have SetNodeElem because the list might get emptied in
13705    the call to AFNI notification.
13706    You should just put the next call at the end of the list.*/
13707    if (!list) list = SUMA_CreateList();
13708    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13709    if (!SUMA_RegisterEngineListCommand (  list, ED,
13710                                           SEF_iv3, (void*)iv3,
13711                                           SES_Suma, (void *)sv, NOPE,
13712                                           SEI_Tail, NULL)) {
13713       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13714       SUMA_RETURNe;
13715    }
13716 
13717    /* call with the list */
13718    if (!SUMA_Engine (&list)) {
13719       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13720       SUMA_RETURNe;
13721    }
13722 
13723    /* redisplay curent only*/
13724    sv->ResetGLStateVariables = YUP;
13725    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13726 
13727    SUMA_RETURNe;
13728 
13729 }
13730 
13731 /*!
13732    \brief sends the cross hair to a certain XYZ location.
13733 
13734    \param s (char *) a string containing XYZ coordinates
13735    \param data (void *) a typecast of the pointer to the surface viewer to be affected
13736 
13737    - Update to AFNI is done if linked
13738    - Update to other viewers is performed IF they are XYZ locked
13739    (that can get confusing)
13740 */
SUMA_JumpXYZ(char * s,void * data)13741 void SUMA_JumpXYZ (char *s, void *data)
13742 {
13743    static char FuncName[]={"SUMA_JumpXYZ"};
13744    DList *list=NULL;
13745    DListElmt *Location=NULL;
13746    SUMA_EngineData *ED = NULL;
13747    SUMA_SurfaceViewer *sv = NULL;
13748    float fv3[3];
13749    SUMA_Boolean LocalHead = NOPE;
13750 
13751    SUMA_ENTRY;
13752 
13753    // fprintf(stderr, "%s\n", FuncName);
13754 
13755    if (!s) SUMA_RETURNe;
13756 
13757    sv = (SUMA_SurfaceViewer *)data;
13758 
13759    /* parse s */
13760    if (SUMA_StringToNum (s, (void*)fv3, 3,1) != 3) {/*problem, beep and ignore */
13761       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13762       SUMA_RETURNe;
13763    }
13764 
13765    /* Now set the cross hair position */
13766    if (!list) list = SUMA_CreateList ();
13767    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13768    if (!(Location = SUMA_RegisterEngineListCommand (  list, ED,
13769                                           SEF_fv3, (void*)fv3,
13770                                           SES_Suma, (void *)sv, NOPE,
13771                                           SEI_Head, NULL))) {
13772       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13773       SUMA_RETURNe;
13774    }
13775    /* and add the SO with this location (not possible here), needed for VisX
13776       business*/
13777    SUMA_RegisterEngineListCommand (  list, ED,
13778                                      SEF_vp, NULL,
13779                                      SES_Suma, (void *)sv, NOPE,
13780                                      SEI_In, Location);
13781 
13782    /* check to see if AFNI needs to be notified */
13783    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13784       int it;
13785       if (LocalHead)
13786          fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13787       it = 0;
13788       ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13789       if (!SUMA_RegisterEngineListCommand (  list, ED,
13790                                           SEF_i, (void*)&it,
13791                                           SES_Suma, (void *)sv, NOPE,
13792                                           SEI_Tail, NULL)) {
13793          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13794          SUMA_RETURNe;
13795       }
13796 
13797    }
13798 
13799    /* call with the list */
13800    if (!SUMA_Engine (&list)) {
13801       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13802       SUMA_RETURNe;
13803    }
13804 
13805    /* now put in a request for locking cross hair but you must
13806    do this after the node selection has been executed
13807    NOTE: You do not always have SetNodeElem because the list might
13808    get emptied in the call to AFNI notification.
13809    You should just put the next call at the end of the list.*/
13810    /* NOTE2: Only viewers that are XYZ locked will be affected */
13811    if (!list) list = SUMA_CreateList();
13812    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13813    if (!SUMA_RegisterEngineListCommand (  list, ED,
13814                                           SEF_Empty, NULL,
13815                                           SES_Suma, (void *)sv, NOPE,
13816                                           SEI_Tail, NULL)) {
13817       SUMA_SLP_Err("Failed to register element");
13818       SUMA_RETURNe;
13819    }
13820 
13821    /* call with the list */
13822    if (!SUMA_Engine (&list)) {
13823       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13824       SUMA_RETURNe;
13825    }
13826 
13827 
13828    /* redisplay curent only*/
13829    sv->ResetGLStateVariables = YUP;
13830    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13831 
13832    SUMA_RETURNe;
13833 }
13834 
13835 /*!
13836    \brief Changes the focus node without moving the cross hair
13837    \param s (char *) a string containing node index
13838    \param data (void *) a typecast of the pointer to the surface viewer to be affected
13839 
13840    -actions of this function are limited to the viewer that launched it
13841 */
13842 
SUMA_JumpFocusNode(char * s,void * data)13843 void SUMA_JumpFocusNode (char *s, void *data)
13844 {
13845    static char FuncName[]={"SUMA_JumpFocusNode"};
13846    DList *list=NULL;
13847    DListElmt *el=NULL;
13848    SUMA_EngineData *ED = NULL;
13849    SUMA_SurfaceViewer *sv = NULL;
13850    float fv3[3];
13851    int it;
13852    SUMA_SurfaceObject *SO=NULL, *SOc=NULL;
13853    SUMA_SO_SIDE sd=SUMA_NO_SIDE;
13854    SUMA_Boolean LocalHead = NOPE;
13855 
13856    SUMA_ENTRY;
13857 
13858    // fprintf(stderr, "%s\n", FuncName);
13859 
13860    if (!s) SUMA_RETURNe;
13861 
13862    sv = (SUMA_SurfaceViewer *)data;
13863    if (!(SO = SUMA_SV_Focus_SO(sv))) {
13864       SUMA_S_Err("No SO in focus");
13865       SUMA_RETURNe;
13866    }
13867 
13868 
13869    /* HERE you should check if you have an L or R at the beginning
13870    or end of s.
13871    If you do, then first see if the side of SO (the focus surface)
13872    is the same as the letter. If it is, proceed. If it is not,
13873    try to get the contralateral surface with SUMA_Contralateral_SO
13874    then set the contralateral as the focus surface, then proceed
13875    with setting the focus node. Needs more work
13876    */
13877    /* parse s */
13878    SUMA_LHv("Parsing %s\n", s);
13879    if (SUMA_StringToNumSide(s, (void*)fv3, 1,1, &sd) != 1) {
13880                                     /*problem, beep and ignore */
13881       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13882       SUMA_RETURNe;
13883    }
13884 
13885    SUMA_LHv("Side of focus jump is %d\n", sd);
13886    /* do we have side match with Focus node? */
13887    if (sd == SUMA_RIGHT || sd == SUMA_LEFT) {
13888       if ((SO->Side == SUMA_RIGHT || SO->Side == SUMA_LEFT) &&
13889             SO->Side != sd) {
13890          /* Need to swith sides */
13891          if ((SOc = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
13892             sv->Focus_DO_ID = SUMA_findSO_inDOv(SOc->idcode_str,
13893                                              SUMAg_DOv, SUMAg_N_DOv);
13894             SUMA_LHv("Jumping focus only to %s (contralateral of %s)\n",
13895                   SOc->Label, SO->Label);
13896             SO = SOc;
13897          } else {
13898             SUMA_S_Errv("Failed to find contralateral surface to %s\n"
13899                         "Ignoring jump to node's side marker\n",
13900                         SO->Label);
13901          }
13902       }
13903    }
13904    /* Set the Nodeselection  */
13905    it = (int) fv3[0];
13906    if (!list) list = SUMA_CreateList ();
13907    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13908    if (!(el=SUMA_RegisterEngineListCommand (  list, ED,
13909                                           SEF_i, (void*)(&it),
13910                                           SES_Suma, (void *)sv, NOPE,
13911                                           SEI_Head, NULL))) {
13912       SUMA_SLP_Err("Failed to register element");
13913       SUMA_RETURNe;
13914    } else {
13915       SUMA_RegisterEngineListCommand (  list, ED,
13916                                           SEF_ngr, NULL,
13917                                           SES_Suma, (void *)sv, NOPE,
13918                                           SEI_In, el);
13919    }
13920 
13921    /* call with the list */
13922    if (!SUMA_Engine (&list)) {
13923       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13924       SUMA_RETURNe;
13925    }
13926 
13927    /* redisplay curent only*/
13928    sv->ResetGLStateVariables = YUP;
13929    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13930 
13931    SUMA_RETURNe;
13932 
13933 }
13934 
13935 /*!
13936    \brief changes the selected faceset (Focus FaceSet)
13937    \param s (char *) a string containing FaceSet index
13938    \param data (void *) a typecast of the pointer to the surface viewer to be affected
13939 
13940 */
SUMA_JumpFocusFace(char * s,void * data)13941 void SUMA_JumpFocusFace (char *s, void *data)
13942 {
13943    static char FuncName[]={"SUMA_JumpFocusFace"};
13944    DList *list=NULL;
13945    SUMA_EngineData *ED = NULL;
13946    SUMA_SurfaceViewer *sv = NULL;
13947    float fv3[3];
13948    int it;
13949 
13950    SUMA_ENTRY;
13951 
13952    // fprintf(stderr, "%s\n", FuncName);
13953 
13954    if (!s) SUMA_RETURNe;
13955 
13956    sv = (SUMA_SurfaceViewer *)data;
13957 
13958    /* parse s */
13959    if (SUMA_StringToNum (s, (void*)fv3, 1,1) != 1) {/*problem, beep and ignore */
13960       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13961       SUMA_RETURNe;
13962    }
13963 
13964 
13965 
13966    /* Set the Faceselection  */
13967    it = (int) fv3[0];
13968    if (!list) list = SUMA_CreateList ();
13969    ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
13970    if (!SUMA_RegisterEngineListCommand (  list, ED,
13971                                           SEF_i, (void*)&it,
13972                                           SES_Suma, (void *)sv, NOPE,
13973                                           SEI_Head, NULL)) {
13974       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13975       SUMA_RETURNe;
13976    }
13977 
13978    /* call with the list */
13979    if (!SUMA_Engine (&list)) {
13980       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13981       SUMA_RETURNe;
13982    }
13983 
13984    /* redisplay curent only*/
13985    sv->ResetGLStateVariables = YUP;
13986    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13987 
13988    SUMA_RETURNe;
13989 
13990 }
13991 
13992 /*!
13993    \brief Highlight a set of nodes within a box
13994    \param s (char *) a string containing box center followed by box size (6 values)
13995    \param data (void *) a typecast of the pointer to the surface viewer to be affected
13996 
13997    - operates by coloring nodes inside box.
13998    - coloring is not permanent and modifies other colors already present
13999    - operates on current viewer only
14000 */
SUMA_HighlightBox(char * s,void * data)14001 void SUMA_HighlightBox (char *s, void *data)
14002 {
14003    static char FuncName[]={"SUMA_HighlightBox"};
14004    DList *list=NULL;
14005    SUMA_EngineData *ED = NULL;
14006    SUMA_SurfaceViewer *sv = NULL;
14007    float fv15[15];
14008 
14009    SUMA_ENTRY;
14010 
14011    // fprintf(stderr, "%s\n", FuncName);
14012 
14013    if (!s) SUMA_RETURNe;
14014 
14015    sv = (SUMA_SurfaceViewer *)data;
14016 
14017    /* parse s */
14018    if (SUMA_StringToNum (s, (void*)fv15, 6,1) != 6) {
14019                               /*problem, beep and ignore */
14020       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
14021       SUMA_RETURNe;
14022    }
14023 
14024    /* register fv15 with ED */
14025    if (!list) list = SUMA_CreateList();
14026    ED = SUMA_InitializeEngineListData (SE_HighlightNodes);
14027    if (!SUMA_RegisterEngineListCommand (     list, ED,
14028                                              SEF_fv15, (void*)fv15,
14029                                              SES_Suma, (void *)sv, NOPE,
14030                                              SEI_Head, NULL)) {
14031          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
14032          SUMA_RETURNe;
14033    }
14034 
14035    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
14036 
14037    if (!SUMA_Engine (&list)) {
14038       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
14039    }
14040 
14041 
14042    SUMA_RETURNe;
14043 
14044 }
14045 
14046 
14047 /*** Begin - Drawing colored line ***
14048 
14049 void Line(Vector3 start, Vector3 end) {
14050 
14051         Vector3 startPoint = start;
14052         Vector3 endPoint = end;
14053         Vector3 lineColor = {1.0, 1.0, 1.0};
14054 
14055         const char *vertexShaderSource = "#version 330 core\n"
14056             "layout (location = 0) in vec3 aPos;\n"
14057             "uniform mat4 MVP;\n"
14058             "void main()\n"
14059             "{\n"
14060             "   gl_Position = MVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
14061             "}\0";
14062         const char *fragmentShaderSource = "#version 330 core\n"
14063             "out vec4 FragColor;\n"
14064             "uniform vec3 color;\n"
14065             "void main()\n"
14066             "{\n"
14067             "   FragColor = vec4(color, 1.0f);\n"
14068             "}\n\0";
14069 
14070         // vertex shader
14071         int vertexShader = glCreateShader(GL_VERTEX_SHADER);
14072         glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
14073         glCompileShader(vertexShader);
14074         // check for shader compile errors
14075 
14076         // fragment shader
14077         int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
14078         glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
14079         glCompileShader(fragmentShader);
14080         // check for shader compile errors
14081 
14082         // link shaders
14083         shaderProgram = glCreateProgram();
14084         glAttachShader(shaderProgram, vertexShader);
14085         glAttachShader(shaderProgram, fragmentShader);
14086         glLinkProgram(shaderProgram);
14087         // check for linking errors
14088 
14089         glDeleteShader(vertexShader);
14090         glDeleteShader(fragmentShader);
14091 
14092         vertices = {
14093              start.x, start.y, start.z,
14094              end.x, end.y, end.z,
14095 
14096         };
14097 
14098         glGenVertexArrays(1, &VAO);
14099         glGenBuffers(1, &VBO);
14100         glBindVertexArray(VAO);
14101 
14102         glBindBuffer(GL_ARRAY_BUFFER, VBO);
14103         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);
14104 
14105         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
14106         glEnableVertexAttribArray(0);
14107 
14108         glBindBuffer(GL_ARRAY_BUFFER, 0);
14109         glBindVertexArray(0);
14110 
14111     }
14112 
14113     int setMVP(mat4 mvp) {
14114         MVP = mvp;
14115     }
14116 
14117     int setColor(vec3 color) {
14118         lineColor = color;
14119     }
14120 
14121     int draw() {
14122         glUseProgram(shaderProgram);
14123         glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
14124         glUniform3fv(glGetUniformLocation(shaderProgram, "color"), 1, &lineColor[0]);
14125 
14126         glBindVertexArray(VAO);
14127         glDrawArrays(GL_LINES, 0, 2);
14128         return 0;
14129     }
14130 
14131     ~Line() {
14132 
14133         glDeleteVertexArrays(1, &VAO);
14134         glDeleteBuffers(1, &VBO);
14135         glDeleteProgram(shaderProgram);
14136     }
14137 
14138 
14139 *** End - Drawing colored line ***/
14140 
DrawCube(Display * dpy,Window win)14141 void DrawCube(Display *dpy, Window  win){
14142 
14143     float vertCoords[] = {
14144         0.5f, 0.5f, 0.5f,       //V0
14145         -0.5f, 0.5f, 0.5f,       //V1
14146         -0.5f, -0.5f, 0.5f,       //V2
14147         0.5f, -0.5f, 0.5f,       //V3
14148         0.5f, -0.5f, -0.5f,       //V4
14149         0.5f, 0.5f, -0.5f,       //V5
14150         -0.5f, 0.5f, -0.5f,       //V6
14151         -0.5f, -0.5f, -0.5f        //V7
14152     };
14153 
14154     GLubyte indices[] = {
14155         0, 1, 2, 3,             // Front face
14156         5, 0, 3, 4,             // Right face
14157         5, 6, 7, 4,             // Back face
14158         5, 6, 1, 0,             // Upper face
14159         1, 6, 7, 2,             // Left face
14160         7, 4, 3, 2             // Bottom face
14161     };
14162 
14163     GLubyte colors[] = {
14164         255, 0, 0,              //V0
14165         0, 255, 0,              //V1
14166         0, 0, 255,              //V2
14167         255, 255, 0,              //V3
14168         0, 255, 255,              //V4
14169         255, 0, 255,              //V5
14170         255, 255, 255,              //V6
14171         0, 0, 0,              //V7
14172     };
14173     static int angle = 0;
14174     XWindowAttributes  winattr;
14175     XGetWindowAttributes( dpy, win, &winattr);
14176     glViewport(0,0,winattr.width, winattr.height);
14177 
14178     glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
14179     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
14180     glColor3f(0.0f, 0.9f, 1.0f);
14181 
14182     glPushMatrix();
14183         glRotatef(angle, 0.5, 1.0, 0.0);
14184 
14185 #if 0
14186         glBegin(GL_TRIANGLES);
14187             glVertex3f(0.0, -0.2f, 0.5f);
14188             glVertex3f(-0.5, 0.3, 0.5f);
14189             glVertex3f(0.5, 0.6f, 0.5f);
14190         glEnd();
14191 #endif
14192         glEnableClientState(GL_VERTEX_ARRAY);
14193         glEnableClientState(GL_COLOR_ARRAY);
14194         glColorPointer(3,GL_UNSIGNED_BYTE,0,colors);
14195         glVertexPointer(3,GL_FLOAT,0,vertCoords);
14196 
14197         glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE, indices);
14198 
14199     glPopMatrix();
14200 
14201     glXSwapBuffers(dpy, win);
14202 
14203     usleep(5000);
14204 
14205     angle += 1;
14206 }
14207 
makeCube()14208 void makeCube(){
14209     int i;
14210 /*
14211     Display *dpy;
14212     static int     screen;
14213     Window  win, root_win;
14214     XEvent  event;
14215 
14216     // unsigned int    depth;
14217     XSetWindowAttributes    attrs;
14218 
14219     XWindowAttributes  winattr;
14220 
14221     // GLX vars
14222     GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
14223     XVisualInfo *visual;
14224     GLXContext glc;
14225 
14226     if (!(dpy = XOpenDisplay(NULL))){
14227         fprintf(stderr, "Cannot open display\n");
14228         exit(1);
14229     }
14230 
14231     screen = DefaultScreen(dpy);
14232 
14233     int depth = DefaultDepth(dpy, screen);
14234 
14235     root_win = RootWindow(dpy, screen); // Program crashes
14236 
14237     visual = glXChooseVisual(dpy, screen, att);
14238 
14239     attrs.border_pixel = BlackPixel(dpy, screen);
14240     attrs.background_pixel = WhitePixel(dpy, screen);
14241     attrs.override_redirect = True;
14242 
14243     // attrs.colormap = CopyFromParent;
14244     attrs.colormap = XCreateColormap(dpy, root_win, visual->visual, AllocNone);
14245     attrs.event_mask = ExposureMask | KeyPressMask | PointerMotionMask | ButtonPress;
14246     // Note the PointerMotionMask is necessary for the MotionNotify event
14247     //  to be seen
14248 
14249     // Parent window
14250     win = XCreateWindow(dpy, root_win,
14251             200, 200, 500, 300,
14252             0, visual->depth, InputOutput, visual->visual,
14253             CWBackPixel | CWColormap | CWBorderPixel |
14254             CWEventMask, &attrs);
14255 
14256     XMapWindow(dpy, win);
14257 
14258     // Get current window
14259     Display * currentDisplay = glXGetCurrentDisplay();
14260     GLXContext currentContext = glXGetCurrentContext();
14261     Window focused;
14262     int revert_to;
14263     XGetInputFocus(currentDisplay, &focused, &revert_to);
14264 
14265     glc = glXCreateContext(dpy, visual, NULL, GL_TRUE);
14266 
14267     // glXMakeCurrent(dpy, win, glc);
14268     glXMakeCurrent(currentDisplay, focused, currentContext);
14269 
14270     glEnable(GL_DEPTH_TEST);
14271 
14272     glEnable(GL_LINE_SMOOTH);    // fOR LINE formatting (Makes line thicker)
14273 
14274     glEnable(GL_LINE_STIPPLE);
14275 
14276     for (i=0; i<5; ++i)
14277         DrawCube(currentDisplay, focused);
14278         // DrawCube(dpy, win);
14279         */
14280     static int     screen;
14281     Window  win, root_win;
14282 
14283     // GLX vars
14284     GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
14285     XVisualInfo *visual;
14286     GLXContext glc;
14287 
14288     // For pointer position
14289     Window  root_return, child_return;
14290     int     root_x_return, root_y_return;
14291     int     win_x_return, win_y_return;
14292     unsigned int    mask_return;
14293     XSetWindowAttributes    attrs;
14294 
14295     // Get current window
14296     Display * currentDisplay = glXGetCurrentDisplay();
14297     GLXContext currentContext = glXGetCurrentContext();
14298     Window focused;
14299     int revert_to;
14300     XGetInputFocus(currentDisplay, &focused, &revert_to);
14301 
14302     screen = DefaultScreen(currentDisplay);
14303 
14304     int depth = DefaultDepth(currentDisplay, screen);
14305 
14306     root_win = RootWindow(currentDisplay, screen); // Program crashes
14307 
14308     visual = glXChooseVisual(currentDisplay, screen, att);
14309 
14310     attrs.border_pixel = BlackPixel(currentDisplay, screen);
14311     attrs.background_pixel = WhitePixel(currentDisplay, screen);
14312     attrs.override_redirect = True;
14313     attrs.colormap = XCreateColormap(currentDisplay, root_win, visual->visual, AllocNone);
14314     attrs.event_mask = ExposureMask | KeyPressMask | PointerMotionMask | ButtonPress;
14315 
14316     glc = glXCreateContext(currentDisplay, visual, NULL, GL_TRUE);
14317 
14318     // glXMakeCurrent(dpy, win, glc);
14319     glXMakeCurrent(currentDisplay, focused, currentContext);
14320 
14321     glEnable(GL_DEPTH_TEST);
14322 
14323     glEnable(GL_LINE_SMOOTH);    // fOR LINE formatting (Makes line thicker)
14324 
14325     glEnable(GL_LINE_STIPPLE);
14326 
14327     for (i=0; i<5; ++i)
14328         DrawCube(currentDisplay, focused);
14329 
14330 
14331 }
14332