root/core/gui_script.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_param
  2. new_param
  3. skip_whitespace
  4. skip_to_token
  5. skip_token
  6. skip_toeol
  7. skip_eol
  8. skip_tochar
  9. get_token
  10. get_name
  11. get_script_filename
  12. process_title
  13. process_subtitle
  14. check_param
  15. process_param
  16. get_default
  17. process_default
  18. get_range
  19. process_range
  20. get_values
  21. process_values
  22. process_single
  23. script_scan
  24. make_param_filename
  25. get_last_paramset_num
  26. load_params_values
  27. do_save_param_file
  28. save_params_values
  29. script_reset_to_default_params_values
  30. script_load
  31. gui_script_param_set_enum
  32. gui_load_script_selected
  33. gui_load_script
  34. gui_reset_script_default
  35. gui_load_script_default
  36. cb_change_param_save_enum
  37. gui_update_script_submenu

   1 #include "camera_info.h"
   2 #include "stdlib.h"
   3 #include "conf.h"
   4 #include "gui.h"
   5 #include "gui_lang.h"
   6 #include "gui_menu.h"
   7 #include "fileutil.h"
   8 
   9 #include "script_api.h"
  10 #include "gui_fselect.h"
  11 
  12 // Forward reference
  13 static void gui_update_script_submenu();
  14 
  15 //-------------------------------------------------------------------
  16 
  17 #define SCRIPT_DEFAULT_FILENAME     "A/CHDK/SCRIPTS/DEFAULT.LUA"
  18 #define SCRIPT_DATA_PATH            "A/CHDK/DATA/"
  19 
  20 // Requested filename
  21 enum FilenameMakeModeEnum {
  22     MAKE_PARAMSETNUM_FILENAME,      // "DATA/scriptname.cfg"
  23     MAKE_PARAM_FILENAME,            // "DATA/scriptname_%d"
  24     MAKE_PARAM_FILENAME_V2          // "DATA/scriptname.$d"
  25 };
  26 
  27 // ================ SCRIPT PARAMETERS ==========
  28 
  29 char script_title[36];                          // Title of current script
  30 _chdk_version_t script_version;                 // parsed from @chdk_version header, default to 1.3.0.0
  31 int script_has_version = 0;                     // indicates if script included @chdk_version header
  32 static int last_script_param_set = -1;          // used to test if script_param_set has changed
  33 static int is_script_loaded = 0;                // set after successful loading of script
  34 
  35 #define DEFAULT_PARAM_SET       10              // Value of conf.script_param_set for 'Default' rather than saved parameters
  36 #define MAX_PARAM_NAME_LEN      64              // Max length of a script name or description
  37 
  38 sc_param        *script_params = 0;             // Parameters for loaded script (linked list)
  39 static sc_param *tail = 0;
  40 int             script_param_count;             // Number of parameters
  41 
  42 //-------------------------------------------------------------------
  43 // Find parameter entry for 'name', return null if not found
  44 sc_param* find_param(char *name)
  45 {
  46     sc_param *p = script_params;
  47     while (p)
  48     {
  49         if ((p->name != 0) && (strcmp(name, p->name) == 0))
  50             break;
  51         p = p->next;
  52     }
  53     return p;
  54 }
  55 
  56 // Create new sc_param structure, and link into list
  57 sc_param* new_param(char *name)
  58 {
  59     sc_param *p = malloc(sizeof(sc_param));
  60     memset(p, 0, sizeof(sc_param));
  61     if (tail)
  62     {
  63         tail->next = p;
  64         tail = p;
  65     }
  66     else
  67     {
  68         script_params = tail = p;
  69     }
  70     script_param_count++;
  71 
  72     if (name != 0)
  73     {
  74         p->name = malloc(strlen(name)+1);
  75         strcpy(p->name, name);
  76     }
  77 
  78     return p;
  79 }
  80 
  81 //-------------------------------------------------------------------
  82 
  83 #define IS_SPACE(p)     ((*p == ' ')  || (*p == '\t'))
  84 #define IS_EOL(p)       ((*p == '\n') || (*p == '\r'))
  85 
  86 const char* skip_whitespace(const char* p)  { while (IS_SPACE(p)) p++; return p; }                                      // Skip past whitespace
  87 const char* skip_to_token(const char* p)    { while (IS_SPACE(p) || (*p == '=')) p++; return p; }                       // Skip to next token
  88 const char* skip_token(const char* p)       { while (*p && !IS_EOL(p) && !IS_SPACE(p) && (*p != '=')) p++; return p; }  // Skip past current token value
  89 const char* skip_toeol(const char* p)       { while (*p && !IS_EOL(p)) p++; return p; }                                 // Skip to end of line
  90 const char* skip_eol(const char *p)         { p = skip_toeol(p); if (*p == '\r') p++; if (*p == '\n') p++; return p; }  // Skip past end of line
  91 
  92 const char* skip_tochar(const char *p, char end)
  93 {
  94     while (!IS_EOL(p) && (*p != end)) p++;
  95     return p;
  96 }
  97 
  98 // Extract next token into buffer supplied (up to maxlen)
  99 const char* get_token(const char *p, char *buf, int maxlen)
 100 {
 101     p = skip_whitespace(p);
 102     int l = skip_token(p) - p;
 103     int n = (l <= maxlen) ? l : maxlen;
 104     strncpy(buf, p, n);
 105     buf[n] = 0;
 106     return p + l;
 107 }
 108 
 109 // Extract name up to maxlen, find or create sc_param based on name
 110 // Return pointer past name.
 111 // Sets *sp to sc_param entry, or 0 if not found
 112 const char* get_name(const char *p, int maxlen, sc_param **sp, int create)
 113 {
 114     char str[MAX_PARAM_NAME_LEN+1];
 115     *sp = 0;
 116     p = skip_whitespace(p);
 117     if (p[0] && isalpha(p[0]))
 118     {
 119         p = get_token(p, str, maxlen);
 120         *sp = find_param(str);
 121         if ((*sp == 0) && create)
 122             *sp = new_param(str);
 123     }
 124     return p;
 125 }
 126 
 127 // Extract name part of script file from full path
 128 const char* get_script_filename()
 129 {
 130     const char* name = 0;
 131     // find name of script
 132     if (conf.script_file[0] != 0)
 133     {
 134         name = strrchr(conf.script_file, '/');
 135         if (name)
 136             name++;
 137         else
 138             name = conf.script_file;
 139     }
 140     return name;
 141 }
 142 
 143 //=======================================================
 144 //             PROCESSING "@ACTION" FUNCTIONS
 145 //=======================================================
 146 
 147 //-------------------------------------------------------------------
 148 static void process_title(const char *ptr)
 149 {
 150     ptr = skip_whitespace(ptr);
 151     int l = skip_toeol(ptr) - ptr;
 152     if (l >= sizeof(script_title)) l = sizeof(script_title) - 1;
 153     strncpy(script_title, ptr, l);
 154     script_title[l] = 0;
 155 }
 156 
 157 static void process_subtitle(const char *ptr)
 158 {
 159     ptr = skip_whitespace(ptr);
 160     int l = skip_toeol(ptr) - ptr;
 161     if (l >= sizeof(script_title)) l = sizeof(script_title) - 1;
 162     sc_param *p = new_param(0);
 163     p->desc = malloc(l+1);
 164     strncpy(p->desc, ptr, l);
 165     p->desc[l] = 0;
 166     p->range_type = MENUITEM_SEPARATOR;
 167 }
 168 
 169 //-------------------------------------------------------------------
 170 // Process one entry "@param VAR TITLE" to check if it exists
 171 // RETURN VALUE: 0 if not valid, 1 if valid
 172 // Used to ensure that a param loaded from an old saved paramset does
 173 // not overwrite defaults from script
 174 //-------------------------------------------------------------------
 175 static int check_param(const char *ptr)
 176 {
 177     sc_param *p;
 178     ptr = get_name(ptr, MAX_PARAM_NAME_LEN, &p, 0);
 179     if (p)
 180         return 1;
 181     return 0;
 182 }
 183 
 184 //-------------------------------------------------------------------
 185 // Process one entry "@param VAR TITLE"
 186 // RESULT: params[VAR].desc - parameter title
 187 // RETURN VALUE: 0 if err, 1 if ok
 188 //-------------------------------------------------------------------
 189 static void process_param(const char *ptr)
 190 {
 191     sc_param *p;
 192     ptr = get_name(ptr, MAX_PARAM_NAME_LEN, &p, 1);
 193     if (p)
 194     {
 195         ptr = skip_whitespace(ptr);
 196         int l = skip_toeol(ptr) - ptr;
 197         if (l > MAX_PARAM_NAME_LEN) l = MAX_PARAM_NAME_LEN;
 198         p->desc = malloc(l+1);
 199         strncpy(p->desc, ptr, l);
 200         p->desc[l] = 0;
 201     }
 202 }
 203 
 204 //-------------------------------------------------------------------
 205 // Process one entry "@default VAR VALUE"
 206 //-------------------------------------------------------------------
 207 static const char* get_default(sc_param *p, const char *ptr, int isScript)
 208 {
 209     ptr = skip_to_token(ptr);
 210     if (p)
 211     {
 212         int type = MENUITEM_INT|MENUITEM_SCRIPT_PARAM;
 213         int range = 0;
 214         if (strncmp(ptr, "true", 4) == 0)
 215         {
 216             p->val = 1;
 217             type = MENUITEM_BOOL|MENUITEM_SCRIPT_PARAM;
 218             range = MENU_MINMAX(1,0);   // Force boolean data type in Lua (ToDo: this is clunky, needs fixing)
 219 
 220         }
 221         else if (strncmp(ptr, "false", 5) == 0)
 222         {
 223             p->val = 0;
 224             type = MENUITEM_BOOL|MENUITEM_SCRIPT_PARAM;
 225             range = MENU_MINMAX(1,0);   // Force boolean data type in Lua (ToDo: this is clunky, needs fixing)
 226         }
 227         else
 228         {
 229             p->val = strtol(ptr, NULL, 0);
 230         }
 231         p->old_val = p->val;
 232         if (isScript)   // Loading from script file (rather than saved param set file)
 233         {
 234             p->def_val = p->val;
 235             p->range = range;
 236             p->range_type = type;
 237         }
 238     }
 239     return skip_token(ptr);
 240 }
 241 
 242 static void process_default(const char *ptr, int isScript)
 243 {
 244     sc_param *p;
 245     ptr = get_name(ptr, MAX_PARAM_NAME_LEN, &p, isScript);
 246     get_default(p, ptr, isScript);
 247 }
 248 
 249 //-------------------------------------------------------------------
 250 // Process one entry "@range VAR MIN MAX"
 251 //-------------------------------------------------------------------
 252 static const char* get_range(sc_param *p, const char *ptr, char end)
 253 {
 254     ptr = skip_whitespace(ptr);
 255     int min = strtol(ptr,NULL,0);
 256     ptr = skip_whitespace(skip_token(ptr));
 257     int max = strtol(ptr,NULL,0);
 258 
 259     if (p)
 260     {
 261         p->range = MENU_MINMAX(min,max);
 262         p->range_type = MENUITEM_INT|MENUITEM_F_MINMAX|MENUITEM_SCRIPT_PARAM;
 263         if ((p->range == MENU_MINMAX(0,1)) || (p->range == MENU_MINMAX(1,0)))
 264             p->range_type = MENUITEM_BOOL|MENUITEM_SCRIPT_PARAM;
 265         else if ((min >= 0) && (max >= 0))
 266             p->range_type |= MENUITEM_F_UNSIGNED;
 267     }
 268 
 269     ptr = skip_tochar(ptr, end);
 270     if (end && (*ptr == end)) ptr++;
 271     return ptr;
 272 }
 273 
 274 static void process_range(const char *ptr)
 275 {
 276     sc_param *p;
 277     ptr = get_name(ptr, MAX_PARAM_NAME_LEN, &p, 1);
 278     get_range(p, ptr, 0);
 279 }
 280 
 281 //-------------------------------------------------------------------
 282 // Process one entry "@values VAR A B C D ..."
 283 //-------------------------------------------------------------------
 284 static const char* get_values(sc_param *p, const char *ptr, char end)
 285 {
 286     ptr = skip_whitespace(ptr);
 287     int len = skip_tochar(ptr, end) - ptr;
 288 
 289     if (p)
 290     {
 291         p->range = 0;
 292         p->range_type = MENUITEM_ENUM2|MENUITEM_SCRIPT_PARAM;
 293 
 294         p->option_buf = malloc(len+1);
 295         strncpy(p->option_buf, ptr, len);
 296         p->option_buf[len] = 0;
 297 
 298         const char *s = p->option_buf;
 299         int cnt = 0;
 300         while (*s)
 301         {
 302             s = skip_whitespace(skip_token(s));
 303             cnt++;
 304         }
 305         p->option_count = cnt;
 306         p->options = malloc(cnt * sizeof(char*));
 307 
 308         s = p->option_buf;
 309         cnt = 0;
 310         while (*s)
 311         {
 312             p->options[cnt] = s;
 313             s = skip_token(s);
 314             if (*s)
 315             {
 316                 *((char*)s) = 0;
 317                 s = skip_whitespace(s+1);
 318             }
 319             cnt++;
 320         }
 321     }
 322 
 323     ptr += len;
 324     if (end && (*ptr == end)) ptr++;
 325     return ptr;
 326 }
 327 
 328 static void process_values(const char *ptr)
 329 {
 330     sc_param *p;
 331     ptr = get_name(ptr, MAX_PARAM_NAME_LEN, &p, 1);
 332     get_values(p, ptr, 0);
 333 }
 334 
 335 //-------------------------------------------------------------------
 336 // Process short form entry on single line
 337 //      '#VAR=VAL "TITLE" [MIN MAX]'
 338 // or   '#VAR=VAL "TITLE" {A B C D ...}'
 339 //-------------------------------------------------------------------
 340 static int process_single(const char *ptr)
 341 {
 342     sc_param *p;
 343     ptr = get_name(ptr, MAX_PARAM_NAME_LEN, &p, 1);
 344     if (p)
 345     {
 346         ptr = get_default(p, ptr, 1);
 347         ptr = skip_whitespace(ptr);
 348         if ((*ptr == '"') || (*ptr == '\''))
 349         {
 350             const char *s = skip_tochar(ptr+1, *ptr);
 351             p->desc = malloc(s-ptr);
 352             strncpy(p->desc, ptr+1, s-ptr-1);
 353             p->desc[s-ptr-1] = 0;
 354             if (*s == *ptr) s++;
 355             ptr = skip_whitespace(s);
 356         }
 357         else
 358         {
 359             // Error - log to console and abort
 360             return 0;
 361         }
 362         if (*ptr == '[')
 363         {
 364             ptr = get_range(p, ptr+1, ']');
 365         }
 366         else if (*ptr == '{')
 367         {
 368             ptr = get_values(p, ptr+1, '}');
 369             ptr = skip_whitespace(ptr);
 370             if (strncmp(ptr,"table",5) == 0)
 371             {
 372                 p->data_type = DTYPE_TABLE;
 373                 p->val--;   // Initial value is 1 based for Lua table, convert to 0 based for C code
 374                 p->def_val--;   // also adjust default
 375             }
 376         }
 377         ptr = skip_whitespace(ptr);
 378         if (strncmp(ptr,"bool",4) == 0)
 379         {
 380             p->range = MENU_MINMAX(1,0);   // Force boolean data type in Lua (ToDo: this is clunky, needs fixing)
 381             p->range_type = MENUITEM_BOOL|MENUITEM_SCRIPT_PARAM;
 382             ptr = skip_token(ptr);
 383         }
 384         ptr = skip_whitespace(ptr);
 385         if (strncmp(ptr,"long",4) == 0)
 386         {
 387             p->range = 9999999;
 388             p->range_type = MENUITEM_INT|MENUITEM_SD_INT;
 389             ptr = skip_token(ptr);
 390         }
 391     }
 392     return 1;
 393 }
 394 
 395 //=======================================================
 396 //                 SCRIPT LOADING FUNCTIONS
 397 //=======================================================
 398 
 399 //-------------------------------------------------------------------
 400 // PURPOSE: Parse script (conf.script_file) for parameters and title
 401 //-------------------------------------------------------------------
 402 static void script_scan()
 403 {
 404     // Reset everything
 405     sc_param *p = script_params;
 406     while (p)
 407     {
 408         if (p->name)       free(p->name);
 409         if (p->desc)       free(p->desc);
 410         if (p->options)    free(p->options);
 411         if (p->option_buf) free(p->option_buf);
 412         sc_param *l = p;
 413         p = p->next;
 414         free(l);
 415     }
 416     script_params = tail = 0;
 417     script_param_count = 0;
 418 
 419     parse_version(&script_version, "1.3.0.0", 0);
 420     script_has_version = 0;
 421     is_script_loaded = 0;
 422 
 423     // Load script file
 424     const char *buf=0;
 425     if (conf.script_file[0] != 0)
 426         buf = load_file_to_length(conf.script_file, 0, 1, 4096);    // Assumes parameters are in first 4K of script file
 427 
 428     // Check file loaded
 429     if (buf == 0)
 430     {
 431         strcpy(script_title, "NO SCRIPT");
 432         return;
 433     }
 434 
 435     // Build title from name (in case no title in script)
 436     const char *c = get_script_filename();
 437     strncpy(script_title, c, sizeof(script_title)-1);
 438     script_title[sizeof(script_title)-1]=0;
 439 
 440     // Fillup order, defaults
 441     const char *ptr = buf;
 442     while (ptr[0])
 443     {
 444         ptr = skip_whitespace(ptr);
 445         if (ptr[0] == '@')
 446         {
 447             if (strncmp("@title", ptr, 6)==0)
 448             {
 449                 process_title(ptr+6);
 450             }
 451             else if (strncmp("@subtitle", ptr, 9)==0)
 452             {
 453                 process_subtitle(ptr+9);
 454             }
 455             else if (strncmp("@param", ptr, 6)==0)
 456             {
 457                 process_param(ptr+6);
 458             }
 459             else if (strncmp("@default", ptr, 8)==0)
 460             {
 461                 process_default(ptr+8, 1);
 462             }
 463             else if (strncmp("@range", ptr, 6)==0)
 464             {
 465                 process_range(ptr+6);
 466             }
 467             else if (strncmp("@values", ptr, 7)==0)
 468             {
 469                 process_values(ptr+7);
 470             }
 471             else if (strncmp("@chdk_version", ptr, 13)==0)
 472             {
 473                 ptr = skip_whitespace(ptr+13);
 474                 parse_version(&script_version, ptr, 0);
 475                 script_has_version = 1;
 476             }
 477         }
 478         else if (ptr[0] == '#')
 479         {
 480             process_single(ptr+1);
 481         }
 482         ptr = skip_eol(ptr);
 483     }
 484 
 485     free((void*)buf);
 486     is_script_loaded = 1;
 487 }
 488 
 489 //-------------------------------------------------------------------
 490 // PURPOSE:     Create cfg filename in buffer.
 491 // PARAMETERS:  mode - what exact kind of cfg file name required
 492 // RESULT:  pointer to buffer with full path to config file
 493 //-------------------------------------------------------------------
 494 static char* make_param_filename(enum FilenameMakeModeEnum mode)
 495 {
 496     // output buffer
 497     static char tgt_buf[100];
 498     
 499     // find name of script
 500     const char* name = get_script_filename();
 501     
 502     // make path
 503     strcpy(tgt_buf, SCRIPT_DATA_PATH);
 504     
 505     // add script filename
 506     char* s = tgt_buf + strlen(tgt_buf);
 507     strncpy(s, name, 12);
 508     s[12] = 0;
 509 
 510     // find where extension start and replace it
 511     s = strrchr(tgt_buf, '.');
 512     if (!s) s = tgt_buf + strlen(tgt_buf);
 513 
 514     switch (mode)
 515     {
 516         case MAKE_PARAMSETNUM_FILENAME:
 517             strcpy(s,".cfg");
 518             break;
 519         case MAKE_PARAM_FILENAME:
 520             sprintf(s,"_%d", conf.script_param_set);
 521             break;
 522         case MAKE_PARAM_FILENAME_V2:
 523             sprintf(s,".%d", conf.script_param_set);
 524             break;
 525     }
 526 
 527     return tgt_buf;
 528 }
 529 
 530 //-------------------------------------------------------------------
 531 // read last paramset num of script "fn" to conf.script_param_set
 532 //-------------------------------------------------------------------
 533 static void get_last_paramset_num()
 534 {
 535     // skip if no script available
 536     if (conf.script_file[0] == 0) return;
 537 
 538     char *nm = make_param_filename(MAKE_PARAMSETNUM_FILENAME);
 539     if ( !load_int_value_file( nm, &conf.script_param_set ) )
 540     {
 541         conf.script_param_set = 0;
 542         last_script_param_set = -1;      // failed to load so force next save
 543     }
 544     else
 545     {
 546         last_script_param_set = conf.script_param_set;  // save last value loaded from file
 547     }
 548     if ((conf.script_param_set < 0) || (conf.script_param_set > 10))
 549         conf.script_param_set = 0;
 550 }
 551 
 552 //-------------------------------------------------------------------
 553 // PURPOSE:     Load parameters from paramset for script
 554 // PARAMETERS:  fn - full path of script
 555 //              paramset - num of loaded paramset (usually conf.script_param_set)
 556 // RETURN:      1-succesfully applied, 0 - something was failed
 557 //-------------------------------------------------------------------
 558 static int load_params_values()
 559 {
 560     // skip if no script loaded
 561     if (conf.script_file[0] == 0) return 0;
 562     // skip if 'default' parameters requested
 563     if (conf.script_param_set == DEFAULT_PARAM_SET) return 0;
 564     
 565     if ((conf.script_param_set < 0) || (conf.script_param_set > 10))
 566         conf.script_param_set = 0;
 567 
 568     char *nm = make_param_filename(MAKE_PARAM_FILENAME_V2);
 569 
 570     char* buf = load_file(nm, 0, 1);
 571     if (buf == 0)
 572     {
 573         nm = make_param_filename(MAKE_PARAM_FILENAME);
 574         buf = load_file(nm, 0, 1);
 575         if (buf == 0)
 576             return 0;
 577     }
 578 
 579     const char* ptr = buf;
 580     int valid = 1;
 581 
 582     // Initial scan of saved paramset file
 583     // Ensure all saved params match defaults from script
 584     // If not assume saved file is invalid and don't load it
 585     //   may occur if script is changed, or file was saved by a different script with same name
 586     while (ptr[0] && valid)
 587     {
 588         ptr = skip_whitespace(ptr);
 589         if (ptr[0] == '@')
 590         {
 591             if (strncmp("@param", ptr, 6) == 0) 
 592             {
 593                 if (!check_param(ptr+6))
 594                     valid = 0;
 595             }
 596         }
 597         else if (ptr[0] == '#')
 598         {
 599             if (!check_param(ptr+1))
 600                 valid = 0;
 601         }
 602         ptr = skip_eol(ptr);
 603     }
 604 
 605     if (valid)
 606     {
 607         // All ok, reset and process file
 608         ptr = buf;
 609 
 610         while (ptr[0])
 611         {
 612             ptr = skip_whitespace(ptr);
 613             if (ptr[0]=='@')
 614             {
 615                 // Already checked file, so only need to load the @default values
 616                 // @param, @range & @values already set from script
 617                 if (strncmp("@default", ptr, 8)==0)
 618                 {
 619                     process_default(ptr+8, 0);
 620                 }
 621             }
 622             else if (ptr[0] == '#')
 623             {
 624                 process_default(ptr+1, 0);
 625             }
 626             ptr = skip_eol(ptr);
 627         }
 628     }
 629 
 630     free(buf);
 631 
 632     return valid;
 633 }
 634 
 635 
 636 //-------------------------------------------------------------------
 637 // PURPOSE:     Auxilary function.
 638 //                Actually save param file
 639 //-------------------------------------------------------------------
 640 static void do_save_param_file()
 641 {
 642     char buf[100];
 643 
 644     char *fn = make_param_filename(MAKE_PARAM_FILENAME_V2);
 645     int fd = open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0777);
 646 
 647     if (fd >= 0)
 648     {
 649         sc_param *p = script_params;
 650         while (p)
 651         {
 652             // Only save parameters, skip 'subtitle' lines
 653             if (p->name != 0)
 654             {
 655                 // Only need to save name and value - saved as #name=value
 656                 sprintf(buf,"#%s=%d\n",p->name,p->val);
 657                 write(fd, buf, strlen(buf));
 658             }
 659             p = p->next;
 660         }
 661         close(fd);
 662     }
 663 }
 664 
 665 //-------------------------------------------------------------------
 666 // PURPOSE:     Save parameters to paramset for script
 667 //                  Use: conf.script_file, conf.script_param_set
 668 // PARAMETERS:  enforce = 1 mean save always
 669 //                      = 0 mean save only if any values was changed
 670 //                        (script_params[i].old_val != script_params[i].val)
 671 //
 672 // NOTE:    1. create SCRIPT_DATA_PATH/scriptname.cfg 
 673 //                      which store # of last saved paramset
 674 //          2. create SCRIPT_DATA_PATH/scriptname_PARAMSETNUM 
 675 //                      which param_str
 676 //-------------------------------------------------------------------
 677 void save_params_values( int enforce )
 678 {
 679     if (conf.script_param_save && (conf.script_param_set != DEFAULT_PARAM_SET))
 680     {
 681         // Write paramsetnum file
 682         if (conf.script_param_set != last_script_param_set)
 683         {
 684             char *nm = make_param_filename(MAKE_PARAMSETNUM_FILENAME);
 685             save_int_value_file( nm, conf.script_param_set );
 686             last_script_param_set = conf.script_param_set;
 687         }
 688 
 689         int i, changed=0;
 690 
 691         // Check is anything changed since last time
 692         sc_param *p = script_params;
 693         while (p)
 694         {
 695             if (p->old_val != p->val)
 696             {
 697                 changed++;
 698                 p->old_val = p->val;
 699             }
 700             p = p->next;
 701         }
 702 
 703         if (enforce || changed)
 704         {
 705             // Write parameters file
 706             do_save_param_file();
 707         }
 708     }
 709 }
 710 
 711 //-------------------------------------------------------------------
 712 // PURPOSE: Reset values of variables to default
 713 //-------------------------------------------------------------------
 714 void script_reset_to_default_params_values() 
 715 {
 716     sc_param *p = script_params;
 717     while (p)
 718     {
 719         p->val = p->def_val;
 720         p = p->next;
 721     }
 722 }
 723 
 724 //-------------------------------------------------------------------
 725 // PURPOSE: Load script to memory ( and free malloc previous if exists)
 726 // PARAMETERS:  fn - full path of script
 727 //
 728 // RESULTS: conf.script_file
 729 //
 730 // NOTES:  1. Try to load fn, if fn or file is empty - SCRIPT_DEFAULT_FILENAME, 
 731 //                if default not exists - display 'NO SCRIPT'
 732 //         2. Update conf.script_file, title, submenu
 733 //-------------------------------------------------------------------
 734 void script_load(const char *fn)
 735 {
 736     char* buf;
 737 
 738     // if filename is empty, try to load default named script.
 739     // if no such one, no script will be used
 740     if ((fn == 0) || (fn[0] == 0))
 741         fn = SCRIPT_DEFAULT_FILENAME;
 742 
 743     strcpy(conf.script_file, fn);
 744 
 745     get_last_paramset_num();    // update data paths
 746     script_scan();              // re-fill @title/@names/@range/@value + reset values to @default
 747     load_params_values();
 748 
 749     gui_update_script_submenu();
 750 }
 751 
 752 //-------------------------------------------------------------------
 753 
 754 static const char* gui_script_param_set_enum(int change, int arg)
 755 {
 756     static const char* modes[]={ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Default" };
 757 
 758     if (change != 0)
 759     {
 760         save_params_values(0);
 761         gui_enum_value_change(&conf.script_param_set,change,sizeof(modes)/sizeof(modes[0]));
 762 
 763         if (conf.script_param_set == DEFAULT_PARAM_SET)
 764             conf.script_param_save = 0;
 765         else
 766             conf.script_param_save = 1;
 767 
 768         if ( !load_params_values() )
 769             script_reset_to_default_params_values();
 770         gui_update_script_submenu();
 771     }
 772 
 773     return modes[conf.script_param_set];
 774 }
 775 
 776 static void gui_load_script_selected(const char *fn)
 777 {
 778     if (fn)
 779     {
 780         gui_menu_cancel_redraw();   // Stop menu redraw until after menu rebuilt from script params
 781         save_params_values(0);
 782         script_load(fn);
 783         gui_set_need_restore();
 784     }
 785 }
 786 
 787 static void gui_load_script(int arg)
 788 {
 789     libfselect->file_select(LANG_STR_SELECT_SCRIPT_FILE, conf.script_file, "A/CHDK/SCRIPTS", gui_load_script_selected);
 790 }
 791 
 792 static void gui_reset_script_default(int arg)
 793 {
 794     gui_menu_cancel_redraw();       // Stop menu redraw until after menu rebuilt from script params
 795     save_params_values(0);
 796     conf.script_file[0] = 0;        // Reset loaded script
 797     script_load(conf.script_file);
 798     gui_set_need_restore();
 799 }
 800 
 801 static void gui_load_script_default(int arg)
 802 {
 803     script_reset_to_default_params_values();
 804     gui_update_script_submenu();
 805     save_params_values(1);
 806 }
 807 
 808 static const char* gui_script_autostart_modes[]=            { "Off", "On", "Once", "ALT"};
 809 
 810 static void cb_change_param_save_enum()
 811 {
 812     if (conf.script_param_set != DEFAULT_PARAM_SET)
 813     {
 814         if (conf.script_param_save)
 815             save_params_values(0);
 816     }
 817     else
 818     {
 819         conf.script_param_save = 0;
 820     }
 821 }
 822 
 823 static CMenuItem param_save[2] = {
 824     MENU_ITEM   (0, 0,  MENUITEM_ENUM,                                      gui_script_param_set_enum,      0 ),
 825     MENU_ITEM   (0, 0,  MENUITEM_BOOL|MENUITEM_ARG_CALLBACK,                &conf.script_param_save,        (int)cb_change_param_save_enum ),
 826 };
 827 
 828 // Indexes into script_submenu_items array, if you add or remove entries adjust these
 829 #define SCRIPT_SUBMENU_PARAMS_IDX   8       // First adjustable parameter entry
 830 #define SCRIPT_SUBMENU_BOTTOM_IDX   34      // 'Back' entry
 831 
 832 static CMenuItem hdr_script_submenu_items[] = {
 833     MENU_ITEM   (0x35,LANG_MENU_SCRIPT_LOAD,                MENUITEM_PROC,                      gui_load_script,            0 ),
 834     MENU_ITEM   (0x5f,LANG_MENU_SCRIPT_DELAY,               MENUITEM_INT|MENUITEM_F_UNSIGNED,   &conf.script_shoot_delay,   0 ),
 835     // remote autostart
 836     MENU_ENUM2  (0x5f,LANG_MENU_SCRIPT_AUTOSTART,           &conf.script_startup,               gui_script_autostart_modes ),
 837     MENU_ITEM   (0x5c,LANG_MENU_LUA_RESTART,                MENUITEM_BOOL,                      &conf.debug_lua_restart_on_error,   0 ),
 838     MENU_ITEM   (0x5d,LANG_MENU_SCRIPT_DEFAULT_VAL,         MENUITEM_PROC,                      gui_load_script_default,    0 ),
 839     MENU_ITEM   (0x5e,LANG_MENU_SCRIPT_PARAM_SET,           MENUITEM_STATE_VAL_PAIR,            &param_save,                0 ),
 840     MENU_ITEM   (0x0 ,(int)script_title,                    MENUITEM_SEPARATOR,                 0,                          0 ),
 841 };
 842 
 843 static CMenuItem *script_submenu_items = 0;
 844 int script_submenu_count = 0;
 845 
 846 CMenu script_submenu = {0x27,LANG_MENU_SCRIPT_TITLE, 0 };
 847 
 848 static void gui_update_script_submenu() 
 849 {
 850     int i;
 851     sc_param *p;
 852 
 853     int warn = 0;
 854     if (is_script_loaded && (!script_has_version || (cmp_chdk_version(chdk_version, script_version) < 0)))
 855     {
 856         warn = 1;
 857     }
 858 
 859     // Calculate # of header items, and total required for header, parameters, back button and terminator
 860     int f = (sizeof(hdr_script_submenu_items) / sizeof(CMenuItem)) + warn;
 861     int n = f + script_param_count + 2;
 862 
 863     // If we need more room, then free up old buffer
 864     if (script_submenu_items && (script_submenu_count < n))
 865     {
 866         free(script_submenu_items);
 867         script_submenu_items = 0;
 868         script_submenu_count = 0;
 869     }
 870 
 871     // If no buffer allocated, allocate one
 872     if (script_submenu_items == 0)
 873     {
 874         script_submenu_items = malloc(n * sizeof(CMenuItem));
 875         memset(script_submenu_items, 0, n * sizeof(CMenuItem));
 876         // Update size of buffer if smaller than new size
 877         if (script_submenu_count < n)
 878             script_submenu_count = n;
 879     }
 880 
 881     // Copy header items
 882     memcpy(script_submenu_items, hdr_script_submenu_items, sizeof(hdr_script_submenu_items));
 883 
 884     // Add warning if no @chdk_version, or if chdk_version < script_version
 885     if (warn)
 886     {
 887         if (cmp_chdk_version(chdk_version, script_version) < 0)
 888         {
 889             static char warning[50];
 890             sprintf(warning, "Script requires CHDK ver: %d.%d.%d.%d", script_version.major, script_version.minor, script_version.maintenance, script_version.revision);
 891             script_submenu_items[f-1].text = (int)warning;
 892             script_submenu_items[f-1].type = MENUITEM_ERROR;
 893         }
 894         else
 895         {
 896             script_submenu_items[f-1].text = (int)"No @chdk_version, assuming CHDK 1.3";
 897             script_submenu_items[f-1].type = MENUITEM_WARNING;
 898         }
 899     }
 900 
 901     // Update menu to point to new submenu buffer
 902     script_submenu.menu = script_submenu_items;
 903 
 904     // Build parameter menu items
 905     for (i=f, p=script_params; p; i++, p=p->next)
 906     {
 907         script_submenu_items[i].symbol = 0x0;
 908         script_submenu_items[i].text = (int)p->desc;
 909         script_submenu_items[i].type = p->range_type;
 910         script_submenu_items[i].value = &p->val;
 911         script_submenu_items[i].arg = p->range;
 912 
 913         if (p->option_count != 0)
 914         {
 915             script_submenu_items[i].opt_len = p->option_count;
 916             script_submenu_items[i].arg = (int)p->options;
 917         }
 918     }
 919 
 920     // Fill in 'Back' button
 921     memset(&script_submenu_items[i],0,sizeof(CMenuItem)*2);
 922     script_submenu_items[i].symbol = 0x51;
 923     script_submenu_items[i].text = LANG_MENU_BACK;
 924     script_submenu_items[i].type = MENUITEM_UP;
 925 }
 926 
 927 //-------------------------------------------------------------------

/* [<][>][^][v][top][bottom][index][help] */