root/modules/user_menu_edit.c

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

DEFINITIONS

This source file includes following definitions.
  1. validrow
  2. gui_menu_disp_rows
  3. gui_menu_rows
  4. gui_menu_erase_and_redraw
  5. inUserMenu
  6. add_usermenu_item
  7. add_usermenu
  8. del_usermenu_item
  9. del_usermenu
  10. move_usermenu_item
  11. move_usermenu_item_up
  12. move_usermenu_item_down
  13. add_extern_to_user_menu
  14. add_script_to_user_menu
  15. add_module_to_user_menu
  16. gui_menu_set_curr_menu
  17. gui_init
  18. gui_menu_back
  19. gui_activate_sub_menu
  20. select_sub_menu
  21. gui_menu_updown
  22. gui_draw_initial
  23. gui_draw_symbol
  24. gui_draw_value
  25. gui_draw_text
  26. gui_draw_state_value
  27. gui_draw
  28. gui_uedit_kbd_process_menu_btn
  29. skip_whitespace
  30. skip_toeol
  31. skip_eol
  32. chk_ext
  33. gui_uedit_script_selected
  34. gui_uedit_module_selected
  35. uedit_set
  36. gui_uedit_kbd_process
  37. _run
  38. _module_can_unload
  39. _module_exit_alt
  40. _module_unload

   1 #include "camera_info.h"
   2 #include "stdlib.h"
   3 #include "conf.h"
   4 #include "keyboard.h"
   5 #include "font.h"
   6 #include "lang.h"
   7 #include "fileutil.h"
   8 #include "gui.h"
   9 #include "gui_draw.h"
  10 #include "gui_menu.h"
  11 #include "gui_user_menu.h"
  12 #include "gui_lang.h"
  13 #include "gui_mbox.h"
  14 #include "gui_mpopup.h"
  15 #include "gui_fselect.h"
  16 
  17 #include "module_load.h"
  18 #include "module_def.h"
  19 
  20 //-------------------------------------------------------------------
  21 #define MENUSTACK_MAXDEPTH  4
  22 
  23 //-------------------------------------------------------------------
  24 typedef struct {
  25     CMenu       *menu;
  26     int         curpos;
  27     int         toppos;
  28 } CMenuStacked;
  29 
  30 //-------------------------------------------------------------------
  31 
  32 static CMenu        *curr_menu;
  33 static CMenuStacked gui_menu_stack[MENUSTACK_MAXDEPTH];
  34 static unsigned int gui_menu_stack_ptr;
  35 static int          gui_menu_curr_item;
  36 static int          gui_menu_top_item;
  37 static int          gui_menu_redraw;
  38 
  39 static int          count;
  40 static int          x, y;
  41 static int          w, wplus, num_lines;
  42 static int          len_bool, len_space;
  43 
  44 static int running = 0;
  45 static gui_handler *gui_mode_old; // stored previous gui_mode
  46 
  47 //-------------------------------------------------------------------
  48 static int validrow(int n)
  49 {
  50     if (((curr_menu->menu[n].type & MENUITEM_MASK) != MENUITEM_SEPARATOR) &&
  51         ((curr_menu->menu[n].type & MENUITEM_SCRIPT_PARAM) != MENUITEM_SCRIPT_PARAM) &&
  52         ((curr_menu->menu[n].type & MENUITEM_TEXT) != MENUITEM_TEXT) &&
  53         (curr_menu->menu[n].text != LANG_MENU_USER_MENU) &&
  54         (curr_menu->menu[n].text != LANG_MENU_MAIN_TITLE))
  55         return 1;
  56     return 0;
  57 }
  58 
  59 static int gui_menu_disp_rows()
  60 {
  61     int n, m;
  62     // Count the numer of rows in current menu
  63     for(n = 0, m = 0; curr_menu->menu[n].text; n++)
  64         if (validrow(n)) m++;
  65     return m;
  66 }
  67 
  68 static int gui_menu_rows()
  69 {
  70     int n;
  71     // Count the numer of rows in current menu
  72     for(n = 0; curr_menu->menu[n].text; n++);
  73     return n;
  74 }
  75 
  76 //-------------------------------------------------------------------
  77 // Full screen erase and redraw of menu
  78 void gui_menu_erase_and_redraw()
  79 {
  80     gui_menu_redraw = 2;
  81     gui_set_need_restore();
  82 }
  83 
  84 //-------------------------------------------------------------------
  85 static int inUserMenu(int n)
  86 {
  87     int i;
  88     for (i=1; user_submenu.menu[i].text != 0; i++)
  89     {
  90         if (user_submenu.menu[i].text == curr_menu->menu[n].text)
  91             return 1;
  92     }
  93     return 0;
  94 }
  95 
  96 //-------------------------------------------------------------------
  97 static CMenuItem mod_menu_item;
  98 static char msgbuf[200];
  99 
 100 void add_usermenu_item(unsigned int btn)
 101 {
 102     gui_menu_erase_and_redraw();
 103     if (btn == MBOX_BTN_YES)
 104     {
 105         int i;
 106 
 107         /*
 108          * Insert new Item at end of existing entries
 109          */
 110         CMenuItem *items = (CMenuItem*)user_submenu.menu;
 111 
 112         for (i = 1; i < USER_MENU_ITEMS + 1; i++)
 113         {
 114             if (!items[i].text)
 115             {
 116                 items[i] = mod_menu_item;
 117                 camera_info.state.user_menu_has_changed = 1;
 118                 return;
 119             }
 120         }
 121         gui_mbox_init(LANG_MENU_USER_MENU, LANG_USER_MENU_FULL, MBOX_BTN_OK|MBOX_TEXT_CENTER, NULL);
 122     }
 123 }
 124 
 125 static void add_usermenu()
 126 {
 127     if (!inUserMenu(gui_menu_curr_item) && (curr_menu->menu[gui_menu_curr_item].text != LANG_MENU_BACK))
 128     {
 129         mod_menu_item = curr_menu->menu[gui_menu_curr_item];
 130         sprintf(msgbuf, lang_str(LANG_USER_MENU_ADD), lang_str(mod_menu_item.text));
 131         gui_mbox_init(LANG_INFORMATION, (int)msgbuf, MBOX_BTN_YES_NO|MBOX_DEF_BTN1|MBOX_TEXT_CENTER, add_usermenu_item);
 132     }
 133 }
 134 
 135 static void del_usermenu_item(unsigned int btn)
 136 {
 137     gui_menu_erase_and_redraw();
 138     if (btn == MBOX_BTN_YES)
 139     {
 140         int i, c;
 141 
 142         /*
 143          * Delete user menu entry by sliding all the lower valid/existing entries up.
 144          */
 145         CMenuItem *items = (CMenuItem*)user_submenu.menu;
 146 
 147         for (c = 1; c < USER_MENU_ITEMS + 1; c++)
 148         {
 149             if (items[c].text == mod_menu_item.text)
 150             {
 151                 for (i = c; items[i].text; i++)
 152                 {
 153                     items[i] = items[i+1];
 154 
 155                     if (conf.user_menu_vars.items[i-1].script_file)
 156                         free(conf.user_menu_vars.items[i-1].script_file);
 157                     conf.user_menu_vars.items[i-1].script_file = conf.user_menu_vars.items[i].script_file;
 158                     conf.user_menu_vars.items[i].script_file = 0;
 159 
 160                     if (conf.user_menu_vars.items[i-1].script_title)
 161                         free(conf.user_menu_vars.items[i-1].script_title);
 162                     conf.user_menu_vars.items[i-1].script_title = conf.user_menu_vars.items[i].script_title;
 163                     conf.user_menu_vars.items[i].script_title = 0;
 164                 }
 165 
 166                 camera_info.state.user_menu_has_changed = 1;
 167 
 168                 if (curr_menu->title == LANG_MENU_USER_MENU)
 169                 {
 170                     if (gui_menu_curr_item >= gui_menu_rows())
 171                         gui_menu_curr_item--;
 172                 }
 173 
 174                 return;
 175             }
 176         }
 177     }
 178 }
 179 
 180 static void del_usermenu()
 181 {
 182     if (inUserMenu(gui_menu_curr_item))
 183     {
 184         mod_menu_item = curr_menu->menu[gui_menu_curr_item];
 185         sprintf(msgbuf, lang_str(LANG_USER_MENU_DEL), lang_str(mod_menu_item.text));
 186         gui_mbox_init(LANG_INFORMATION, (int)msgbuf, MBOX_BTN_YES_NO|MBOX_DEF_BTN1|MBOX_TEXT_CENTER, del_usermenu_item);
 187     }
 188 }
 189 
 190 static void move_usermenu_item(int* cur_menu_item_indx, int dir)
 191 {
 192     int src_index, dst_index ;
 193     char *tbuff;
 194 
 195     src_index = *cur_menu_item_indx ;
 196     dst_index = *cur_menu_item_indx + dir;    
 197         
 198     // Move current user menu item up (dir = -1) or down (dir = 1)
 199     CMenuItem *items = (CMenuItem*)user_submenu.menu;
 200         
 201     CMenuItem tmp_menu_item = items[dst_index];
 202     items[dst_index] = items[src_index];
 203     items[src_index] = tmp_menu_item;
 204     
 205     src_index--; dst_index--;
 206    
 207     tbuff = conf.user_menu_vars.items[dst_index].script_file;
 208     conf.user_menu_vars.items[dst_index].script_file = conf.user_menu_vars.items[src_index].script_file;    
 209     conf.user_menu_vars.items[src_index].script_file = tbuff;
 210             
 211     tbuff = conf.user_menu_vars.items[dst_index].script_title;
 212     conf.user_menu_vars.items[dst_index].script_title = conf.user_menu_vars.items[src_index].script_title;    
 213     conf.user_menu_vars.items[src_index].script_title = tbuff;
 214         
 215     *cur_menu_item_indx += dir;
 216 
 217     gui_menu_erase_and_redraw();
 218     camera_info.state.user_menu_has_changed = 1;
 219 }
 220 
 221 static void move_usermenu_item_up(int* cur_menu_item_indx)
 222 {
 223     /*
 224      * Move entry up
 225      */
 226     if (*cur_menu_item_indx > 1)
 227         move_usermenu_item(cur_menu_item_indx, -1);
 228 }
 229 
 230 static void move_usermenu_item_down(int* cur_menu_item_indx)
 231 {
 232     // don't allow moving link to main menu
 233     if (*cur_menu_item_indx == 0)
 234         return;
 235 
 236     /*
 237      * Move entry down below next entry if next entry is not empty
 238      */
 239     if((*cur_menu_item_indx < (USER_MENU_ITEMS)) && (user_submenu.menu[*cur_menu_item_indx +1].text))
 240         move_usermenu_item(cur_menu_item_indx, 1);
 241 }
 242 
 243 static void add_extern_to_user_menu(const char* fname, char* title, char sym, short type, int* func)
 244 {
 245     int i;
 246     /*
 247      * Insert script/module info at end of existing entries
 248      */
 249     CMenuItem *items = (CMenuItem*)user_submenu.menu;
 250     gui_menu_erase_and_redraw();
 251 
 252     for(i = 1; i < USER_MENU_ITEMS + 1; i++)
 253     {
 254         if (!items[i].text)   // insert script/module title & full filename in next available spot 
 255         {
 256             if (conf.user_menu_vars.items[i-1].script_file == 0)
 257                 conf.user_menu_vars.items[i-1].script_file = malloc(CONF_STR_LEN);
 258             strcpy(conf.user_menu_vars.items[i-1].script_file, fname);
 259             if (conf.user_menu_vars.items[i-1].script_title == 0)
 260                 conf.user_menu_vars.items[i-1].script_title = malloc(CONF_STR_LEN);
 261             strcpy(conf.user_menu_vars.items[i-1].script_title, title);
 262 
 263             items[i].symbol = sym;
 264             items[i].opt_len = 0;
 265             items[i].type = type;
 266             items[i].text = (int) conf.user_menu_vars.items[i-1].script_title;
 267             items[i].value = func;
 268             items[i].arg = (int) conf.user_menu_vars.items[i-1].script_file;
 269             
 270             sprintf(msgbuf,lang_str(LANG_USER_MENU_ITEM_ADDED), lang_str(items[i].text));
 271             gui_mbox_init(LANG_MENU_USER_MENU, (int)msgbuf, MBOX_BTN_OK|MBOX_TEXT_CENTER|MBOX_FUNC_RESTORE, NULL);
 272             camera_info.state.user_menu_has_changed = 1;
 273             return;
 274         }
 275     }
 276     gui_mbox_init(LANG_MENU_USER_MENU, LANG_USER_MENU_FULL, MBOX_BTN_OK|MBOX_TEXT_CENTER, NULL);
 277 }
 278 
 279 static void add_script_to_user_menu(const char* fname, char* title)
 280 {
 281     add_extern_to_user_menu(fname, title, 0x35, MENUITEM_PROC, (int*)gui_load_user_menu_script);
 282 }
 283 
 284 static void add_module_to_user_menu(const char* fname, char* title)
 285 {
 286     add_extern_to_user_menu(fname, title, 0x28, MENUITEM_PROC|MENUITEM_USER_MODULE, (int*)module_run);
 287 }
 288 
 289 //-------------------------------------------------------------------
 290 static void gui_menu_set_curr_menu(CMenu *menu_ptr, int top_item, int curr_item)
 291 {
 292     curr_menu = menu_ptr;
 293     gui_menu_top_item = top_item;
 294     gui_menu_curr_item = curr_item;
 295     while (!validrow(gui_menu_curr_item))
 296     {
 297         ++gui_menu_curr_item;
 298     }
 299 }
 300 
 301 //-------------------------------------------------------------------
 302 static void gui_init(CMenu *menu_ptr) {
 303 
 304     if (menu_ptr) {
 305         gui_menu_set_curr_menu(menu_ptr, 0, 0);
 306         gui_menu_stack_ptr = 0;
 307     }
 308 
 309     num_lines = camera_screen.height/rbf_font_height()-1;
 310     x = camera_screen.disp_left + camera_screen.menu_border_width;
 311     w = camera_screen.disp_width - camera_screen.menu_border_width;
 312     len_bool = rbf_str_width("\x95");
 313     len_space = rbf_char_width(' ');
 314 
 315     gui_menu_redraw=2;
 316 }
 317 
 318 //-------------------------------------------------------------------
 319 // Return to previous menu on stack
 320 void gui_menu_back() {
 321     if (gui_menu_stack_ptr > 0)
 322     {
 323         gui_menu_stack_ptr--;
 324         gui_menu_set_curr_menu(gui_menu_stack[gui_menu_stack_ptr].menu, gui_menu_stack[gui_menu_stack_ptr].toppos, gui_menu_stack[gui_menu_stack_ptr].curpos);
 325         gui_menu_erase_and_redraw();
 326     }
 327 }
 328 
 329 //-------------------------------------------------------------------
 330 // Helper functions for gui_uedit_kbd_process
 331 //  common code blocks extracted to try and make it easier to understand
 332 
 333 // Open a sub-menu
 334 void gui_activate_sub_menu(CMenu *sub_menu)
 335 {
 336     // push current menu on stack
 337     gui_menu_stack[gui_menu_stack_ptr].menu = curr_menu;
 338     gui_menu_stack[gui_menu_stack_ptr].curpos = gui_menu_curr_item;
 339     gui_menu_stack[gui_menu_stack_ptr].toppos = gui_menu_top_item;
 340 
 341     gui_menu_set_curr_menu(sub_menu, 0, 0);
 342 
 343     gui_menu_stack_ptr++;
 344 
 345     // FIXME check on stack overrun;
 346     if (gui_menu_stack_ptr > MENUSTACK_MAXDEPTH)
 347     {
 348         draw_string(1, 0, "E1", MAKE_COLOR(COLOR_RED, COLOR_YELLOW));
 349         gui_menu_stack_ptr = 0;
 350     }
 351 
 352     // Force full redraw
 353     gui_menu_erase_and_redraw();
 354 }
 355 
 356 // Open a sub-menu
 357 static void select_sub_menu()
 358 {
 359     gui_activate_sub_menu((CMenu*)(curr_menu->menu[gui_menu_curr_item].value));
 360 }
 361 
 362 // Move up / down in menu, adjusting scroll position if needed
 363 //   increment = -1 to move up, 1 to move down
 364 static void gui_menu_updown(int increment)
 365 {
 366     int c, j;
 367 
 368     if (count == 0) return;
 369 
 370     // Determine number of rows to move (1 or 4)
 371     if (camera_info.state.is_shutter_half_press || kbd_is_key_pressed(KEY_ZOOM_IN) || kbd_is_key_pressed(KEY_ZOOM_OUT)) c=4; else c=1;
 372 
 373     for (j = 0; j < c; ++j)
 374     {
 375         do
 376         {
 377             // Move to next or previous row
 378             gui_menu_curr_item += increment;
 379 
 380             if (gui_menu_curr_item < 0)                                     // Off top, move to bottom
 381             {
 382                 gui_menu_curr_item = gui_menu_rows() - 1;
 383                 gui_menu_top_item = gui_menu_curr_item - num_lines + 1;
 384             }
 385             else if (gui_menu_curr_item >= gui_menu_rows())                 // Off bottom, move to top
 386             {
 387                 gui_menu_curr_item = gui_menu_top_item = 0;
 388             }
 389             else if (increment == 1)                                        // Still in menu, if moving down adjust scroll if needed
 390             {
 391                 if (gui_menu_curr_item - gui_menu_top_item >= num_lines - 1)
 392                 {
 393                     gui_menu_top_item = gui_menu_curr_item - num_lines + 2;
 394                     if (gui_menu_top_item + num_lines > gui_menu_rows()) gui_menu_top_item = gui_menu_rows() - num_lines;
 395                 }
 396             }
 397             else                                                            // Still in menu, and moving up, adjust scroll
 398             {
 399                 if (gui_menu_curr_item == gui_menu_top_item) 
 400                     --gui_menu_top_item;
 401             }
 402 
 403             // Check in case scroll moved off top of menu
 404             if (gui_menu_top_item < 0) gui_menu_top_item = 0;
 405         } while (!validrow(gui_menu_curr_item));
 406 
 407         // Redraw menu if needed
 408         if (gui_menu_redraw == 0) gui_menu_redraw=1;
 409     }
 410 }
 411 
 412 //-------------------------------------------------------------------
 413 // Draw menu scroll bar if needed, and title bar
 414 static void gui_draw_initial()
 415 { 
 416     count = gui_menu_disp_rows();
 417 
 418     if (count > num_lines)
 419     {
 420         y = ((camera_screen.height-(num_lines-1)*rbf_font_height())>>1);
 421         wplus = 8; 
 422         // scrollbar background 
 423         draw_rectangle((x+w), y, (x+w)+wplus, y+num_lines*rbf_font_height()-1, MAKE_COLOR(BG_COLOR(user_color(conf.menu_color)), BG_COLOR(user_color(conf.menu_color))), RECT_BORDER0|DRAW_FILLED);
 424     }
 425     else
 426     {
 427         wplus = 0;
 428         if (conf.menu_center)
 429         {
 430             y = (camera_screen.height-(count-1)*rbf_font_height())>>1; 
 431         }
 432         else
 433         {
 434             y = ((camera_screen.height-(num_lines-1)*rbf_font_height())>>1);  
 435         }
 436     }
 437 
 438     rbf_draw_menu_header(x, y-rbf_font_height(), w+wplus, (conf.menu_symbol_enable)?curr_menu->symbol:0, lang_str(curr_menu->title), MAKE_COLOR(COLOR_RED,COLOR_WHITE));
 439 }
 440 
 441 //-------------------------------------------------------------------
 442 
 443 // Local variables used by menu draw functions
 444 static int imenu, yy, xx, symbol_width;
 445 static twoColors cl, cl_symbol;
 446 
 447 // Common code extracted from gui_draw for displaying the symbol on the left
 448 static void gui_draw_symbol(int num_symbols)
 449 {
 450     if (conf.menu_symbol_enable)
 451     {
 452         xx += rbf_draw_char(xx, yy, ' ', cl_symbol);
 453         xx += symbol_width = rbf_draw_symbol(xx, yy, curr_menu->menu[imenu].symbol, cl_symbol);
 454         symbol_width = (symbol_width * num_symbols) + len_space;
 455     }
 456     else
 457     {
 458         symbol_width = 0;
 459     }
 460 
 461     xx += rbf_draw_char(xx, yy, ' ', cl);
 462 }
 463 
 464 // Common code extracted from gui_draw for displaying an int, enum or bool value on the right
 465 static void gui_draw_value()
 466 {
 467     gui_draw_symbol(1);
 468     xx += rbf_draw_string_len(xx, yy, w-len_space*4, lang_str(curr_menu->menu[imenu].text), cl);
 469 }
 470 
 471 // Common code extracted from gui_draw for displaying a text menu string
 472 static void gui_draw_text(char *str, int num_symbols)
 473 {
 474     gui_draw_symbol(num_symbols);
 475     xx += rbf_draw_string_len(xx, yy, w-len_space-len_space-symbol_width, str, cl);
 476     if ((num_symbols == 2) && conf.menu_symbol_enable)
 477         xx += rbf_draw_symbol(xx, yy, 0x52, cl_symbol);
 478     rbf_draw_char(xx, yy, ' ', cl);
 479 }
 480 
 481 // Common code extracted from gui_draw for displaying an int or enum that can be enabled/disabled
 482 static void gui_draw_state_value(CMenuItem *c)
 483 {
 484     int text = curr_menu->menu[imenu].text;
 485     if (c[0].text != 0)
 486         text = c[0].text;
 487 
 488     int wid = w-len_space-len_space;
 489 
 490     gui_draw_symbol(1);
 491     xx += rbf_draw_string_len(xx, yy, wid, lang_str(text), cl);
 492 }
 493 
 494 //-------------------------------------------------------------------
 495 static void gui_draw(int enforce_redraw)
 496 {
 497     int i, j;
 498 
 499         if ( enforce_redraw )
 500                 gui_menu_redraw = 2;
 501 
 502     if (gui_menu_redraw)
 503     {
 504         if (gui_menu_redraw==2)
 505             gui_draw_initial();
 506 
 507         gui_menu_redraw=0;
 508 
 509         for (imenu=gui_menu_top_item, i=0, yy=y; curr_menu->menu[imenu].text && i<num_lines; ++imenu)
 510         {
 511             if (validrow(imenu))
 512             {
 513                 cl = user_color((gui_menu_curr_item==imenu) ? conf.menu_cursor_color : conf.menu_color);
 514                 if (inUserMenu(imenu) && (curr_menu->title != LANG_MENU_USER_MENU))
 515                     cl = MAKE_COLOR(BG_COLOR(cl),COLOR_GREEN);
 516                 cl_symbol = (gui_menu_curr_item==imenu)?MAKE_COLOR(BG_COLOR(cl),FG_COLOR(user_color(conf.menu_symbol_color))):user_color(conf.menu_symbol_color);
 517 
 518                 xx = x;
 519 
 520                 switch (curr_menu->menu[imenu].type & MENUITEM_MASK)
 521                 {
 522                 case MENUITEM_STATE_VAL_PAIR:
 523                     gui_draw_state_value((CMenuItem*)(curr_menu->menu[imenu].value));
 524                     break;
 525                 case MENUITEM_BOOL:
 526                 case MENUITEM_INT:
 527                 case MENUITEM_ENUM:
 528                 case MENUITEM_ENUM2:
 529                     gui_draw_value();
 530                     break;
 531                 case MENUITEM_SUBMENU_PROC:
 532                 case MENUITEM_SUBMENU:
 533                     sprintf(msgbuf, "%s%s", lang_str(curr_menu->menu[imenu].text),(conf.menu_symbol_enable)?"":" ->");
 534                     gui_draw_text(msgbuf,2);
 535                     break;
 536                 case MENUITEM_UP:
 537                     sprintf(msgbuf, "%s%s", (conf.menu_symbol_enable)?"":"<- ", lang_str(curr_menu->menu[imenu].text));
 538                     gui_draw_text(msgbuf,1);
 539                     break;
 540                 case MENUITEM_PROC:
 541                     gui_draw_text(lang_str(curr_menu->menu[imenu].text),1);
 542                     break;
 543                 case MENUITEM_COLOR_FG:
 544                 case MENUITEM_COLOR_BG:
 545                     gui_draw_symbol(1);
 546                     xx+=rbf_draw_string_len(xx, yy, w-len_space-symbol_width, lang_str(curr_menu->menu[imenu].text), cl);
 547                     break;
 548                 }
 549 
 550                 yy += rbf_font_height();
 551                 i++;
 552             }
 553         }
 554 
 555         // scrollbar
 556         if (count > num_lines)
 557         {
 558             i = num_lines*rbf_font_height()-1 -1;           // full height
 559             j = i*num_lines/count;                          // bar height
 560             if (j<20) j=20;
 561             i = (i-j)*((gui_menu_curr_item<0)?0:gui_menu_curr_item)/(count-1);   // top pos
 562             draw_rectangle((x+w)+2, y+1,   (x+w)+6, y+1+i,                             MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED|RECT_ROUND_CORNERS);
 563             draw_rectangle((x+w)+2, y+i+j, (x+w)+6, y+num_lines*rbf_font_height()-1-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED|RECT_ROUND_CORNERS);
 564             draw_rectangle((x+w)+2, y+1+i, (x+w)+6, y+i+j,                             MAKE_COLOR(COLOR_WHITE, COLOR_WHITE), RECT_BORDER0|DRAW_FILLED|RECT_ROUND_CORNERS);
 565         }
 566     }
 567 }
 568 
 569 //-------------------------------------------------------------------
 570 // Menu button handler for Menu mode
 571 static void gui_uedit_kbd_process_menu_btn()
 572 {
 573     if (curr_menu->title == LANG_MENU_USER_MENU)
 574     {
 575         running = 0;
 576         gui_set_mode(gui_mode_old);
 577     }
 578     else
 579     {
 580         gui_menu_erase_and_redraw();
 581         gui_init(&user_submenu);
 582     }
 583 }
 584 
 585 //-------------------------------------------------------------------
 586 #define UEDIT_MENU      1
 587 #define UEDIT_SCRIPT    2
 588 #define UEDIT_MODULE    4
 589 #define UEDIT_REMOVE    8
 590 
 591 static struct mpopup_item popup_uedit[]= {
 592         { UEDIT_MENU,           LANG_USER_MENU_ITEMS },
 593         { UEDIT_SCRIPT,         LANG_MENU_USER_MENU_SCRIPT_ADD },
 594         { UEDIT_MODULE,         LANG_MENU_USER_MENU_MODULE_ADD },
 595         { UEDIT_REMOVE,         LANG_MENU_USER_MENU_REMOVE },
 596         { 0,                    0 },
 597 };
 598 
 599 const char* skip_whitespace(const char* p)  { while (*p==' ' || *p=='\t') p++; return p; }                                  // Skip past whitespace
 600 const char* skip_toeol(const char* p)       { while (*p && *p!='\r' && *p!='\n') p++; return p; }                           // Skip to end of line
 601 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
 602 
 603 static int chk_ext(char *ext, char *tst)
 604 {
 605     if (ext && (strlen(ext) == strlen(tst)+1))
 606     {
 607         int i;
 608         for (i=0; i<strlen(tst); i++)
 609             if (toupper(ext[i+1]) != toupper(tst[i]))
 610                 return 0;
 611         return 1;
 612     }
 613     return 0;
 614 }
 615 
 616 static void gui_uedit_script_selected(const char *fn)
 617 {
 618     if (fn)
 619     {
 620         char *ext = strrchr(fn,'.');
 621         if (chk_ext(ext,"lua") || chk_ext(ext,"bas"))
 622         {
 623             char* buf;
 624 
 625             buf = load_file(fn, 0, 1);
 626 
 627             if (buf)
 628             {
 629                 char script_title[36];
 630                 register const char *ptr = buf;
 631                 char *c;
 632 
 633                 // Build title
 634 
 635                 c=strrchr(fn, '/');
 636                 strncpy(script_title, (c)?c+1:fn, sizeof(script_title));
 637                 script_title[sizeof(script_title)-1]=0;
 638 
 639                 while (ptr[0])
 640                 {
 641                     ptr = skip_whitespace(ptr);
 642                     if (ptr[0]=='@') {
 643                         if (strncmp("@title", ptr, 6)==0)
 644                         {
 645                             ptr = ptr + 6;
 646                             register int i=0;
 647 
 648                             ptr = skip_whitespace(ptr);
 649                             while (i<(sizeof(script_title)-1) && ptr[i] && ptr[i]!='\r' && ptr[i]!='\n')
 650                             {
 651                                 script_title[i]=ptr[i];
 652                                 ++i;
 653                             }
 654                             script_title[i]=0;
 655                             break;
 656                         }
 657                     }
 658                     ptr = skip_eol(ptr);
 659                 }
 660 
 661                 add_script_to_user_menu(fn, script_title);
 662                 free(buf);
 663             }
 664         }
 665     }
 666 }
 667 
 668 static void gui_uedit_module_selected(const char *fn)
 669 {
 670     if (fn)
 671     {
 672         char *ext = strrchr(fn,'.');
 673         if (chk_ext(ext,"flt"))
 674         {
 675             _version_t v = ANY_VERSION;
 676             flat_hdr* mod = module_preload(fn, fn, v);  // Pass fn as both path and name (file browser sends us full path to module)
 677             if (mod > 0)
 678             {
 679                 if (mod->_module_info->lib->run != 0)   // Simple Module?
 680                 {
 681                     char *n;
 682                     if (mod->_module_info->moduleName < 0)
 683                         n = lang_str(-mod->_module_info->moduleName);
 684                     else
 685                         n = (char*)mod->_module_info->moduleName;
 686                     add_module_to_user_menu(fn, n);
 687                     free(mod);
 688                 }
 689                 else
 690                 {
 691                     sprintf(msgbuf, lang_str(LANG_MODULE_NOT_SIMPLE), fn);
 692                     gui_mbox_init(LANG_ERROR, (int)msgbuf, MBOX_BTN_OK|MBOX_TEXT_CENTER|MBOX_FUNC_RESTORE, NULL);
 693                 }
 694             }
 695         }
 696     }
 697 }
 698 
 699 static void uedit_set(unsigned int actn)
 700 {
 701     switch (actn)
 702     {
 703         case UEDIT_MENU:
 704             gui_init(&root_menu);
 705             break;
 706         case UEDIT_SCRIPT:
 707             libfselect->file_select(LANG_MENU_USER_MENU_SCRIPT_ADD, conf.script_file, "A/CHDK/SCRIPTS", gui_uedit_script_selected);
 708             break;
 709         case UEDIT_MODULE:
 710             libfselect->file_select(LANG_MENU_USER_MENU_MODULE_ADD, "A/CHDK/MODULES", "A/CHDK/MODULES", gui_uedit_module_selected);
 711             break;
 712         case UEDIT_REMOVE:
 713             del_usermenu();
 714             break;
 715     }
 716     gui_menu_erase_and_redraw();
 717 }
 718 
 719 // Process button presses when in GUI_MODE_MENU mode
 720 static int gui_uedit_kbd_process() {
 721 
 722     switch (kbd_get_autoclicked_key() | get_jogdial_direction())
 723     {
 724         case JOGDIAL_LEFT:
 725         case KEY_UP:
 726             gui_menu_updown(-1);
 727             break;
 728         case JOGDIAL_RIGHT:
 729         case KEY_DOWN: 
 730             gui_menu_updown(1);
 731             break;
 732         case FRONTDIAL_LEFT:
 733         case KEY_LEFT:
 734             if (curr_menu->title == LANG_MENU_USER_MENU)
 735             {
 736                 move_usermenu_item_up(&gui_menu_curr_item);
 737             }
 738             else
 739             {
 740                 del_usermenu();
 741             }
 742             break;
 743         case KEY_SHOOT_HALF:
 744         case KEY_ERASE:
 745             del_usermenu();
 746             break;
 747         case FRONTDIAL_RIGHT:
 748         case KEY_RIGHT:
 749             if (curr_menu->title == LANG_MENU_USER_MENU)
 750             {
 751                 move_usermenu_item_down(&gui_menu_curr_item);
 752             }
 753             else
 754             {
 755                 add_usermenu();
 756             }
 757             break;
 758         case KEY_SET:
 759             if (curr_menu->title == LANG_MENU_USER_MENU)
 760             {
 761                 libmpopup->show_popup( popup_uedit, UEDIT_MENU|UEDIT_SCRIPT|UEDIT_MODULE|UEDIT_REMOVE, uedit_set);
 762             }
 763             else
 764             {
 765                 switch (curr_menu->menu[gui_menu_curr_item].type & MENUITEM_MASK)
 766                 {
 767                     case MENUITEM_UP:
 768                         gui_menu_back();
 769                         break;
 770                     case MENUITEM_SUBMENU:
 771                         select_sub_menu();
 772                         break;
 773                 }
 774             }
 775             break;
 776         case KEY_DISPLAY:
 777             gui_menu_back();
 778             break;
 779     }
 780 
 781     return 0;
 782 }
 783 
 784 //-------------------------------------------------------------------
 785 // GUI handler for menus
 786 static gui_handler ueditGuiHandler = { GUI_MODE_MODULE, gui_draw, gui_uedit_kbd_process, gui_uedit_kbd_process_menu_btn, 0, 0 };
 787 //-------------------------------------------------------------------
 788 
 789 
 790 // =========  MODULE INIT =================
 791 #include "simple_module.h"
 792 
 793 int _run()
 794 {
 795     running = 1;
 796     gui_menu_redraw = 2;
 797     gui_init(&user_submenu);
 798     gui_mode_old = gui_set_mode(&ueditGuiHandler);
 799 
 800     return 0;
 801 }
 802 
 803 int _module_can_unload()
 804 {
 805     return running == 0;
 806 }
 807 
 808 int _module_exit_alt()
 809 {
 810     running = 0;
 811     return 0;
 812 }
 813 
 814 int _module_unload()
 815 {
 816     conf_save();
 817     return 0;
 818 }
 819 
 820 libsimple_sym _librun =
 821 {
 822     {
 823         0,
 824         _module_unload,
 825         _module_can_unload,
 826         _module_exit_alt,
 827         _run
 828     }
 829 };
 830 
 831 /******************** Module Information structure ******************/
 832 
 833 ModuleInfo _module_info =
 834 {
 835     MODULEINFO_V1_MAGICNUM,
 836     sizeof(ModuleInfo),
 837     SIMPLE_MODULE_VERSION,              // Module version
 838 
 839     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,                       // Requirements of CHDK version
 840     ANY_PLATFORM_ALLOWED,               // Specify platform dependency
 841 
 842     -LANG_MENU_USER_MENU_EDIT,
 843     MTYPE_EXTENSION,
 844 
 845     &_librun.base,
 846 
 847     CONF_VERSION,               // CONF version
 848     CAM_SCREEN_VERSION,         // CAM SCREEN version
 849     ANY_VERSION,                // CAM SENSOR version
 850     ANY_VERSION,                // CAM INFO version
 851 };

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