Rebuilt mmenu 'category' internals so its much more pleasant to work with (internally)
[pandora-libraries.git] / minimenu / mmconf.c
1
2 #include <stdio.h>
3 #include <limits.h> /* for PATH_MAX */
4 #define __USE_GNU /* for strndup */
5 #include <string.h> /* for strdup */
6
7 #include "SDL.h"
8 #include "SDL_image.h"
9 #include "SDL_ttf.h"
10
11 #include "pnd_container.h"
12 #include "pnd_conf.h"
13 #include "pnd_discovery.h"
14
15 #include "mmenu.h"
16 #include "mmconf.h"
17 #include "mmcat.h"
18 #include "mmui.h"
19 #include "mmwrapcmd.h"
20
21 static unsigned char conf_render_text ( TTF_Font *f, char *buffer, SDL_Rect *dest, unsigned int x, unsigned int y, unsigned char selected );
22 static unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y );
23 static char *conf_format_int ( int v, change_type_e c );
24
25 confitem_t page_general[] = {
26   { "Default tab to show",           "On startup, Minimenu will try to switch to this tab",     NULL /* default */, "categories.default_cat",  ct_visible_tab_list },
27 #if 0 // and also in mmenu.c -- something crashes during image caching
28   { "Set CPU speed within Minimenu", "Whether the next setting is applied or not",              "0",                "minimenu.use_mm_speed",   ct_boolean },
29   { "CPU speed within Minimenu",     "Set low; speed to run Minimenu at",                       "400",              "minimenu.mm_speed",       ct_cpu_speed },
30 #endif
31   { "Set CPU speed when leaving",    "Whether the next setting is applied or not",              "0",                "minimenu.use_run_speed",  ct_boolean },
32   { "CPU speed when leaving",        "Before running app, set this speed; app may override.",   "500",              "minimenu.run_speed",      ct_cpu_speed },
33   { "Show 'All' tab",                "Whethor an All tab is shown or not",                      "1",                "categories.do_all_cat",   ct_boolean },
34   { "Show directory browser tabs",   "Show a tab for each SD card?",                            "0",                "filesystem.do_browser",   ct_boolean },
35   { "Detail panel on start?",        "Show or hide the detail panel when menu starts",          "1",                "display.show_detail_pane", ct_boolean },
36   { "Start with app selected",       "Whethor selection is placed by default or not",           "0",                "minimenu.start_selected", ct_boolean },
37   { "Sub-categories as folders?",    "If no, uses tabs instead of folders within tabs.",        "1",                "tabs.subcat_as_folders",  ct_boolean },
38   { "Wrap tab change",               "Changing tab left or right, does it wrap around?",        "0",                "tabs.wraparound",         ct_boolean },
39   { "Grid stop vertical",            "Changing selection up or down, does it stop or wrap?",    "0",                "grid.wrap_vert_stop",     ct_boolean },
40   { "Live (not exit) on app run?",   "Normally menu exits (to save ram) on app run",            "0",                "minimenu.live_on_run",    ct_boolean },
41   { "Force wallpaper with..",        "You can force an override over themes background",        "/pandora/appdata/mmenu/wallpaper.png", "minimenu.force_wallpaper",  ct_filename },
42   { "",                              "",                                                        NULL,               NULL,                      ct_nil },
43   { "^- Back up to main",            "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
44   { NULL }
45 };
46
47 confitem_t page_appshowhide [ CONF_MAX_LISTLENGTH ] = {
48   { "^- Back up to main",        "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
49   { CONF_APPLIST_TAG,            "Show or hide this application",                           "1",                "appshow",                 ct_nil },
50   { NULL }
51 };
52
53 confitem_t page_tabshowhide [ CONF_MAX_LISTLENGTH ] = {
54   { "^- Back up to main",        "Go back to top level of configuration",                   NULL,               NULL,                      ct_switch_page, NULL },
55   { CONF_TABLIST_TAG,            "Show or hide or reorder this tab",                        "1",                "tabshow",                 ct_nil },
56   { NULL }
57 };
58
59 confitem_t pages[] = {
60   { "General Options",           "Miscellaneous handy options",                             NULL /* default */, NULL,                      ct_switch_page, page_general },
61   { "Show/Hide Applications",    "Each application can be hidden/revealed",                 NULL /* default */, NULL,                      ct_switch_page, page_appshowhide },
62   { "Show/Hide/Order Tabs",      "Each tab can be hidden/revealed or re-ordered",           NULL /* default */, NULL,                      ct_switch_page, page_tabshowhide },
63   { "",                          "",                                                        NULL,               NULL,                      ct_nil },
64   { "Exit configuration",        "Quit and save configuration",                             NULL /* default */, NULL,                      ct_exit },
65   { "",                          "",                                                        NULL,               NULL,                      ct_nil },
66   { "Reset to defaults",         "Remove any custom options set in this UI",                NULL /* default */, NULL,                      ct_reset },
67   { NULL }
68 };
69
70 extern pnd_conf_handle g_conf;
71 extern SDL_Surface *sdl_realscreen;
72 extern mm_imgcache_t g_imagecache [ IMG_TRUEMAX ];
73 extern pnd_box_handle g_active_apps;
74
75 unsigned char conf_run_menu ( confitem_t *toplevel ) {
76   confitem_t *page = toplevel;
77   unsigned int sel = 0;
78   unsigned int first_visible = 0;
79   unsigned char max_visible = 12;
80   SDL_Event event;
81   confitem_t *lastpage = NULL;
82
83   while ( 1 ) {
84
85     if ( ! page ) {
86       page = pages;
87       sel = 0;
88       first_visible = 0;
89     }
90
91     if ( lastpage != page ) {
92       conf_prepare_page ( page );
93       lastpage = page;
94     }
95
96     conf_display_page ( page, sel, first_visible, max_visible );
97
98     // check for input
99     while ( SDL_WaitEvent ( &event ) ) {
100
101       switch ( event.type ) {
102
103       //case SDL_KEYUP:
104       case SDL_KEYDOWN:
105
106         if ( event.key.keysym.sym == SDLK_UP ) {
107
108           do {
109
110             if ( sel ) {
111               sel--;
112
113               if ( sel < first_visible ) {
114                 first_visible--;
115               }
116
117             }
118
119           } while ( page [ sel ].type == ct_nil );
120
121         } else if ( event.key.keysym.sym == SDLK_DOWN ) {
122
123           do {
124
125             if ( page [ sel + 1 ].text ) {
126               sel++;
127
128               // ensure visibility
129               if ( sel >= first_visible + max_visible ) {
130                 first_visible++;
131               }
132
133             }
134
135           } while ( page [ sel ].type == ct_nil );
136
137         } else if ( event.key.keysym.sym == SDLK_PAGEUP ) {
138           page = NULL;
139
140         } else if ( event.key.keysym.sym == SDLK_LEFT || event.key.keysym.sym == SDLK_RIGHT ) {
141
142           unsigned char left = 0;
143           if ( event.key.keysym.sym == SDLK_LEFT ) {
144             left = 1;
145           }
146
147           switch ( page [ sel ].type ) {
148
149           case ct_cpu_speed:
150             {
151               int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
152               if ( v == PND_CONF_BADNUM ) {
153                 v = 500;
154               }
155
156               if ( left ) {
157                 if ( v > 30 ) {
158                   v -= 10;
159                 }
160               } else {
161                 v += 10;
162               }
163
164               char buffer [ 20 ];
165               sprintf ( buffer, "%u", v );
166               pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
167
168             }
169             break;
170
171           case ct_visible_tab_list:
172             {
173               if ( g_categorycount ) {
174                 char *v = pnd_conf_get_as_char ( g_conf, page [ sel ].key );
175                 if ( v ) {
176                   unsigned char n = 0;
177                   for ( n = 0; n < g_categorycount; n++ ) {
178                     if ( strcmp ( v, g_categories [ n ] -> catname ) == 0 ) {
179                       break;
180                     }
181                   }
182                   if ( n < g_categorycount ) {
183                     if ( left && n ) {
184                       pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n - 1 ] -> catname );
185                     } else if ( ! left && n + 1 < g_categorycount ) {
186                       pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ n + 1 ] -> catname );
187                     }
188                   } else {
189                     pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ] -> catname );
190                   }
191                 } else {
192                   pnd_conf_set_char ( g_conf, page [ sel ].key, g_categories [ 0 ] -> catname );
193                 }
194               } // if category count
195             }
196             break;
197
198           case ct_boolean:
199             {
200               int v = pnd_conf_get_as_int ( g_conf, page [ sel ].key );
201               if ( v == PND_CONF_BADNUM ) {
202                 v = 0;
203               }
204               if ( v ) {
205                 v = 0;
206               } else {
207                 v = 1;
208               }
209
210               char buffer [ 20 ];
211               sprintf ( buffer, "%u", v );
212
213               pnd_conf_set_char ( g_conf, page [ sel ].key, buffer );
214             }
215             break;
216
217           case ct_filename:
218             break;
219
220           case ct_nil:
221           case ct_switch_page:
222           case ct_reset:
223           case ct_exit:
224             break;
225
226           } // switch
227
228         } else if ( event.key.keysym.sym == SDLK_ESCAPE ) {
229           emit_and_quit ( MM_QUIT );
230
231         } else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_END ) { // return, or "B"
232
233           switch ( page [ sel ].type ) {
234           case ct_exit:
235             {
236               return ( 1 /* always cause restart for now */ );
237             }
238             break;
239           case ct_reset:
240             {
241               conf_reset_to_default ( g_conf );
242               page = NULL;
243               sel = 0;
244             }
245             break;
246           case ct_switch_page:
247             page = page [ sel ].newhead;
248             sel = 0; // should use a stack..
249             break;
250           case ct_filename:
251             break;
252           case ct_nil:
253           case ct_visible_tab_list:
254           case ct_cpu_speed:
255           case ct_boolean:
256             break;
257           } // switch
258
259         } else {
260           // nada
261         }
262
263         break; // case sdl_key_up
264
265       } // switch what SDL event
266
267       break; // get out of sdl-wait-event loop
268     } // while events
269
270   } // while forever
271
272   return ( 1 /* always cause restart for now */ );
273 }
274
275 void conf_display_page ( confitem_t *page, unsigned int selitem, unsigned int first_visible, unsigned int max_visible ) {
276   extern TTF_Font *g_big_font;
277   extern TTF_Font *g_tab_font;
278
279 #define MAXRECTS 200
280   SDL_Rect rects [ MAXRECTS ];
281   SDL_Rect *dest = rects;
282   bzero ( dest, sizeof(SDL_Rect)*MAXRECTS );
283
284   unsigned short int tx, ty;
285
286   // background
287   if ( g_imagecache [ IMG_BACKGROUND_800480 ].i ) {
288     dest -> x = 0;
289     dest -> y = 0;
290     dest -> w = sdl_realscreen -> w;
291     dest -> h = sdl_realscreen -> h;
292     SDL_BlitSurface ( g_imagecache [ IMG_BACKGROUND_800480 ].i, NULL /* whole image */, sdl_realscreen, dest /* 0,0 */ );
293     dest++;
294   }
295
296   // title
297   //
298   // <items>
299   // description
300   // default
301   //
302   // controls help
303
304   // title
305   dest += conf_render_text ( g_big_font, "Minimenu Configuration", dest, 10, 10, CONF_UNSELECTED );
306   dest += conf_render_line ( dest, 45 );
307
308   // scrollable hints
309   {
310
311     // up
312     if ( first_visible > 0 ) {
313       dest -> x = 10;
314       dest -> y = 65;
315       SDL_BlitSurface ( g_imagecache [ IMG_ARROW_UP ].i, NULL /* whole image */, sdl_realscreen, dest );
316       dest++;
317     } // scroll arrow up
318
319     // down
320     if ( first_visible + max_visible < conf_determine_pagelength ( page ) ) {
321       dest -> x = 10;
322       dest -> y = 345;
323       SDL_BlitSurface ( g_imagecache [ IMG_ARROW_DOWN ].i, NULL /* whole image */, sdl_realscreen, dest );
324       dest++;
325     } // scroll arrow up
326
327   } // scrollbar
328
329   // items
330   tx = 50; ty = 70;
331   unsigned char counter = first_visible;
332   while ( page [ counter ].text ) {
333
334     // item
335     conf_render_text ( g_tab_font, page [ counter ].text, dest, tx, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
336
337     // value
338     switch ( page [ counter ].type ) {
339     case ct_switch_page:
340       break;
341     case ct_reset:
342       break;
343     case ct_visible_tab_list:
344       {
345         char *v = pnd_conf_get_as_char ( g_conf, page [ counter ].key );
346         if ( v ) {
347           conf_render_text ( g_tab_font, v, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
348         } else {
349           conf_render_text ( g_tab_font, "Not specified", dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
350         }
351       }
352       break;
353     case ct_cpu_speed:
354       {
355         int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
356         conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
357       }
358       break;
359     case ct_boolean:
360       {
361         int v = pnd_conf_get_as_int ( g_conf, page [ counter ].key );
362         conf_render_text ( g_tab_font, conf_format_int ( v, page [ counter ].type ), dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
363       }
364       break;
365     case ct_filename:
366       conf_render_text ( g_tab_font, page [ counter ].def, dest, tx + 400, ty, counter == selitem ? CONF_SELECTED : CONF_UNSELECTED );
367       break;
368     case ct_exit:
369       break;
370     case ct_nil:
371       break;
372     } // switch
373
374     // far enough?
375     if ( counter - first_visible >= max_visible - 1 ) {
376       break;
377     }
378
379     // next line
380     ty += 25;
381     counter++;
382   } // while
383
384   // description and default
385   if ( page [ selitem ].desc ) {
386     dest += conf_render_text ( g_tab_font, page [ selitem ].desc, dest, 380, 400, CONF_UNSELECTED );
387   }
388   if ( page [ selitem ].def ) {
389     char buffer [ 100 ] = "Default: ";
390
391     switch ( page [ selitem ].type ) {
392     case ct_boolean:
393       sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_boolean ) );
394       break;
395     case ct_cpu_speed:
396       sprintf ( buffer + strlen ( buffer ), "%s", conf_format_int ( atoi ( page [ selitem ].def ), ct_cpu_speed ) );
397       break;
398     case ct_filename:
399       sprintf ( buffer + strlen ( buffer ), "%s", page [ selitem ].def );
400       break;
401     case ct_nil:
402     case ct_switch_page:
403     case ct_reset:
404     case ct_exit:
405     case ct_visible_tab_list:
406       break;
407     } // switch
408
409     dest += conf_render_text ( g_tab_font, buffer, dest, 380, 420, CONF_UNSELECTED );
410   } else {
411     dest += conf_render_text ( g_tab_font, "No default value", dest, 380, 420, CONF_UNSELECTED );
412   }
413
414   // cursor's conf item count number - not for top level, just the sublevels
415   if ( page != pages ) {
416     char buffer [ 40 ];
417     sprintf ( buffer, "Config item %d of %d", selitem + 1, conf_determine_pagelength ( page ) );
418     /*dest += */conf_render_text ( g_tab_font, buffer, dest, 380, 440, CONF_UNSELECTED );
419   }
420
421   // help
422   dest += conf_render_line ( dest, 380 );
423   dest += conf_render_text ( g_tab_font, "D-pad Up/down; Y return to index", dest, 10, 400, CONF_UNSELECTED );
424   dest += conf_render_text ( g_tab_font, "Left and right to alter selected item", dest, 10, 420, CONF_UNSELECTED );
425   dest += conf_render_text ( g_tab_font, "B or Enter to activate an option", dest, 10, 440, CONF_UNSELECTED );
426
427   // update all the rects and send it all to sdl
428   // - at this point, we could probably just do 1 rect, of the
429   //   whole screen, and be faster :/
430   SDL_UpdateRects ( sdl_realscreen, dest - rects, rects );
431
432   return;
433 }
434
435 unsigned char conf_render_text ( TTF_Font *f, char *buffer, SDL_Rect *dest, unsigned int x, unsigned int y, unsigned char selected ) {
436   unsigned int font_rgba_r = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_r", 200 );
437   unsigned int font_rgba_g = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_g", 200 );
438   unsigned int font_rgba_b = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_b", 200 );
439   unsigned int font_rgba_a = pnd_conf_get_as_int_d ( g_conf, "display.font_rgba_a", 100 );
440
441   SDL_Color tmpfontcolor = { font_rgba_r, font_rgba_g, font_rgba_b, font_rgba_a };
442   SDL_Color selfontcolor = { 0/*font_rgba_r*/, font_rgba_g, font_rgba_b, font_rgba_a };
443
444   SDL_Surface *rtext = TTF_RenderText_Blended ( f, buffer, selected ? selfontcolor : tmpfontcolor );
445   dest -> x = x;
446   dest -> y = y;
447   SDL_BlitSurface ( rtext, NULL /* all */, sdl_realscreen, dest );
448   SDL_FreeSurface ( rtext );
449
450   return ( 1 );
451 }
452
453 unsigned char conf_render_line ( SDL_Rect *dest, unsigned int y ) {
454
455   dest -> x = 0;
456   dest -> y = y;
457
458   SDL_Surface *i = g_imagecache [ IMG_TAB_LINE ].i;
459
460   while ( dest -> x + i -> w < 800 ) {
461     SDL_BlitSurface ( i, NULL, sdl_realscreen, dest );
462     dest -> x += i -> w;
463   }
464
465   dest -> x = 0;
466   dest -> w = 480 - 10;
467   dest -> h = i -> h;
468
469   return ( 1 );
470 }
471
472 char *conf_format_int ( int v, change_type_e c ) {
473   static char buffer [ 50 ];
474   buffer [ 0 ] = '\0';
475
476   switch ( c ) {
477
478     case ct_cpu_speed:
479       {
480         if ( v == PND_CONF_BADNUM ) {
481           strcpy ( buffer, "Leave Alone" );
482         } else {
483           sprintf ( buffer, "%u", v );
484         }
485       }
486       break;
487
488     case ct_boolean:
489       {
490         if ( v == PND_CONF_BADNUM ) {
491           strcpy ( buffer, "FUBAR" );
492         } else if ( v == 0 ) {
493           strcpy ( buffer, "no" );
494         } else if ( v == 1 ) {
495           strcpy ( buffer, "yes" );
496         } else {
497           strcpy ( buffer, "FUBAR 2" );
498         }
499       }
500       break;
501
502   case ct_filename:
503     break;
504
505   case ct_exit:
506   case ct_reset:
507   case ct_switch_page:
508   case ct_visible_tab_list:
509   case ct_nil:
510     break;
511
512   } // switch
513
514   return ( buffer );
515 }
516
517 unsigned char conf_prepare_page ( confitem_t *page ) {
518   char buffer [ 100 ];
519
520   confitem_t *p = page;
521   confitem_t *template = NULL;
522   while ( p -> text != NULL ) {
523
524     if ( strcmp ( p -> text, CONF_APPLIST_TAG ) == 0 ) {
525       // rewrite this and subsequent items to be the listing
526       template = p;
527       p++;
528
529       template -> text = ""; // so it won't get repopulated again later
530
531       // for each app..
532       pnd_disco_t *iter = pnd_box_get_head ( g_active_apps );
533
534       while ( p - page < CONF_MAX_LISTLENGTH && iter ) {
535
536         p -> text = strndup ( iter -> title_en ? iter -> title_en : "Unnamed", 40 );
537         p -> desc = strdup ( iter -> unique_id );
538         p -> def = NULL;
539
540         sprintf ( buffer, "%s.%s", template -> key, iter -> unique_id );
541         p -> key = strdup ( buffer );
542         p -> type = ct_boolean;
543         p -> newhead = NULL;
544
545         // create to positive if not existant
546         if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
547           pnd_conf_set_char ( g_conf, buffer, "1" );
548         }
549
550         iter = pnd_box_get_next ( iter );
551         p++;
552       } // while not run off end of buffer
553
554       break;
555
556     } else if ( strcmp ( p -> text, CONF_TABLIST_TAG ) == 0 ) {
557       // rewrite this and subsequent items to be the listing
558       template = p;
559       p++;
560
561       template -> text = ""; // so it won't get repopulated again later
562
563       // switch categories being published
564       category_publish ( CFALL, NULL );
565
566       // for each tab
567       unsigned int i;
568       char catname [ 512 ];
569       char *actual_catname;
570
571       for ( i = 0;  i < g_categorycount; i++ ) {
572
573         // if this is an invisi-guy, it has parent-cat prepended; we want the real cat name.
574         strncpy ( catname, g_categories [ i ] -> catname, 500 );
575
576         if ( ( actual_catname = strchr ( catname, '.' ) ) ) {
577           actual_catname++; // skip the period
578         } else {
579           actual_catname = catname;
580         }
581         //fprintf ( stderr, "conf ui; got '%s' but showing '%s'\n", cc [ i ].catname, actual_catname );
582
583         if ( strncmp ( g_categories [ i ] -> catname, "All ", 4 ) == 0 ) {
584           // skip All tab, since it is generated, and managed by another config item
585           continue;
586         }
587
588         p -> text = strndup ( actual_catname, 40 );
589         p -> desc = NULL;
590         p -> def = NULL;
591
592         sprintf ( buffer, "%s.%s", template -> key, actual_catname );
593         p -> key = strdup ( buffer );
594         p -> type = ct_boolean;
595         p -> newhead = NULL;
596
597         // create to positive if not existant
598         if ( ! pnd_conf_get_as_char ( g_conf, buffer ) ) {
599           pnd_conf_set_char ( g_conf, buffer, "1" );
600         }
601
602         //fprintf ( stderr, "Created tabshow entry '%s'\n", cc [ i ].catname );
603
604         p++;
605       } // for
606
607       // switch categories being published
608       category_publish ( CFNORMAL, NULL );
609
610       break;
611     }
612
613     p++;
614   }
615
616   return ( 1 );
617 }
618
619 unsigned char conf_write ( pnd_conf_handle h, char *fullpath ) {
620
621   // cherry pick the named keys from the conf-ui-array
622   // spill out the apps ands tabs 'broups' of conf keys
623
624   FILE *f = fopen ( fullpath, "w" );
625
626   if ( ! f ) {
627     return ( 0 );
628   }
629
630   fprintf ( f, "# Machine written; do not edit.\n" );
631   fprintf ( f, "# If you do edit, its KEY<tab>VALUE<newline>, nothing extra.\n" );
632   fprintf ( f, "\n" );
633
634   // deal with general keys
635   confitem_t *ci = page_general;
636   while ( ci -> text ) {
637     // does this item have a key? a value? if so, try to emit it.
638     if ( ci -> key ) {
639       char *v = pnd_conf_get_as_char ( h, ci -> key );
640       if ( v ) {
641         fprintf ( f, "%s\t%s\n", ci -> key, v );
642       }
643     }
644     ci++;
645   } // while
646
647   // deal with apps and tabs
648   char *v = pnd_box_get_head ( g_conf );
649   while ( v ) {
650
651     // does item begin with app or tab tag?
652     char *k = pnd_box_get_key ( v );
653
654     if ( k && 
655          ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
656            strncasecmp ( k, "tabshow.", 8 ) == 0 )
657        )
658     {
659       fprintf ( f, "%s\t%s\n", k, v );
660     }
661
662     v = pnd_box_get_next ( v );
663   } // while
664
665   fclose ( f );
666
667   return ( 1 );
668 }
669
670 void conf_merge_into ( char *fullpath, pnd_conf_handle h ) {
671   FILE *f;
672   char buffer [ 1024 ];
673   char *s;
674
675   f = fopen ( fullpath, "r" );
676
677   if ( ! f ) {
678     return;
679   }
680
681   while ( fgets ( buffer, 1000, f ) ) {
682 #if 0
683     // trim trailing spaces
684     s = strchr ( buffer, ' ' );
685     if ( s ) {
686       *s = '\0';
687     }
688 #endif
689     // and #...
690     s = strchr ( buffer, '#' );
691     if ( s ) {
692       *s = '\0';
693     }
694     // and newline...
695     s = strchr ( buffer, '\n' );
696     if ( s ) {
697       *s = '\0';
698     }
699
700     // if theres anything left..
701     if ( buffer [ 0 ] != '\0' ) {
702
703       // assume FOO<tab>BAR<newline> since this really should be machine written, not human screwed with; or if human
704       // edited, assume they know what to do :) I even put in some 'docs' in the conf file.
705       char *s = strchr ( buffer, '\t' );
706
707       if ( s ) {
708         *s = '\0';
709
710         // set it; libpnd conf code already handles 'existant' or 'new'
711         pnd_conf_set_char ( h, buffer, s + 1 );
712
713       } // found a <tab>?
714
715     } // anything left?
716
717   } // while
718
719   fclose ( f );
720
721   return;
722 }
723
724 char *conf_determine_location ( pnd_conf_handle h ) {
725   static char path [ PATH_MAX ];
726
727   bzero ( path, PATH_MAX );
728
729   if ( ! getenv ( "HOME" ) ) {
730     return ( "." ); // wtf?
731   }
732
733   snprintf ( path, PATH_MAX - strlen(CONF_PREF_FILENAME) - 1, "%s/%s", getenv ( "HOME" ), CONF_PREF_FILENAME );
734
735   return ( path );
736 }
737
738 void conf_setup_missing ( pnd_conf_handle h ) {
739
740   confitem_t *ci = page_general;
741
742   while ( ci -> text ) {
743
744     // does this item have a default value?
745     if ( ci -> def ) {
746
747       // it does, so lets see if we can pull a current value in; if not, set one
748       char *v = pnd_conf_get_as_char ( h, ci -> key );
749
750       if ( ! v ) {
751         fprintf ( stderr, "pref conf: no value present in config, better set to default; key is '%s' def '%s'\n", ci -> key, ci -> def );
752         pnd_conf_set_char ( h, ci -> key, ci -> def );
753       }
754
755     } // has def?
756
757     ci++;
758   } // while
759
760   return;
761 }
762
763 void conf_reset_to_default ( pnd_conf_handle h ) {
764
765   // reset all keys to default value - if present
766   // reset all apps to show
767   // reset all tabs to show
768
769   // deal with general keys
770   confitem_t *ci = page_general;
771   while ( ci -> text ) {
772
773     // does this item have a default value? if so, set it
774     if ( ci -> key && ci -> def ) {
775       pnd_conf_set_char ( h, ci -> key, ci -> def );
776     }
777
778     ci++;
779   } // while
780
781   // deal with apps and tabs
782   char *v = pnd_box_get_head ( g_conf );
783   char *next;
784   while ( v ) {
785     next = pnd_box_get_next ( v );
786
787     // does item begin with app or tab tag?
788     char *k = pnd_box_get_key ( v );
789
790     if ( k && 
791          ( strncasecmp ( k, "appshow.", 8 ) == 0 ||
792            strncasecmp ( k, "tabshow.", 8 ) == 0 )
793        )
794     {
795       pnd_conf_set_char ( g_conf, k, "1" );
796     }
797
798     v = next;
799   } // while
800
801   return;
802 }
803
804 unsigned int conf_determine_pagelength ( confitem_t *page ) {
805   confitem_t *p = page;
806   while ( p -> text ) {
807     p++;
808   }
809   return ( p - page );
810 }