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