FreeWRL / FreeX3D 4.3.0
common.c
1/*
2
3 FreeWRL support library.
4
5 See common.h.
6
7*/
8
9/*
10 MVC - the setter functions here in common.c are called from the Model (libfreewrl),
11 - the getter functions you call from your View (UI), typically once per frame, in a style called 'polling'
12 - once per Controller loop (_DisplayThread) you can have the controller notify your View that
13 it's time to poll the Model for updates
14 - benefit of MVC: the Model never calls back into the View, so isn't dependent on it, so
15 a) the View is easier to change (for different platforms and windowing technology), and
16 b) the Model is UI-technology-agnostic, so it's easier to maintain across platforms.
17 - Polling vs callbacks: the reason we poll the model, instead of registering callbacks:
18 the Controller is usually in the same language/technology as the UI, which often isn't C,
19 and calling into C is usually much easier then calling back from C into python, ObjectiveC, Java, C#
20 or whatever other technology/language your View/UI and Controller is in
21*/
22
23#include <config.h>
24#include <system.h>
25#include <internal.h>
26#include <libFreeWRL.h>
27#include <iglobal.h>
28#include "../ui/common.h"
29#include <scenegraph/Vector.h>
30
31// OLD_IPHONE_AQUA #if defined (_MSC_VER) || defined (AQUA) || defined(QNX) || defined(_ANDROID) || defined(ANDROIDNDK)
32#if defined (_MSC_VER) || defined (AQUA) || defined(QNX) || defined(_ANDROID) || defined(ANDROIDNDK)
33#include "../../buildversion.h"
34#endif
35
36
37// Linux builds, thanks to our very own Ian, creates this function for us.
38// on other platforms, we have to have this defined, as we don't have Ian's
39// talents to help us out.
40
41// OLD_IPHONE_AQUA #if defined (AQUA) || defined (_MSC_VER) || defined(QNX) || defined(_ANDROID) || defined(ANDROIDNDK)
42#if defined (_MSC_VER) || defined (AQUA) || defined(QNX) || defined(_ANDROID) || defined(ANDROIDNDK)
43const char *libFreeWRL_get_version(void) {return FW_BUILD_VERSION_STR;}
44//#else desktop linux which has a more complex versioning system
45#endif
46
47
48#define MAXSTAT 200
49
50#define MAXTITLE 200
51
52typedef struct keyval {
53 char *key;
54 char *val;
55} keyval;
56
57/* textual status messages */
58typedef struct pcommon{
59 int itrap;
60 float myFps; // = (float) 0.0;
61 int target_frames_per_second;
62 char myMenuStatus[MAXSTAT];
63 char messagebar[MAXSTAT];
64 char fpsbar[16];
65 char distbar[16];
66 char window_title[MAXTITLE];
67 int cursorStyle;
68 int promptForURL;
69 int promptForFile;
70 int sb_hasString;// = FALSE;
71 char buffer[200];
72 int showConsoleText;
73 void *colorScheme;
74 int colorSchemeChanged;
75 int pin_statusbar;
76 int pin_menubar;
77 int want_menubar;
78 int want_statusbar;
79 struct Vector *keyvals;
80 float density_factor;
81 int pedal;
82 int hover;
83 int jsengine;
84 int jsengine_variant;
85 int draw_bounding_boxes;
86}*ppcommon;
87void *common_constructor(){
88 void *v = MALLOCV(sizeof(struct pcommon));
89 memset(v,0,sizeof(struct pcommon));
90 return v;
91}
92void common_init(struct tcommon *t){
93 //public
94 //private
95 t->prv = common_constructor();
96 {
97 ppcommon p = (ppcommon)t->prv;
98 p->itrap = 0; //handy for debugging, see fwl_setTrap, fwl_getTrap
99 p->myFps = (float) 0.0;
100 p->cursorStyle = ACURSE;
101 p->sb_hasString = FALSE;
102 p->colorScheme = NULL;
103 p->colorSchemeChanged = 0;
104 p->pin_statusbar = 1;
105 p->pin_menubar = 0;
106 p->want_menubar = 1;
107 p->want_statusbar = 1;
108 p->keyvals = NULL;
109 p->showConsoleText = 0; //in the UI, if a callback is registered with ConsoleMessage. Won't affect old fashioned console,
110 p->target_frames_per_second = 120; //is 120 FPS a good target FPS?
111 p->density_factor = 1.0f; //how much to scale up UI elements for small high res screens ie mobile, see fwl_setDensityFactor
112 p->pedal = 0; //pedal mode moves in-scene cursor by drag amount ie indirect/offset drag
113 p->hover = 0; //hover mode means your drags only do isOver -no navigation or sensor click
114 p->jsengine = JSENGINE_STUB;
115#ifdef JAVASCRIPT_DUK
116 p->jsengine = JSENGINE_DUK;
117#endif
118#ifdef JAVASCRIPT_SM
119 p->jsengine = JSENGINE_SM;
120 p->jsengine_variant = 2; //1= pre-2018 SM1 2= 2018+ SM2
121#ifdef JAVASCRIPT_ENGINE_VARIANT
122 p->jsengine_variant = JAVASCRIPT_ENGINE_VARIANT; //1= pre-2018 SM1 2= 2018+ SM2
123#endif
124 p->draw_bounding_boxes = FALSE;
125#endif
126 }
127}
128void common_clear(struct tcommon *t){
129 //public
130 //private
131 {
132 ppcommon p = (ppcommon)t->prv;
133 if(p->keyvals){
134 int i;
135 for(i=0;i<vectorSize(p->keyvals);i++){
136 keyval k_v = vector_get(keyval,p->keyvals,i);
137 FREE_IF_NZ(k_v.key);
138 FREE_IF_NZ(k_v.val);
139 }
140 deleteVector(keyval,p->keyvals);
141 }
142 }
143}
144
145//ppcommon p = (ppcommon)gglobal()->common.prv;
146
147void fwl_setTrap(int k){
148 ppcommon p = (ppcommon)gglobal()->common.prv;
149 p->itrap = k;
150}
151int fwl_getTrap(){
152 ppcommon p = (ppcommon)gglobal()->common.prv;
153 return p->itrap;
154}
155
156void fwl_setJsEngine(char *optarg){
157 //this has to be set during startup, can't reset during the run.
158 int engine, engine_variant, ivalid;
159 ppcommon p = (ppcommon)gglobal()->common.prv;
160 engine = -1;
161 engine_variant = -1;
162 ivalid = FALSE;
163
164 if(strlen(optarg) >= 2 && (!strncmp(optarg,"SM",2) || !strncmp(optarg,"sm",2))){
165 ivalid = TRUE;
166 #ifdef JAVASCRIPT_SM
167 engine = JSENGINE_SM;
168 if(strlen(optarg) >= 3){
169 if(optarg[2] == '2') engine_variant = 2;
170 if(optarg[2] == '1') engine_variant = 1;
171 }
172 #else
173 ConsoleMessage("not built with spidermonkey js engine\n");
174 #endif
175 }
176 if(!strcmp(optarg,"DUK") || !strcmp(optarg,"duk")){
177 ivalid = TRUE;
178 #ifdef JAVASCRIPT_DUK
179 engine = JSENGINE_DUK;
180 #else
181 ConsoleMessage("not built with duktape js engine\n");
182 #endif
183 }
184 if(!strcmp(optarg,"NONE") || !strcmp(optarg,"none")){
185 ivalid = TRUE;
186 engine = JSENGINE_STUB;
187 }
188 if(engine == -1){
189 static char *engine_names [] = {"NONE","DUK","SM"};
190 ConsoleMessage("could not do js preference %s, trying %s\n",optarg,engine_names[p->jsengine]);
191 }
192 if(!ivalid){
193 ConsoleMessage("invalid --javascript / -J otpion, should be SM, DUK or NONE\n");
194 }
195 if(ivalid && engine > -1){
196 p->jsengine = engine; //should be JSENGINE_SM 1 or JSENGINE_DUK 2 or 0 for stubs)
197 if(engine_variant > -1) p->jsengine_variant = engine_variant;
198 }
199}
200int getJsEngine(){
201 ppcommon p = (ppcommon)gglobal()->common.prv;
202 return p->jsengine;
203}
204int getJsEngineVariant(){
205 ppcommon p = (ppcommon)gglobal()->common.prv;
206 return p->jsengine_variant;
207}
208/* Status update functions (generic = all platform) */
209void setFpsBar();
210void setMenuFps(float fps)
211{
212 ppcommon p = (ppcommon)gglobal()->common.prv;
213
214 p->myFps = fps;
215 setFpsBar();
216}
217/* make sure that on a re-load that we re-init */
218void kill_status(void) {
219 /* hopefully, by this time, rendering has been stopped */
220 ppcommon p = (ppcommon)gglobal()->common.prv;
221
222 p->sb_hasString = FALSE;
223 p->buffer[0] = '\0';
224}
225
226void showConsoleText(int on){
227 ppcommon p = (ppcommon)gglobal()->common.prv;
228 p->showConsoleText = on;
229}
230int getShowConsoleText(){
231 ppcommon p = (ppcommon)gglobal()->common.prv;
232 return p->showConsoleText;
233}
234/* trigger a update */
235void update_status(char* msg) {
236 ppcommon p = (ppcommon)gglobal()->common.prv;
237
238 if (msg == NULL){
239 p->sb_hasString = FALSE;
240 p->buffer[0] = '\0';
241 }
242 else {
243 p->sb_hasString = TRUE;
244 strcpy(p->buffer, msg);
245 }
246}
247char *get_status(){
248 ppcommon p = (ppcommon)gglobal()->common.prv;
249 return p->buffer;
250}
251void setMenuStatus3(char* status3)
252{
253 char *pp;
254 ppcommon p = (ppcommon)gglobal()->common.prv;
255
256 pp = status3;
257 if (!pp) pp = "";
258 snprintf(p->myMenuStatus, MAXSTAT-1, "%s", pp);
259}
260void setMenuStatus(char *stattext)
261{
262 setMenuStatus3(stattext);
263}
264void setMenuStatusVP(char *stattext)
265{
266 setMenuStatus3(stattext);
267}
268char *getMenuStatus()
269{
270 return ((ppcommon)gglobal()->common.prv)->myMenuStatus;
271}
272//#if !defined (_ANDROID)
273
274
275void setWindowTitle0()
276{
277 ppcommon p = (ppcommon)gglobal()->common.prv;
278
279 snprintf(p->window_title, sizeof(p->window_title), "FreeWRL");
280 //setWindowTitle(); //dug9 Mar2014: it will be up to your UI/View to poll for getWindowTitle and set any windowing title in your UI.
281}
282char *getWindowTitle()
283{
284 ppcommon p = (ppcommon)gglobal()->common.prv;
285 return p->window_title;
286}
287//#endif //ANDROID
288
289void setMessageBar()
290{
291 ppcommon p = (ppcommon)gglobal()->common.prv;
292
293 snprintf(p->messagebar, MAXSTAT-1, "%s", p->myMenuStatus);
294}
295char *getMessageBar()
296{
297 ppcommon p = (ppcommon)gglobal()->common.prv;
298 return p->messagebar;
299}
300double get_viewer_dist();
301char *getDistBar(){
302 ppcommon p = (ppcommon)gglobal()->common.prv;
303 snprintf(p->distbar, 10, "D%8f", (float)get_viewer_dist()); //DIST %4f
304
305 return p->distbar;
306}
307
308char *getFpsBar(){
309 ppcommon p = (ppcommon)gglobal()->common.prv;
310 return p->fpsbar;
311}
312void setFpsBar(){
313 ppcommon p = (ppcommon)gglobal()->common.prv;
314 //snprintf(p->fpsbar, 10, "%7.2f", p->myFps);
315 snprintf(p->fpsbar, 10, "%4d", (int)(p->myFps + .49999f));
316}
317static int frontend_using_cursor = 0;
318void fwl_set_frontend_using_cursor(int on)
319{
320 //used by statusbarHud to shut off cursor settings coming from sensitive nodes
321 //while the mouse is over the statusbar or menu buttons.
322 frontend_using_cursor = on;
323}
324
325void setArrowCursor()
326{
327 ppcommon p = (ppcommon)gglobal()->common.prv;
328 p->cursorStyle = ACURSE;
329}
330void setLookatCursor()
331{
332 ppcommon p = (ppcommon)gglobal()->common.prv;
333 p->cursorStyle = SCURSE; // need a special cursor just for lookat
334}
335
336void setSensorCursor()
337{
338 ppcommon p = (ppcommon)gglobal()->common.prv;
339 p->cursorStyle = SCURSE;
340}
341
342int getCursorStyle()
343{
344 ppcommon p = (ppcommon)gglobal()->common.prv;
345 if (!frontend_using_cursor)
346 return p->cursorStyle;
347 else
348 return ACURSE;
349}
350
351int fwl_set_sbh_pin_option(char *optarg){
352 if(optarg && strlen(optarg) > 1){
353 ppcommon p = (ppcommon)gglobal()->common.prv;
354 p->pin_statusbar = (optarg[0] == 'T' || optarg[0] == 't') ? 1 : 0;
355 p->pin_menubar = (optarg[1] == 'T' || optarg[1] == 't') ? 1 : 0;
356 }
357 return 1;
358}
359int fwl_set_sbh_want_option(char *optarg){
360 if(optarg && strlen(optarg) > 1){
361 ppcommon p = (ppcommon)gglobal()->common.prv;
362 p->want_statusbar = (optarg[0] == 'T' || optarg[0] == 't') ? 1 : 0;
363 p->want_menubar = (optarg[1] == 'T' || optarg[1] == 't') ? 1 : 0;
364 }
365 return 1;
366}
367
368void fwl_set_sbh_pin(int sb, int mb){
369 ppcommon p = (ppcommon)gglobal()->common.prv;
370 p->pin_statusbar = sb;
371 p->pin_menubar = mb;
372}
373void fwl_get_sbh_pin(int *sb, int *mb){
374 ppcommon p = (ppcommon)gglobal()->common.prv;
375 *sb = p->pin_statusbar;
376 *mb = p->pin_menubar;
377}
378void fwl_set_sbh_wantMenubar(int want){
379 ppcommon p = (ppcommon)gglobal()->common.prv;
380 p->want_menubar = want ? 1 : 0;
381}
382int fwl_get_sbh_wantMenubar(){
383 ppcommon p = (ppcommon)gglobal()->common.prv;
384 return p->want_menubar;
385}
386void fwl_set_sbh_wantStatusbar(int want){
387 ppcommon p = (ppcommon)gglobal()->common.prv;
388 p->want_statusbar = want ? 1 : 0;
389}
390int fwl_get_sbh_wantStatusbar(){
391 ppcommon p = (ppcommon)gglobal()->common.prv;
392 return p->want_statusbar;
393}
394
395void fwl_set_target_fps(int target_fps){
396 ppcommon p = (ppcommon)gglobal()->common.prv;
397 p->target_frames_per_second = max(1,target_fps);
398}
399int fwl_get_target_fps(){
400 ppcommon p = (ppcommon)gglobal()->common.prv;
401 return p->target_frames_per_second;
402}
403// start ui color scheme >>>>>>>>>>>
404
405// StatusbarHud color schemes:
406
407typedef struct colorScheme {
408 char *name;
409 char *panel;
410 char *menuIcon;
411 char *statusText;
412 char *messageText;
414static colorScheme colorSchemes [] = {
415{
416"original",
417"#EBE8D7", //{.922f,.91f,.844f,1.0f}; 235 232 215 //offwhite
418"#5E5EE6", //{0.37f,0.37f,0.9f,1.0f}; 94 94 230//medium blue
419"#333333", //{.2f, .2f, .2f, 1.0f}; 51 //very dark grey
420"#FFFFFF", //{1.0f, 1.0f, 1.0f, 1.0f}; 255 //white
421},
422{
423"midnight",
424"#000000",
425"#FFFFFF",
426"#FFFFFF",
427"#FFFFFF",
428},
429{
430"angry",
431"#003333", //= {0.0f,0.2f,0.2f,1.0f}; //slightly blue-green black
432"#FF0000", // {1.0f, 0.0f, 0.0f, 1.0f}; //red
433"#FF0000", //{1.0f, 0.0f, 0.0f, 1.0f}; //red
434"#FF0000", // {1.0f, 0.0f, 0.0f, 1.0f}; //red
435},
436{
437"favicon",
438"#004073", // {0.0f,0.25f,0.45f,1.0f}; 0 64 115//indigo
439"#91CCF0", // {.57f, 0.8f, 0.94f, 1.0f}; 145 204 240//light aqua
440"#FF7800", // {1.0f, 0.47f, 0.0f, 1.0f}; 255 120 0//orange
441"#FF7800", // {1.0f, 0.47f, 0.0f, 1.0f}; 255 120 0//orange
442},
443{
444"aqua",
445"#BFD4BD", // {0.75f,0.83f,0.74f,1.0f}; 191 212 189//clamshell
446"#007085", //{.0f, 0.44f, 0.52f, 1.0f}; 0 112 133//dark aqua/indigo
447"#52736E", // {.32f, 0.45f, 0.43f, 1.0f}; 82 115 110//dark clamshell
448"#0FB0CC", // {.06f, 0.69f, 0.8f, 1.0f}; 15 176 204//aqua
449},
450{
451"neon:lime",
452"#3D4557", //= {0.24f,0.27f,0.34f,1.0f}; 61 69 87//steely grey
453"#CCFF00", //LIME {.8f,1.0f,0.0f,1.0f} 204 255 0
454"#CCFF00", //LIME {.8f,1.0f,0.0f,1.0f} 204 255 0
455"#CCFF00", //LIME {.8f,1.0f,0.0f,1.0f} 204 255 0
456},
457{
458"neon:yellow",
459"#3D4557", //= {0.24f,0.27f,0.34f,1.0f}; 61 69 87//steely grey
460"#FFFF33", //YELLOW {1.0f,1.0f,.2f,1.0f} 255 255 51
461"#FFFF33", //YELLOW {1.0f,1.0f,.2f,1.0f} 255 255 51
462"#FFFF33", //YELLOW {1.0f,1.0f,.2f,1.0f} 255 255 51
463},
464{
465"neon:cyan",
466"#3D4557", //= {0.24f,0.27f,0.34f,1.0f}; 61 69 87//steely grey
467"#00FFFF", //CYAN {0.0f,1.0f,1.0f,1.0f} 0 255 255
468"#00FFFF", //CYAN {0.0f,1.0f,1.0f,1.0f} 0 255 255
469"#00FFFF", //CYAN {0.0f,1.0f,1.0f,1.0f} 0 255 255
470},
471{
472"neon:pink",
473"#3D4557", //= {0.24f,0.27f,0.34f,1.0f}; 61 69 87//steely grey
474"#FF78FF", //PINK {1.0f,.47f,1.0f,1.0f} 255 120 255
475"#FF78FF", //PINK {1.0f,.47f,1.0f,1.0f} 255 120 255
476"#FF78FF", //PINK {1.0f,.47f,1.0f,1.0f} 255 120 255
477},
478{
479"custom",
480NULL,
481NULL,
482NULL,
483NULL,
484},
485{NULL,NULL,NULL,NULL},
486};
487
488void color_html2rgb(char *html, float *rgb){
489 //converts one html color in "#FFFFFF" or "FFFFFF" format
490 //int float[3] rgb colors in range 0.0f-1.0f suitable for use in opengl
491 int ir, ig, ib;
492 long ic;
493 char *shex;
494 shex = html;
495 if(shex[0] == '#') shex = &shex[1];
496 ic = strtol(shex,NULL,16);
497 ib = (ic & 0xFF);
498 ig = (ic & 0xFF00) >> 8;
499 ir = (ic & 0xFF0000) >> 16;
500 rgb[0] = (float)ir/255.0f;
501 rgb[1] = (float)ig/255.0f;
502 rgb[2] = (float)ib/255.0f;
503}
504char *hexpermitted = " #0123456789ABCDEFabcdef";
505
506// OLD_IPHONE_AQUA #ifdef AQUA
507// OLD_IPHONE_AQUA #include <malloc/malloc.h>
508// OLD_IPHONE_AQUA #else
509
510#include <malloc.h>
511
512// OLD_IPHONE_AQUA #endif
513
514#include <string.h>
515int colorsoption2colorscheme(const char *optionstring, colorScheme *cs){
516 //converts html colors given for freewrl command line option:
517 // --ui_colors "#FFFFFF,#FFFFFF,#FFFFFF,#FFFFFF" (for panel, menuicon, statusText, messageText)
518 //into 4 float [0-1] rgb colors suitable for use in opengl calls
519 //returns number of successfully parsed numbers
520 int len,i,count;
521 char *str, *html, *stok; //4 colors per color scheme
522 len = strlen(optionstring);
523 str = alloca(len+1); //alloca on stack so its freed automatically at end of function, _msc can't do str[len]
524 strcpy(str,optionstring);
525 //clean string
526 for(i=0;i<len;i++){
527 if(!strchr(hexpermitted,str[i])){
528 str[i] = ' ';
529 }
530 }
531 //find color substrings ie strtok
532 count = 0;
533 stok = str;
534 for(i=0;i<4;i++){
535 html = strtok(stok," ");
536 if(!html) {
537 if(cs->menuIcon) html = cs->menuIcon;
538 else html = "#FFFFFF";
539 }
540 switch(i){
541 case 0: cs->panel = strdup(html); break;
542 case 1: cs->menuIcon = strdup(html); break;
543 case 2: cs->statusText = strdup(html); break;
544 case 3: cs->messageText = strdup(html); break;
545 default:
546 break;
547 }
548 count++;
549 stok = NULL;
550 }
551 return count;
552}
553
554colorScheme *search_ui_colorscheme(char *colorschemename){
555 int i;
556 colorScheme *cs = NULL;
557 i = 0;
558 do{
559 if(!strcmp(colorSchemes[i].name,colorschemename)){
560 cs = &colorSchemes[i];
561 break;
562 }
563 i++;
564 }while(colorSchemes[i].name);
565 return cs;
566}
567int fwl_set_ui_colorscheme(char *colorschemename){
568 colorScheme *cs;
569 ppcommon p = (ppcommon)gglobal()->common.prv;
570 cs = search_ui_colorscheme(colorschemename);
571 if(cs) {
572 p->colorScheme = cs;
573 p->colorSchemeChanged++;
574 }
575 return 1;
576}
577// set here from commandline options
578// --ui_colorscheme "angry"
579// --ui_colors "#FFFFFF,#FFFFFF,#FFFFFF,#FFFFFF" panel, menuIcon, statusText, messsageText
580
581void fwl_set_ui_colors(char *fourhtmlcolors){
582 colorScheme *cs;
583 ppcommon p = (ppcommon)gglobal()->common.prv;
584 cs = search_ui_colorscheme("custom");
585 colorsoption2colorscheme(fourhtmlcolors, cs);
586 p->colorScheme = (void *)cs;
587 p->colorSchemeChanged++;
588}
589char *fwl_get_ui_colorschemename(){
590 colorScheme *cs;
591 ppcommon p = (ppcommon)gglobal()->common.prv;
592 cs = (colorScheme*)p->colorScheme;
593 return cs->name;
594}
595void fwl_next_ui_colorscheme(){
596 int i;
597 colorScheme *cs;
598 char *colorschemename;
599 //ppcommon p = (ppcommon)gglobal()->common.prv;
600
601 colorschemename = fwl_get_ui_colorschemename();
602 i = 0;
603 do{
604 if(!strcmp(colorSchemes[i].name,colorschemename)){
605 cs = &colorSchemes[i+1];
606 if(!cs->name){
607 cs = &colorSchemes[0]; //start over
608 }
609 if(!strcmp(cs->name,"custom")){
610 cs = &colorSchemes[0]; //skip custom and start over
611 }
612 fwl_set_ui_colorscheme(cs->name);
613 break;
614 }
615 i++;
616 }while(colorSchemes[i].name);
617
618}
619
620//want to compile-in the default color scheme? just define UI_COLORSCHEME_DEFAULT in your config.h
621#ifndef UI_COLORSCHEME_DEFAULT
622#define UI_COLORSCHEME_DEFAULT "neon:lime" //"original" "favicon" "midnight" "aqua" "angry" "neon:cyan" "neon:yellow" "neon:lime" "neon:pink"
623#endif
624void fwl_get_ui_color(char *use, float *rgb){
625 colorScheme *cs;
626 ppcommon p = (ppcommon)gglobal()->common.prv;
627 if(!p->colorScheme){
628 p->colorScheme = search_ui_colorscheme(UI_COLORSCHEME_DEFAULT); //"original");
629 p->colorSchemeChanged++;
630 }
631 cs = p->colorScheme;
632 if(!strcmp(use,"panel")){
633 color_html2rgb(cs->panel, rgb);
634 }else if(!strcmp(use,"menuIcon")){
635 color_html2rgb(cs->menuIcon, rgb);
636 }else if(!strcmp(use,"statusText")){
637 color_html2rgb(cs->statusText, rgb);
638 }else if(!strcmp(use,"messageText")){
639 color_html2rgb(cs->messageText, rgb);
640 }
641}
642int fwl_get_ui_color_changed(){
643 ppcommon p = (ppcommon)gglobal()->common.prv;
644 return p->colorSchemeChanged;
645}
646// end ui colors <<<<<<<<<<<<<<<
647
648
649// fwl_command() >>>>>>>>>>
650/* generally: I'm tired of writing fwl_setThisOrThat() functions. I want a simpler interface.
651 one idea is to have a set_keyval(key,val) function and a set_command(key) function.
652 another idea is to have a set_commandline(commandline) function and it would split
653 on a separator like ',' or ' ' and decide if it has a parameter or not.
654 Now from your front end you can call:
655 fwl_commandline("pin,FF");
656 Or if calling through the dllfreewrl api wrapper:
657 dllFreeWRL_commandline(fwctx,"pin,FF");
658
659 PS. A benefit of storing View settings/preferences like colorscheme and pinning
660 in the Model part of MVC is that several Views can be setting and/or polling
661 the settings on each frame.
662 For example commandline options can set, then javascript Browser.keyvalue can set or get,
663 then statusbarHud can poll or set, then Motif or .net Gui can poll or set. And they have
664 a common place to set, and poll. If there's no statusbarHud, and no GUI, nothing
665 breaks: commandline options still has a place to put the values. Even though they
666 aren't used in the backend/Model.
667*/
668#include <scenegraph/Viewer.h>
669
670int fwl_setDragChord(char *chordname);
671int fwl_setKeyChord(char *chordname);
672int print_help();
673int fwl_keyval(char *key, char *val);
674
675int searchkeyvals(char *key){
676 int i, iret;
677 ppcommon p = (ppcommon)gglobal()->common.prv;
678 if(!p->keyvals)
679 p->keyvals = newVector(keyval,4);
680 iret = -1;
681 for(i=0;i<vectorSize(p->keyvals);i++){
682 keyval k_v = vector_get(keyval,p->keyvals,i);
683 if(!strcmp(k_v.key,key)){
684 iret = i;
685 break;
686 }
687 }
688 return iret;
689}
690int set_key_val(char *key, char *val){
691 int index;
692 keyval k_v;
693 ppcommon p = (ppcommon)gglobal()->common.prv;
694
695 index = searchkeyvals(key);
696 if(index < 0){
697 if(!p->keyvals)
698 p->keyvals = newVector(keyval,4);
699 k_v.key = STRDUP(key);
700 k_v.val = STRDUP(val);
701 vector_pushBack(keyval,p->keyvals,k_v);
702 }else{
703 k_v = vector_get(keyval,p->keyvals,index);
704 FREE_IF_NZ(k_v.val);
705 k_v.val = STRDUP(val);
706 vector_set(keyval,p->keyvals,index,k_v);
707 }
708 return 1;
709}
710int set_keyval(char *keyval){
711 //save arbitrary char* keyval = "key,val" pairs,
712 // for later retrieval with print_keyval or get_key_val
713 int i, iret;
714 char kv[100];
715 ppcommon p = (ppcommon)gglobal()->common.prv;
716 if(!p->keyvals)
717 p->keyvals = newVector(keyval,4);
718 i = strlen(keyval);
719 iret = 0;
720 if(i > 100)
721 iret = -1;
722 else
723 {
724 char *sep;
725 strcpy(kv,keyval);
726 sep = strchr(kv,' ');
727 if(!sep) sep = strchr(kv,',');
728 if(sep){
729 char *key, *val;
730 val = &sep[1];
731 (*sep) = '\0';
732 key = kv;
733 set_key_val(key,val);
734 iret = 1;
735 }
736 }
737 return iret;
738}
739char *get_key_val(char *key){
740 int index;
741 keyval k_v;
742 ppcommon p = (ppcommon)gglobal()->common.prv;
743
744 index = searchkeyvals(key);
745 if(index < 0) return NULL;
746 k_v = vector_get(keyval,p->keyvals,index);
747 return k_v.val; //warning not strduped here, caller doesn't own, just looking
748}
749int print_keyval(char *key){
750 int index;
751 ppcommon p = (ppcommon)gglobal()->common.prv;
752 index = searchkeyvals(key);
753 if(index < 0)
754 ConsoleMessage("\n key %s not found\n",key);
755 else{
756 keyval k_v;
757 k_v = vector_get(keyval,p->keyvals,index);
758 ConsoleMessage("\n key=%s val=%s\n",key,k_v.val);
759 }
760 return 1;
761}
762int fwl_hyper_option(char *val);
763int ssr_test(char *keyval);
764struct command {
765 char *key;
766 int (*cmdfunc)();
767 int (*valfunc)(char *val);
768 char *helpstring;
769} commands [] = {
770 {"dragchord",NULL,fwl_setDragChord,"[yawz,yawpitch,roll,xy]"},
771 {"keychord", NULL,fwl_setKeyChord,"[yawz,yawpitch,roll,xy]"},
772 {"navmode",NULL,fwl_setNavMode,"[walk,fly,examine,explore,spherical,turntable,lookat]"},
773 {"help",print_help,NULL,NULL},
774 {"pin",NULL,fwl_set_sbh_pin_option,"[tf,tt,ft,ff]"},
775 {"colorscheme",NULL,fwl_set_ui_colorscheme,"[original,midnight,angry,favicon,aqua,neon:lime,neon:yellow,neon:cyan,neon:pink]"},
776 {"set_keyval",NULL,set_keyval,"key,val"},
777 {"print_keyval",NULL,print_keyval,"key"},
778 {"hyper_option",NULL,fwl_hyper_option,"[0 - 10]"},
779#ifdef SSR_SERVER
780 {"ssrtest",NULL,ssr_test,"nav,val"},
781#endif
782 {"",print_help,NULL,NULL}, //bootstrap user knowhow by spacebarEnter lucky sequence
783 {NULL,NULL,NULL},
784};
785int print_help(){
786 int i, ret = 1;
787 ConsoleMessage("\n%s\n","spacebar commands: spacebar:key[,val]Enter");
788 i = 0;
789 while(commands[i].key){
790 if(commands[i].helpstring)
791 ConsoleMessage(" %s,%s\n",commands[i].key,commands[i].helpstring);
792 else
793 ConsoleMessage(" %s\n",commands[i].key);
794 i++;
795 }
796 return ret;
797}
798struct command *getCommand(char *key){
799 struct command *ret;
800 int i;
801 i = 0;
802 ret = NULL;
803 while(commands[i].key){
804 if(!strcmp(key,commands[i].key)){
805 ret = &commands[i];
806 break;
807 }
808 i++;
809 }
810 return ret;
811}
812int fwl_keyval(char *key, char *val){
813 struct command *cmd;
814 int ok = 0;
815 cmd = getCommand(key);
816 if(cmd){
817 if(cmd->valfunc)
818 ok = cmd->valfunc(val);
819 }
820 return ok;
821}
822int fwl_command(char *key){
823 struct command *cmd;
824 int ok = 0;
825 cmd = getCommand(key);
826 if(cmd){
827 if(cmd->cmdfunc)
828 ok = cmd->cmdfunc();
829 }
830 return ok;
831}
832int fwl_commandline(char *cmdline){
833 char *sep = strchr(cmdline,' ');
834 if(!sep) sep = strchr(cmdline,',');
835 if(sep){
836 int keylen;
837 char *key, *val;
838 val = strdup(&sep[1]);
839 keylen = (int)(sep - cmdline);
840 //(*sep) = '\0';
841 key = strndup(cmdline,keylen +1);
842 key[keylen] = '\0';
843 //printf("key=[%s] val=[%s]\n",key,val);
844 fwl_keyval(key,val);
845 free(key);
846 free(val);
847 }else{
848 //not key,val, just command
849 fwl_command(cmdline);
850 }
851 return 1;
852}
853
854// fwl_command() <<<<<<<<<<
855
856void fwl_setDensityFactor(float density_factor){
857 // mobile device APIs sometimes can give you a hint
858 // you can use to scale UI elements to human size
859 // for example a human finger tip has a constant size in the physical world
860 // as screen resolutions DPI have increased, its been necessary to scale buttons
861 // up by some factor depending on the DPI relative to good old fashioned 160 DPI
862 ppcommon p = (ppcommon)gglobal()->common.prv;
863 p->density_factor = density_factor;
864}
865float fwl_getDensityFactor(){
866 ppcommon p = (ppcommon)gglobal()->common.prv;
867 return p->density_factor;
868}
869int fwl_getPedal(){
870 ppcommon p = (ppcommon)gglobal()->common.prv;
871 return p->pedal;
872}
873void fwl_setPedal(int pedal){
874 ppcommon p = (ppcommon)gglobal()->common.prv;
875 p->pedal = pedal; //0 means off, 1 means on
876}
877int fwl_getHover(){
878 ppcommon p = (ppcommon)gglobal()->common.prv;
879 return p->hover;
880}
881void fwl_setHover(int hover){
882 ppcommon p = (ppcommon)gglobal()->common.prv;
883 p->hover = hover; //0 means off, 1 means on
884}
885void fwl_setDrawBoundingBoxes(int drawbb){
886 ppcommon p = (ppcommon)gglobal()->common.prv;
887 p->draw_bounding_boxes = drawbb; //0 means off, 1 means on
888}
889int fwl_getDrawBoundingBoxes(){
890 ppcommon p = (ppcommon)gglobal()->common.prv;
891 return p->draw_bounding_boxes; //0 means off, 1 means on
892}
Definition Viewer.h:139