1 /* Trying to isolate SUMA's help functions so that they can
2 be used from AFNI */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <assert.h>
6 #include <string.h>
7 #include <sys/time.h>
8 #include <math.h>
9 #include "mrilib.h"
10 #include "niml.h"
11 #include "../niml/niml_private.h"
12 #include "suma_objs.h" /* 21 Apr 2020 */
13 #include <X11/Intrinsic.h>
14
15 /*------------------------------------------------------------*/
16 #ifndef _MCW_XUTIL_HEADER_ /* 10 Jul 2020 */
17 extern void MCW_register_hint( RwcWidget , char * ) ;
18 extern void MCW_reghint_children( RwcWidget , char * ) ;
19 extern void MCW_register_help( RwcWidget , char * ) ;
20 extern void MCW_reghelp_children( RwcWidget , char * ) ;
21 #endif
22 /*------------------------------------------------------------*/
23
24 static DList *All_GUI_Help = NULL;
25 static char *DocumentedWidgets = NULL; /*!< Widget names for which a Sphinx
26 documentation entry has been created */
SUMA_get_DocumentedWidgets(void)27 char *SUMA_get_DocumentedWidgets(void) { return(DocumentedWidgets); }
SUMA_set_DocumentedWidgets(char ** s)28 char *SUMA_set_DocumentedWidgets(char **s) {
29 static char FuncName[]={"SUMA_set_DocumentedWidgets"};
30 if (!s || !*s) {
31 SUMA_S_Err("Come on friend!");
32 SUMA_RETURN(DocumentedWidgets);
33 }
34 SUMA_ifree(DocumentedWidgets);
35 DocumentedWidgets = *s; *s = NULL;
36 SUMA_RETURN(DocumentedWidgets);
37 }
38
SUMA_free_DocumentedWidgets(void)39 void SUMA_free_DocumentedWidgets(void) {
40 SUMA_ifree(DocumentedWidgets); return; }
41
SUMA_Free_Widget_Help(void * data)42 void SUMA_Free_Widget_Help(void *data)
43 {
44 static char FuncName[]={"SUMA_Free_Widget_Help"};
45 GUI_WIDGET_HELP *gwh = (GUI_WIDGET_HELP *)data;
46
47 SUMA_ENTRY;
48 if (data) SUMA_free(data);
49 SUMA_RETURNe;
50 }
51
52 /* Format help key string */
SUMA_hkf_eng(char * keyi,TFORM target,char * cm)53 char * SUMA_hkf_eng(char *keyi, TFORM target, char *cm)
54 {
55 static char FuncName[]={"SUMA_hkf_eng"};
56 static char ss[20][512];
57 char key1[256], key2[256], *direc="kbd";
58 static int c;
59 char *s, cs[5]={""}, *wname_URI=NULL;
60 int ichar=-1;
61
62 if (!cm) cm = "";
63
64 ++c;
65 if (c > 19) c = 0;
66 s = (char *)ss[c]; s[0] = s[511] = '\0';
67 if (!keyi) return(s);
68 switch (target) {
69 default:
70 case TXT: /* SUMA */
71 /* Actually COMMA, PERIOD, STAR mods are not needed, leave
72 for posterity.*/
73 if (strstr(keyi,"COMMA")) {
74 snprintf(key1, 255, ",");
75 } else if (strstr(keyi,"PERIOD")) {
76 snprintf(key1, 255, ".");
77 } else if (strstr(keyi,"STAR")) {
78 snprintf(key1, 255, "*");
79 } else {
80 snprintf(key1, 255, "%s", keyi);
81 }
82 snprintf(s, 511, " %s", key1);
83 return(s);
84 break;
85 case SPX: /* Sphinx */
86 if (strstr(keyi,"->") == keyi) {
87 /* Won't work if you pass key with blanks before '->'
88 But why do such a thing? */
89 snprintf(key1, 255, "%s", keyi+2);
90 snprintf(key2, 255, "%s", keyi+2);
91 direc = "menuselection";
92 } else {
93 snprintf(key1, 255, "%s", keyi);
94 snprintf(key2, 255, "%s", keyi);
95 direc = "kbd";
96 }
97
98 if (key1[1] == '\0') {
99 ichar = 0;
100 } else if (key1[strlen(key1)-2] == '+'){
101 ichar = strlen(key1)-1;
102 } else ichar = -1;
103
104 if (ichar > -1) {
105 if (SUMA_IS_UPPER_C(key1[ichar])) {
106 sprintf(cs,"UC_");
107 } else {
108 sprintf(cs,"LC_");
109 }
110 } else {
111 cs[0] = '\0';
112 }
113
114 #if 0 /* Good for sphinx, not good for having permalinks ! */
115 snprintf(s, 511, "\n.. _%s%s%s:\n\n:%s:`%s`"
116 , cm, cs, deblank_allname(key1,'_')
117 , direc, deblank_name(key2));
118 #elif 1 /* Good for sphinx and for permalinks */
119 direc = "";
120 snprintf(s, 511, "\n.. _%s%s%s:\n\n:ref:`%s %s<%s%s%s>`"
121 , cm, cs, deblank_allname(key1,'_')
122 , deblank_name(key2), direc, cm, cs, deblank_allname(key1,'_'));
123 #else
124 /* Brute force, and a pain, as you can see below.
125 Left here as illustration for 'raw html use */
126 /* Note that I endup with two labels for the key,
127 one as an html permalink and another sphinx one
128 preceding the text of the first line. The reason
129 this was done has to do with how the help
130 for each key is defined explicitly in
131 a series of SUMA_StringAppend() calls.
132 I could skip the second (sphinx) label but then
133 my html page would have ':' at the beginning of
134 each line. The solution would be to store the
135 help for each key much as I do for each widget
136 and make SUMA_hkf() take the 1st line and body (a parallel
137 to the widget hint and help) as options. That's a lot
138 of tediousness I don't care for quite yet. */
139 wname_URI = SUMA_append_replace_string(cm,
140 deblank_allname(key1,'_'),cs,0);
141 SUMA_Sphinx_Widget_Name_2_Link(wname_URI);
142 snprintf(s, 511, "\n"
143 ".. _%s%s%s:\n"
144 "\n"
145 ".. only:: latex or latexpdf\n"
146 "\n"
147 " :%s:`%s`\n"
148 "\n"
149 "..\n"
150 "\n"
151 ".. only:: html\n"
152 "\n"
153 " .. raw:: html\n"
154 "\n"
155 " <div class=\"section\" id=\"%s\">\n"
156 " <p><a class=\"section\" href=\"#%s\" title=\"%s keyb link\">"
157 "<strong>%s</strong>:</a> </p></div>\n"
158 "\n"
159 "..\n"
160 "\n"
161 ":%s:`%s`",
162 cm, cs, deblank_allname(key1,'_') ,
163 direc, deblank_name(key2),
164 wname_URI, wname_URI,
165 deblank_name(key2), deblank_name(key2),
166 direc, deblank_name(key2));
167
168 SUMA_ifree(wname_URI);
169
170 #endif
171
172 return(s);
173 break;
174 }
175 return(s);
176 }
177
SUMA_hkf(char * keyi,TFORM target)178 char * SUMA_hkf(char *keyi, TFORM target) {
179 /* for main suma area keys */
180 return(SUMA_hkf_eng(keyi,target,""));
181 }
182
SUMA_hkcf(char * keyi,TFORM target)183 char * SUMA_hkcf(char *keyi, TFORM target) {
184 /* for colormap area keys */
185 return(SUMA_hkf_eng(keyi,target,"CM_"));
186 }
187
SUMA_Sphinx_Widget_Name_2_Link(char * name)188 char *SUMA_Sphinx_Widget_Name_2_Link(char *name)
189 {
190 static char FuncName[]={"SUMA_Sphinx_Widget_Name_2_Link"};
191 int m_i, m_c=0;
192
193 SUMA_ENTRY;
194
195 if (name) {
196 SUMA_TO_LOWER(name);
197 if (name[strlen(name)-1] == '.') name[strlen(name)-1]='\0';
198
199 for (m_i=0, m_c=0; m_i<strlen(name); ++m_i) {
200 if (SUMA_IS_BLANK(name[m_i]) || name[m_i] == '/' ||
201 name[m_i] == '[' || name[m_i] == ']' || name[m_i] == '.' ||
202 name[m_i] == '_' || name[m_i] == '+') {
203 name[m_c++] = '-';
204 } else if (name[m_i] == '>') {
205 /* ignore it */
206 } else {
207 name[m_c++] = name[m_i];
208 }
209 }
210 }
211 name[m_c] = '\0';
212
213 SUMA_RETURN(name);
214 }
215
216 /* Format GUI section */
SUMA_gsf_eng(char * uwname,TFORM target,char ** hintout,char ** helpout)217 char * SUMA_gsf_eng(char *uwname, TFORM target, char **hintout, char **helpout)
218 {
219 static char FuncName[]={"SUMA_gsf_eng"};
220 static char ss[20][512], wnameclp[256];
221 char key1[256], key2[256], *direc="kbd", *lnm=NULL;
222 static int c;
223 char *s=NULL, *su=NULL, *shh=NULL, *sii=NULL, *stmp=NULL,
224 *wname = NULL, *wname_URI=NULL;
225 int ichar=-1, i, ntip=0;
226 SUMA_Boolean found = NOPE;
227 GUI_WIDGET_HELP *gwh=NULL, *gwhi=NULL;
228 SUMA_Boolean LocalHead = NOPE;
229
230 ++c;
231 if (c > 19) c = 0;
232 s = (char *)ss[c]; s[0] = s[511] = '\0';
233
234 if ((helpout && *helpout) || (hintout && *hintout)) {
235 SUMA_S_Err("string init error");
236 return(s);
237 }
238
239
240 if (!uwname) return(s);
241 /* make a copy, uwname is likely a static pointer from a convenience
242 function. Could change underneath you */
243 wname = SUMA_copy_string(uwname);
244
245 switch (target) {
246 default:
247 case TXT: /* SUMA */
248 snprintf(s, 511, " %s", wname);
249 SUMA_ifree(wname); return(s);
250 break;
251 case WEB:
252 SUMA_LH("Webbing with %s", wname);
253 if (helpout || hintout) {
254 SUMA_S_Err("Not supposed to call WEB as target with "
255 "helpout or hintout");
256 SUMA_ifree(wname); return(s);
257 }
258 lnm = SUMA_copy_string(wname);
259 if (!(gwh = SUMA_Get_GUI_Help(lnm, target, NULL, NULL,0))) {
260 SUMA_S_Err("No help for %s\n", lnm);
261 SUMA_suggest_GUI_Name_Match(lnm, 8, NULL);
262 }
263 SUMA_ifree(lnm);
264
265 if (!gwh) { SUMA_ifree(wname); return(s); }
266
267
268 found = NOPE;
269 lnm = SUMA_copy_string(wname);
270 if (gwh->type == 1) { /* a regular olde widget */
271 /* DO NOT rely on SUMA_is_Documented_Widget()
272 outside of targ == WEB */
273 if (!SUMA_is_Documented_Widget(lnm)) {
274 /* Not all widget in a table have entries so get
275 rid of .c??, .r??, .[*], or .[*,*] and
276 try again. */
277 ntip = strlen(lnm)-1;
278 if (ntip > 4) {
279 while (ntip > 0 &&lnm[ntip] != '.') --ntip;
280 }
281 if ( (strlen(lnm)-ntip) == 4 &&
282 (lnm[ntip+1] == 'r' || lnm[ntip+1] == 'c') &&
283 SUMA_IS_DIGIT(lnm[ntip+2]) &&
284 SUMA_IS_DIGIT(lnm[ntip+3]) ) {
285 lnm[ntip] = '\0';
286 } else if ((strlen(lnm)-ntip) > 3 &&
287 lnm[strlen(lnm)-1] == ']' &&
288 lnm[ntip+1] == ']') {
289 lnm[ntip] = '\0';
290 }
291 /* try again */
292 if (SUMA_is_Documented_Widget(lnm)) {
293 SUMA_LH("Found after much suffering as %s", lnm);
294 found = YUP;
295 }
296 } else {
297 SUMA_LH("Got Widget with %s, %s", s, lnm);
298 found=YUP;
299 }
300 }
301 snprintf(s,511,"https://afni.nimh.nih.gov/pub/dist/doc/htmldoc");
302 if (found) {
303 SUMA_Sphinx_Widget_Name_2_Link(lnm);
304 SUMA_strncat(s,"/SUMA/Controllers.html#", 511);
305 SUMA_strncat(s,lnm,511);
306 SUMA_ifree(sii);
307 SUMA_ifree(lnm);
308 } else { /* Either a container widget
309 or a widget for which no match
310 was found */
311 /* backup until you find a container widget then try for it */
312 gwhi = NULL;
313 i = 1;
314 while (!gwhi && i < gwh->name_lvl){
315 /* Try some guessing.
316 Before March 4 2015 only headings had permalinks
317 created by SPHINX.
318 Now I manually insert permalinks for the vast
319 majority of the widgets. Still, some widgets
320 such as table cells, or frames, might not have their
321 own entries so we try to get help from their container
322 */
323 stmp = SUMA_copy_string(SUMA_Name_GUI_Help_eng(gwh,-i));
324 SUMA_LH("Now at %s", stmp);
325 gwhi = SUMA_Get_GUI_Help(stmp, target, NULL, NULL, 0);
326 if (gwhi && gwhi->type == 0) {
327 SUMA_LH("Got one at %s!",stmp);
328
329 } else {
330 gwhi = NULL; /* try again */
331 }
332 SUMA_ifree(stmp);
333 ++i; /* keep going lower */
334 }
335
336 gwh = gwhi;
337 if (!gwh || gwh->name_lvl<1) {
338 SUMA_LH("No good link found, going with default");
339 SUMA_ifree(wname); return(s);
340 }
341
342 /* Turn the container name to a link */
343 if (gwh->hint) {
344 sii = SUMA_copy_string(gwh->hint);
345 SUMA_Sphinx_Widget_Name_2_Link(sii);
346 SUMA_strncat(s,"/SUMA/Controllers.html#", 511);
347 SUMA_strncat(s,sii,511);
348 SUMA_ifree(sii);
349 }
350 }
351 SUMA_ifree(wname);
352 return(s);
353 break;
354 case SPX: /* Sphinx */
355 if (!(gwh = SUMA_Get_GUI_Help(wname, target, &shh, &sii,3))) {
356 SUMA_S_Err("No help for %s\n", wname);
357 SUMA_suggest_GUI_Name_Match(wname, 8, NULL);
358 shh = SUMA_copy_string(wname);
359 sii = SUMA_copy_string(wname);
360 }
361
362 if (!sii) sii = SUMA_copy_string("No Hint");
363 if (helpout) *helpout = shh;
364 if (hintout) *hintout = sii;
365
366 if (!gwh) {
367 if (!hintout) SUMA_ifree(sii); SUMA_ifree(wname); return(s);
368 }
369
370 su = (char *)SUMA_calloc(strlen(sii)+2, sizeof(char));
371
372 lnm = gwh->name[gwh->name_lvl-1];
373 snprintf(wnameclp, 255, "%s", lnm);
374 if (strstr(wnameclp,".r00")) { /* get rid of .r00 */
375 wnameclp[strlen(lnm)-4]='\0';
376 }
377 if (strstr(wnameclp,".c00")) { /* get rid of .c00 */
378 wnameclp[strlen(lnm)-4]='\0';
379 }
380
381 switch (gwh->type) {
382 case 0: /* container only */
383 if (gwh->name_lvl == 1) {
384 for (i=0; i<strlen(sii); ++i) {su[i] = '-';} su[i] = '\0';
385 snprintf(s, 511, "\n"
386 ".. _%s:\n"
387 "\n"
388 "%s\n"
389 "%s\n",
390 wname, sii, su);
391 } else if (gwh->name_lvl == 2) {
392 for (i=0; i<strlen(sii); ++i) {su[i] = '^';} su[i] = '\0';
393 snprintf(s, 511, "\n"
394 ".. _%s:\n"
395 "\n"
396 "%s\n"
397 "%s\n",
398 wname, sii, su);
399 } else if (gwh->name_lvl == 3) {
400 for (i=0; i<strlen(sii); ++i) {su[i] = '"';} su[i] = '\0';
401 snprintf(s, 511, "\n"
402 ".. _%s:\n"
403 "\n"
404 "%s\n"
405 "%s\n",
406 wname, sii, su);
407 } else if (gwh->name_lvl == 4) {
408 for (i=0; i<strlen(sii); ++i) {su[i] = '.';} su[i] = '\0';
409 snprintf(s, 511, "\n"
410 ".. _%s:\n"
411 "\n"
412 "%s\n"
413 "%s\n",
414 wname, sii, su);
415 } else {
416 snprintf(s, 511, "\n"
417 " .. _%s:\n"
418 "\n"
419 "**%s**: %s\n"
420 "\n",
421 wname, wnameclp,sii);
422 }
423 break;
424 case 1: /* actual widget */
425 #if 0 /* Looks nice, but no permalinks */
426 snprintf(s, 511, "\n"
427 " .. _%s:\n"
428 "\n"
429 "**%s**: %s\n"
430 "\n",
431 wname, wnameclp,sii);
432 #elif 1 /* Good for sphinx and for permalinks */
433 snprintf(s, 511, "\n"
434 " .. _%s:\n"
435 "\n"
436 ":ref:`%s<%s>`: %s\n"
437 "\n",
438 wname, wnameclp, wname, sii);
439 #else
440 /* Brute force, and a pain, as you can see below.
441 Left here as illustration for 'raw html use */
442 /* The "only::" directives below are not
443 necessary if we are only producing html
444 output. I kept them in should we build
445 other than html in the future */
446 wname_URI = SUMA_copy_string(wname);
447 SUMA_Sphinx_Widget_Name_2_Link(wname_URI);
448 snprintf(s, 511, "\n"
449 " .. _%s:\n"
450 "\n"
451 " .. only:: latex or latexpdf\n"
452 "\n"
453 " **%s**:\n"
454 "\n"
455 " ..\n"
456 "\n"
457 " .. only:: html\n"
458 "\n"
459 " .. raw:: html\n"
460 "\n"
461 " <div class=\"section\" id=\"%s\">\n"
462 " <p><a class=\"section\" href=\"#%s\" title=\"%s widget link\">"
463 "<strong>%s</strong>:</a> %s</p></div>\n"
464 "\n"
465 " ..\n"
466 "\n",
467 wname,
468 wnameclp,
469 wname_URI, wname_URI, wnameclp,
470 wnameclp,sii);
471 SUMA_ifree(wname_URI);
472 #endif
473 break;
474 case 2: /* Just permalink, no text to appear on purpose */
475 wname_URI = SUMA_copy_string(wname);
476 SUMA_Sphinx_Widget_Name_2_Link(wname_URI);
477 snprintf(s, 511, "\n"
478 ".. only:: html\n"
479 "\n"
480 " .. raw:: html\n"
481 "\n"
482 " <div class=\"section\" id=\"%s\">\n"
483 " <p><a class=\"section\" href=\"#%s\" title=\"%s widget link\">"
484 "</a> </p></div>\n"
485 "\n"
486 "..\n"
487 "\n",
488 wname_URI, wname_URI, wnameclp);
489 SUMA_ifree(wname_URI);
490 break;
491 default:
492 SUMA_S_Err("Bad type %d", gwh->type);
493 break;
494 }
495
496 if (!hintout) SUMA_ifree(sii);
497 if (!helpout) SUMA_ifree(shh);
498 SUMA_ifree(su);
499 SUMA_ifree(wname);
500 return(s);
501 break;
502 }
503
504 return(s);
505 }
506
507
508 /*
509 Register help for a widget. This is to replace all individual
510 calls to MCW_register_help and _hint.
511
512 Pointer to help is copied so make sure help is not freed.
513
514 Widget help becoming centralized to help with auto generation of
515 help webpage
516 */
517
SUMA_Register_Widget_Help(RwcWidget w,int type,char * name,char * hint,char * help)518 SUMA_Boolean SUMA_Register_Widget_Help(RwcWidget w, int type, char *name,
519 char *hint, char *help)
520 {
521 static char FuncName[]={"SUMA_Register_Widget_Help"};
522 char *s=NULL, *st=NULL;
523
524 SUMA_ENTRY;
525
526 if (!SUMA_Register_GUI_Help(name, hint, help, w, type)) {
527 SUMA_S_Err("Failed at string level registration");
528 SUMA_RETURN(NOPE);
529 }
530
531 if (w) {
532 if (help) {
533 s = SUMA_copy_string(help);
534 s = SUMA_Sphinx_String_Edit(&s, TXT, 0);
535 st = s;
536 s = SUMA_Break_String(st, 60); SUMA_ifree(st);
537 /* DO not free s, MCW_register_help uses the pointer as
538 data to the help callback */
539 MCW_register_help(w, s);
540 }
541 if (hint) {
542 /* Just make a copy of the hint and don't worry about
543 what got passed! */
544 s = SUMA_copy_string(hint);
545 MCW_register_hint(w, s);
546 }
547 }
548
549 SUMA_RETURN(YUP);
550 }
551
SUMA_Register_Widget_Children_Help(RwcWidget w,int type,char * name,char * hint,char * help)552 SUMA_Boolean SUMA_Register_Widget_Children_Help(RwcWidget w, int type, char *name,
553 char *hint, char *help)
554 {
555 static char FuncName[]={"SUMA_Register_Widget_Children_Help"};
556 char *s=NULL, *st=NULL;
557
558 SUMA_ENTRY;
559
560 if (!w || !help) {
561 SUMA_S_Err("NULL widget!!! or No Help");
562 SUMA_RETURN(NOPE);
563 }
564
565 if (!SUMA_Register_GUI_Help(name, hint, help, w, type)) {
566 SUMA_S_Err("Failed at string level registration");
567 SUMA_RETURN(NOPE);
568 }
569
570 if (help) {
571 s = SUMA_copy_string(help);
572 s = SUMA_Sphinx_String_Edit(&s, TXT, 0);
573 st = s;
574 s = SUMA_Break_String(st, 60); SUMA_ifree(st);
575 /* DO not free s, MCW_register_help uses the pointer as
576 data to the help callback */
577 MCW_reghelp_children(w, s);
578 }
579
580 if (hint) {
581 /* Just make a copy of the hint and don't worry about
582 what got passed! */
583 s = SUMA_copy_string(hint);
584 MCW_register_hint(w, s);
585 }
586 SUMA_RETURN(YUP);
587 }
588
589 /*!
590 Return the help and hint strings stored in the GUI help list.
591
592 \param gname (char *)Name of widget
593 \param format (int) 0: Default
594 1: Sphinx format
595 \param helpout (char **): If Not NULL, this will contain
596 the pointer to a copy of the help string
597 formatted per format.
598 Note that if helpout, *helpout
599 must be NULL at the function call.
600 You must also free *helpout when
601 done with it.
602 \param hintout (char **): If Not NULL, this will contain
603 the pointer to a copy of the hint string
604 formatted per format.
605 if (hintout), *hintout must be NULL at
606 function call. You must also free *hintout
607 when done with it.
608 \param whelp_off (int ): If non-zero, number of blank charcters by which
609 to offset the lines of a widget's help string
610 \return gwh (GUI_WIDGET_HELP *) A pointer to the structure containing
611 the widget help.
612 NULL if nothing was found.
613 */
SUMA_Get_GUI_Help(char * gname,TFORM format,char ** helpout,char ** hintout,int whelp_off)614 GUI_WIDGET_HELP *SUMA_Get_GUI_Help( char *gname, TFORM format,
615 char **helpout, char **hintout,
616 int whelp_off)
617 {
618 static char FuncName[]={"SUMA_Get_GUI_Help"};
619 char *s = NULL, *ss=NULL;
620 DListElmt *el = NULL;
621 int nn;
622 GUI_WIDGET_HELP *gwhc=NULL;
623 SUMA_Boolean LocalHead = NOPE;
624
625 SUMA_ENTRY;
626
627 if (!gname) { SUMA_S_Err("NULL name"); SUMA_RETURN(gwhc);}
628
629 if (!All_GUI_Help || !dlist_size(All_GUI_Help)) {
630 SUMA_S_Err("No help list");
631 SUMA_RETURN(gwhc);
632 }
633 if ((helpout && *helpout) || (hintout && *hintout)) {
634 SUMA_S_Err("string init error");
635 SUMA_RETURN(gwhc);
636 }
637
638 /* Seek name in list */
639 SUMA_LH("Seeking %s", gname);
640 /* Find name in list.
641 Note that no attempt at fast search is done here even though the
642 list is alphabetical... */
643 gwhc = NULL;
644 do {
645 if (!el) el = dlist_head(All_GUI_Help);
646 else el = dlist_next(el);
647 gwhc = (GUI_WIDGET_HELP *)el->data;
648 ss = SUMA_Name_GUI_Help(gwhc);
649 SUMA_LH("Comparing %s to %s (nn=%d)",
650 ss, gname,
651 strcmp(SUMA_Name_GUI_Help(gwhc),
652 gname));
653 if (ss == gname) { /* Safety oblige */
654 SUMA_S_Crit("Collision handsome! Don't send me gname pointers "
655 "returned by the evil SUMA_Name_GUI_Help()!");
656 }
657 if ((nn = strcmp(ss, gname)) == 0) {
658 el = NULL;
659 } else {
660 gwhc = NULL;
661 }
662 } while (el && el != dlist_tail(All_GUI_Help));
663
664 if (gwhc) {
665 SUMA_LH("Got new: %s, nn=%d", SUMA_Name_GUI_Help(gwhc), nn);
666 if (helpout) {
667 *helpout = SUMA_copy_string(gwhc->help);
668 if (gwhc->type == 1 && whelp_off) {/* widget and offset requested */
669 SUMA_Sphinx_String_Edit(helpout, format, whelp_off);
670 } else {
671 SUMA_Sphinx_String_Edit(helpout, format, 0);
672 }
673 }
674 if (hintout) {
675 *hintout = SUMA_copy_string(gwhc->hint);
676 SUMA_Sphinx_String_Edit(hintout, format, 0);
677 }
678 } else {
679 SUMA_LH("Got nothing for %s", gname);
680 }
681
682 SUMA_RETURN(gwhc);
683 }
684
685 /*!
686 Return the help struct for a certain widget.
687
688 */
SUMA_Get_Widget_Help(RwcWidget w)689 GUI_WIDGET_HELP *SUMA_Get_Widget_Help( RwcWidget w )
690 {
691 static char FuncName[]={"SUMA_Get_Widget_Help"};
692 char *s = NULL;
693 DListElmt *el = NULL;
694 int nn;
695 GUI_WIDGET_HELP *gwhc=NULL;
696
697 SUMA_ENTRY;
698
699 if (!w) { SUMA_S_Err("NULL w"); SUMA_RETURN(gwhc);}
700
701 if (!All_GUI_Help || !dlist_size(All_GUI_Help)) {
702 SUMA_S_Err("No help list");
703 SUMA_RETURN(gwhc);
704 }
705
706
707
708 /* Find widget in list. */
709 gwhc = NULL;
710 el = NULL;
711 do {
712 if (!el) el = dlist_head(All_GUI_Help);
713 else el = dlist_next(el);
714 gwhc = (GUI_WIDGET_HELP *)el->data;
715 if (w == gwhc->w) {
716 el = NULL;
717 } else {
718 gwhc = NULL;
719 }
720 } while (el && el != dlist_tail(All_GUI_Help));
721
722 if (!gwhc && (s = XtName(w))) { /* Try matching the hint to the widget name,
723 This is done for container widgets */
724 el = NULL;
725 do {
726 if (!el) el = dlist_head(All_GUI_Help);
727 else el = dlist_next(el);
728 gwhc = (GUI_WIDGET_HELP *)el->data;
729 if (gwhc->hint && !strcmp(s, gwhc->hint)) {
730 el = NULL;
731 } else {
732 gwhc = NULL;
733 }
734 } while (el && el != dlist_tail(All_GUI_Help));
735 }
736
737 SUMA_RETURN(gwhc);
738 }
739
SUMA_Show_All_GUI_Help(DList * dl,FILE * fout,int detail,int format)740 void SUMA_Show_All_GUI_Help(DList *dl, FILE *fout, int detail, int format)
741 {
742 static char FuncName[]={"SUMA_Show_All_GUI_Help"};
743 char *s=NULL;
744
745 SUMA_ENTRY;
746
747 if (!fout) fout = stdout;
748
749 s = SUMA_All_GUI_Help_Info(dl, detail, format);
750
751 fprintf(fout, "%s", s);
752
753 SUMA_ifree(s);
754
755 SUMA_RETURNe;
756 }
757
SUMA_Register_GUI_Help(char * which,char * hint,char * help,RwcWidget widget,int type)758 int SUMA_Register_GUI_Help(char *which, char *hint, char *help,
759 RwcWidget widget, int type)
760 {
761 static char FuncName[]={"SUMA_Register_GUI_Help"};
762 GUI_WIDGET_HELP *gwh=NULL, *gwhc=NULL;
763 char *sstmp = NULL, *s=NULL, buf[64]={""};
764 DListElmt *el=NULL;
765 static char WhinedNames[1025]={""};
766 int nn;
767 SUMA_Boolean LocalHead = NOPE;
768
769 SUMA_ENTRY;
770
771 if (!hint && !which) {
772 SUMA_S_Err("No hint, no which");
773 SUMA_RETURN(NOPE);
774 }
775
776 if (!which) { /* get from hint if it has "which" string between
777 ":which:" directives.
778 ":which:SurfCont->more:which:hint goes here"*/
779 if ( !(strstr(hint,":which:") == hint) ||
780 !(sstmp = strstr(hint+strlen(":which:"),":which:")) ) {
781 SUMA_S_Err("No which and no :which: in hint. No good");
782 SUMA_RETURN(NOPE);
783 }
784 which = hint+strlen(":which:");
785 hint = sstmp+strlen(":which:");
786 }
787
788 gwh = (GUI_WIDGET_HELP *)SUMA_calloc(1,sizeof(GUI_WIDGET_HELP));
789
790 gwh->w = (void *)widget;
791 gwh->type = type; /* 1, regular widget,
792 0, container widget, used for organizing the help,
793 2, a way to insert an html URI for widgets not
794 individually tracked in the help. For now
795 this is only done for table entries. */
796
797 /* parse which: SurfCont->more */
798 sstmp = which;
799 gwh->name_lvl = 0;
800 while( (s = strstr(sstmp, "->")) && gwh->name_lvl < 9 ) {
801 if (s == sstmp) {
802 SUMA_S_Err("Empty child in %s\n", which);
803 SUMA_free(gwh);
804 SUMA_RETURN(NOPE);
805 }
806 nn = s - sstmp;
807 if (nn > 63) {
808 SUMA_S_Err("Too wordy for me.");
809 SUMA_free(gwh);
810 SUMA_RETURN(NOPE);
811 }
812 strncpy(gwh->name[gwh->name_lvl], sstmp, nn);
813 gwh->name[gwh->name_lvl][nn+1] = '\0';
814 sstmp = s+2; /* skip -> */
815 ++gwh->name_lvl;
816 }
817 /* copy last one */
818 strncpy(gwh->name[gwh->name_lvl], sstmp, 63);
819 gwh->name[gwh->name_lvl][63] = '\0';
820 ++gwh->name_lvl;
821
822 /* store the hint */
823 if (hint) {
824 if (strlen(hint)>255) {
825 SUMA_S_Err("Hint too long");
826 SUMA_free(gwh);
827 SUMA_RETURN(NOPE);
828 }
829 strncpy(gwh->hint, hint, 255); gwh->hint[255] = '\0';
830 }
831
832 /* store the help */
833 gwh->help = help;
834
835 /* Put it all in */
836 if (!All_GUI_Help) {
837 All_GUI_Help = (DList *)SUMA_calloc(1, sizeof(DList));
838 dlist_init(All_GUI_Help, SUMA_Free_Widget_Help);
839 }
840
841 /* insert in list */
842 if (!dlist_size(All_GUI_Help)) {
843 dlist_ins_next(All_GUI_Help, dlist_head(All_GUI_Help), (void *)gwh);
844 SUMA_RETURN(YUP);
845 }
846
847 SUMA_LH("Inserting '%s' with %s %s",
848 SUMA_Name_GUI_Help(gwh), gwh->hint, gwh->help);
849 /* Insert in alphabetical order */
850 el = dlist_head(All_GUI_Help);
851 do {
852 gwhc = (GUI_WIDGET_HELP *)el->data;
853 if ((nn = strcmp(SUMA_Name_GUI_Help(gwhc),
854 SUMA_Name_GUI_Help(gwh))) == 0) {
855 snprintf(buf, 63, "%s;",SUMA_Name_GUI_Help(gwh));
856 if (LocalHead || !(sstmp=strstr(WhinedNames, buf))) {
857 SUMA_S_Note("GUI Name %s already in use. No special help entry."
858 "%s",
859 SUMA_Name_GUI_Help(gwh),
860 LocalHead ? "":"\nFurther warnings for this name curtailed.");
861 if (!sstmp) SUMA_strncat(WhinedNames,buf, 1023);
862 if (LocalHead) SUMA_DUMP_TRACE("Trace at duplicate GUI name");
863 SUMA_free(gwh);
864 }
865 SUMA_RETURN(YUP);
866 } else if (nn < 0) {
867 dlist_ins_next(All_GUI_Help, el, (void *)gwh);
868 SUMA_RETURN(YUP);
869 } else {
870 el = dlist_next(el);
871 }
872 } while (el && el != dlist_tail(All_GUI_Help));
873
874 /* Reached bottom without going over, put on the top */
875 dlist_ins_prev(All_GUI_Help, dlist_head(All_GUI_Help), (void *)gwh);
876
877 /* A debug for when you get to the bottom condition */
878 if (LocalHead) {
879 SUMA_Show_All_GUI_Help(All_GUI_Help, NULL, 0, 0);
880 }
881
882 SUMA_RETURN(YUP);
883 }
884
SUMA_Name_GUI_Help(GUI_WIDGET_HELP * gwh)885 char *SUMA_Name_GUI_Help(GUI_WIDGET_HELP *gwh) {
886 static char FuncName[]={"SUMA_Name_GUI_Help"};
887 return(SUMA_Name_GUI_Help_eng(gwh, 0));
888 }
889
SUMA_Name_GUI_Help_eng(GUI_WIDGET_HELP * gwh,int lvl)890 char *SUMA_Name_GUI_Help_eng(GUI_WIDGET_HELP *gwh, int lvl)
891 {
892 static char FuncName[]={"SUMA_Name_GUI_Help_eng"};
893 static char sa[10][641], *s=NULL;
894 static int nc=0;
895 int k;
896
897 SUMA_ENTRY;
898
899 ++nc; if (nc > 9) nc = 0;
900 s = (char *)sa[nc]; s[0] = '\0';
901
902 if (!gwh) SUMA_RETURN(s);
903
904 if (lvl <= 0) lvl = gwh->name_lvl+lvl;
905 if (lvl > gwh->name_lvl) lvl = gwh->name_lvl;
906
907 for (k=0; k<lvl; ++k) {
908 SUMA_strncat(s,gwh->name[k], 640);
909 if (k<lvl-1) SUMA_strncat(s,"->", 640);
910 }
911
912 SUMA_RETURN(s);
913 }
914
SUMA_All_GUI_Help_Info(DList * dl,int detail,int format)915 char *SUMA_All_GUI_Help_Info(DList *dl, int detail, int format)
916 {
917 static char FuncName[]={"SUMA_All_GUI_Help_Info"};
918 SUMA_STRING *SS=NULL;
919 DListElmt *el=NULL;
920 char *s=NULL;
921 GUI_WIDGET_HELP *gwh=NULL;
922
923 SUMA_ENTRY;
924
925 SS = SUMA_StringAppend (NULL, NULL);
926
927 if (!dl) {
928 SS = SUMA_StringAppend(SS,"NULL dl");
929 } else {
930 SS = SUMA_StringAppend_va(SS,
931 "Help for %d widgets. Detail %d, Format %d\n"
932 "--------------------------------------------\n",
933 dlist_size(dl), detail, format);
934 el = dlist_head(dl);
935 do {
936 gwh = (GUI_WIDGET_HELP *)el->data;
937 if (!gwh) SUMA_StringAppend(SS,"NULL widget data!");
938 else {
939 SUMA_StringAppend_va(SS,"Widget: %s (%p)\n",
940 SUMA_Name_GUI_Help(gwh), gwh->w);
941 if (detail > 0)
942 SUMA_StringAppend_va(SS," hint: %s\n", gwh->hint);
943 if (detail > 1) {
944 s = SUMA_copy_string(gwh->help);
945 switch (format) {
946 case 0:
947 SUMA_Sphinx_String_Edit(&s, TXT, 0);
948 SUMA_StringAppend_va(SS," help: %s\n", s);
949 SUMA_ifree(s);
950 break;
951 default:
952 case 1:
953 SUMA_Sphinx_String_Edit(&s, SPX, 0);
954 SUMA_StringAppend_va(SS," help: %s\n", s);
955 SUMA_ifree(s);
956 break;
957 }
958 }
959 SUMA_StringAppend_va(SS,"\n");
960 }
961 el = dlist_next(el);
962 } while (el);
963 }
964
965 SUMA_StringAppend_va(SS,"\n");
966
967 SUMA_SS2S(SS, s);
968 SUMA_RETURN(s);
969 }
970
SUMA_is_Documented_Widget(char * wname)971 SUMA_Boolean SUMA_is_Documented_Widget(char *wname)
972 {
973 static char FuncName[]={"SUMA_is_Documented_Widget"};
974 SUMA_Boolean LocalHead = NOPE;
975
976 SUMA_ENTRY;
977
978 if (!wname) SUMA_RETURN(NOPE);
979 if (!DocumentedWidgets) {
980 SUMA_S_Err("Must call SUMA_set_DocumentedWidgets() first!");
981 SUMA_RETURN(NOPE);
982 }
983 if (strstr(DocumentedWidgets, wname)) SUMA_RETURN(YUP);
984
985 SUMA_LH("Widget %s not in:\n%s", wname, DocumentedWidgets);
986 SUMA_RETURN(NOPE);
987 }
988
989
SUMA_suggest_GUI_Name_Match(char * wname,int nmx,DList * dl)990 void SUMA_suggest_GUI_Name_Match(char *wname, int nmx, DList *dl)
991 {
992 static char FuncName[]={"SUMA_suggest_GUI_Name_Match"};
993 int i, nlot;
994 char **lot=NULL, **slot=NULL;
995 DListElmt *el=NULL;
996 GUI_WIDGET_HELP *gwhc=NULL;
997
998 SUMA_ENTRY;
999
1000 if (!dl) dl = All_GUI_Help;
1001
1002 if (!dl || !dlist_size(dl)) {
1003 SUMA_S_Err("No list to be had");
1004 SUMA_RETURNe;
1005 }
1006 lot = (char **)SUMA_calloc(dlist_size(dl), sizeof(char *));
1007 nlot = 0; i = 0;
1008 gwhc = NULL;
1009 do {
1010 if (!el) el = dlist_head(dl);
1011 else el = dlist_next(el);
1012 gwhc = (GUI_WIDGET_HELP *)el->data;
1013 lot[i] = SUMA_copy_string(SUMA_Name_GUI_Help(gwhc));
1014 ++i;
1015 } while (el && el != dlist_tail(dl));
1016 nlot = i;
1017
1018 slot = approx_str_sort(lot, nlot, wname, 0, NULL, 0, NULL, NULL);
1019
1020 if (nmx < 0) nmx = nlot;
1021 fprintf(SUMA_STDERR,
1022 "Suggestions for %s\n"
1023 "---------------\n", wname);
1024 for (i=0; i < nlot && i < nmx; ++i) {
1025 fprintf(SUMA_STDERR,
1026 " %s\n", slot[i]);
1027 }
1028
1029 for (i=0; i < nlot; ++i) {
1030 SUMA_ifree(lot[i]);
1031 SUMA_ifree(slot[i]);
1032 }
1033 SUMA_ifree(lot);
1034 SUMA_ifree(slot);
1035 SUMA_RETURNe;
1036 }
1037
1038