root/core/gui_menu.c

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

DEFINITIONS

This source file includes following definitions.
  1. find_menu_item
  2. menu_get_increment_factor
  3. menu_set_increment_factor
  4. menu_increment_factor_string
  5. menu_calc_max_increment_factor
  6. increment_factor
  7. decrement_factor
  8. gui_menu_set_curr_menu
  9. get_curr_menu
  10. gui_menu_init
  11. gui_menu_rows
  12. gui_menu_erase_and_redraw
  13. gui_menu_cancel_redraw
  14. gui_menu_color_selected
  15. gui_menu_back
  16. do_callback
  17. update_int_value
  18. update_bool_value
  19. update_enum_value
  20. isText
  21. gui_activate_sub_menu
  22. select_sub_menu
  23. select_proc
  24. gui_menu_updown
  25. gui_menu_touch_handler
  26. gui_menu_kbd_process
  27. gui_menu_draw_initial
  28. gui_menu_draw_symbol
  29. gui_set_int_cursor
  30. gui_menu_draw_value
  31. gui_menu_draw_text
  32. factor_disp_len
  33. get_int_disp_string
  34. gui_menu_draw_state_value
  35. menu_text
  36. gui_menu_draw
  37. gui_menu_kbd_process_menu_btn

   1 #include "camera_info.h"
   2 #include "conf.h"
   3 #include "keyboard.h"
   4 #include "font.h"
   5 #include "lang.h"
   6 #include "gui.h"
   7 #include "gui_draw.h"
   8 #include "gui_menu.h"
   9 #include "gui_user_menu.h"
  10 #include "gui_lang.h"
  11 #include "ctype.h"
  12 
  13 #include "gui_palette.h"
  14 
  15 //-------------------------------------------------------------------
  16 #define MENUSTACK_MAXDEPTH  4
  17 
  18 //-------------------------------------------------------------------
  19 typedef struct {
  20     CMenu       *menu;
  21     int         curpos;
  22     int         toppos;
  23 } CMenuStacked;
  24 
  25 //-------------------------------------------------------------------
  26 
  27 static CMenu        *curr_menu;
  28 static CMenuStacked gui_menu_stack[MENUSTACK_MAXDEPTH];
  29 static unsigned int gui_menu_stack_ptr;
  30 static int          gui_menu_curr_item;
  31 static int          gui_menu_top_item;
  32 static int          gui_menu_redraw;
  33 
  34 static int          count;
  35 static int          x, y;
  36 static int          w, wplus, num_lines;
  37 static int          len_bool, len_int, len_enum, len_space, len_br1, len_br2, cl_rect;
  38 static int          int_incr = 1;
  39 static confColor    *item_color;
  40 static int          item_color_type;    // MENUITEM_COLOR_FG / MENUITEM_COLOR_BG
  41 
  42 //-------------------------------------------------------------------
  43 CMenuItem* find_menu_item(CMenu *curr_menu, int itemid )
  44 {
  45     int gui_menu_curr_item;
  46     CMenuItem* rv=0;
  47 
  48     if ( itemid==0 )
  49         return 0;
  50 
  51     gui_menu_curr_item = 0;
  52     while(curr_menu->menu[gui_menu_curr_item].text) {
  53         if ( lang_strhash31(curr_menu->menu[gui_menu_curr_item].text) == (unsigned)itemid){
  54             return (CMenuItem*) &(curr_menu->menu[gui_menu_curr_item]);
  55         }
  56         if ((curr_menu->menu[gui_menu_curr_item].type & MENUITEM_MASK) == MENUITEM_SUBMENU)
  57         {
  58             if (curr_menu->menu[gui_menu_curr_item].text != LANG_MENU_USER_MENU) {
  59                 rv = find_menu_item((CMenu*)(curr_menu->menu[gui_menu_curr_item].value), itemid);
  60                 if ( rv )
  61                     return rv;
  62             }
  63         }
  64         gui_menu_curr_item++;
  65     }
  66     return 0;
  67 }
  68 
  69 //-------------------------------------------------------------------
  70 // Functions to access increment factor from other code
  71 // Used for quick SD override in ALT mode without entering menu
  72 
  73 int menu_get_increment_factor()
  74 {
  75     return int_incr;
  76 }
  77 
  78 void menu_set_increment_factor(int n)
  79 {
  80     int_incr = n;
  81 }
  82 
  83 // Generate display string for int_incr value
  84 char *menu_increment_factor_string()
  85 {
  86     static char buf[8];
  87     buf[0] = 0;
  88     if (int_incr >= 1000000)
  89         sprintf(buf, "\xb1%dM",int_incr/1000000);
  90     else if (int_incr >= 1000)
  91         sprintf(buf, "\xb1%dK",int_incr/1000);
  92     else
  93         sprintf(buf, "\xb1%d",int_incr);
  94     return buf;
  95 }
  96 
  97 // Given a maximum value for a int menu item, calculate the largest int_incr value
  98 int menu_calc_max_increment_factor(int max_value)
  99 {
 100     int max = 1;
 101     while (max_value/10 != 0)
 102     {
 103         max *= 10;
 104         max_value /= 10;
 105     }
 106     return max;
 107 }
 108 
 109 //-------------------------------------------------------------------
 110 // Adjust the int_incr value up or down - adjust limits based on current
 111 // menu item type and settings
 112 
 113 #define MAX(a,b)    ((a>=b)?a:b)
 114 
 115 static int increment_factor()
 116 {
 117     // Increase int_incr
 118     // Returns 1 if value changed.
 119 
 120     // Get info about the current menu item
 121     int item_flags = curr_menu->menu[gui_menu_curr_item].type;
 122     int item_type = item_flags & MENUITEM_MASK;
 123     int item_arg = curr_menu->menu[gui_menu_curr_item].arg;
 124     int item_val = *(curr_menu->menu[gui_menu_curr_item].value);
 125     // If state / value menu pair get info from value entry
 126     if (item_type == MENUITEM_STATE_VAL_PAIR)
 127     {
 128         CMenuItem *c = (CMenuItem*)(curr_menu->menu[gui_menu_curr_item].value);
 129         item_flags = c[0].type;
 130         item_type = item_flags & MENUITEM_MASK;
 131         item_arg = c[0].arg;
 132         item_val = *(c[0].value);
 133     }
 134 
 135     // Calculate max allowed value for int_incr
 136     // Default is 1000000 for DECIMAL, 10000 for positive int values, 1000 for negative values or 1 otherwise
 137     int max = (item_flags & MENUITEM_DECIMAL) ? 100000 : (item_type == MENUITEM_INT) ? ((item_val < 0) ? 1000 : 10000) : 1;
 138 
 139     // If an int value has a defined MIN / MAX range then adjust int_incr max to fit the range
 140     int vmax = 0;
 141     if ( item_flags & MENUITEM_F_MINMAX )
 142     {
 143         if ( item_flags & MENUITEM_F_UNSIGNED )
 144         {
 145             vmax = MAX(MENU_MIN_UNSIGNED(item_arg),MENU_MAX_UNSIGNED(item_arg));
 146         }
 147         else
 148         {
 149             vmax = MAX(abs(MENU_MIN_SIGNED(item_arg)),abs(MENU_MAX_SIGNED(item_arg)));
 150         }
 151     }
 152 
 153     // Default for SD type (item_arg holds max allowed value)
 154     if (item_flags & MENUITEM_SD_INT)
 155     {
 156         vmax = item_arg;
 157     }
 158 
 159     // If a max value has been set adjust accordingly
 160     if (vmax > 0)
 161     {
 162         max = menu_calc_max_increment_factor(vmax);
 163     }
 164 
 165     // Default for HH:MM:SS type
 166     if (item_flags & MENUITEM_HHMMSS)
 167     {
 168         max = 100;
 169     }
 170 
 171     // Adjust value
 172     if (int_incr < max)
 173     {
 174         int_incr *= 10;
 175         return 1;
 176     }
 177     if (int_incr > max)
 178     {
 179         int_incr = max;
 180         return 1;
 181     }
 182 
 183     return 0;
 184 }
 185 
 186 static int decrement_factor()
 187 {
 188     // Decrease int_incr
 189     // Returns 1 if value changed.
 190 
 191     if (int_incr > 1)
 192     {
 193         int_incr /= 10;
 194         return 1;
 195     }
 196     return 0;
 197 }
 198 
 199 //-------------------------------------------------------------------
 200 static void gui_menu_set_curr_menu(CMenu *menu_ptr, int top_item, int curr_item) {
 201     curr_menu = menu_ptr;
 202     gui_menu_top_item = top_item;
 203     gui_menu_curr_item = curr_item;
 204 }
 205 
 206 CMenu* get_curr_menu()
 207 {
 208     return curr_menu;
 209 }
 210 
 211 //-------------------------------------------------------------------
 212 void gui_menu_init(CMenu *menu_ptr) {
 213 
 214     if (menu_ptr) {
 215         if (conf.menu_select_first_entry)
 216             gui_menu_set_curr_menu(menu_ptr, 0, 0);
 217         else 
 218             gui_menu_set_curr_menu(menu_ptr, 0, -1);
 219         gui_menu_stack_ptr = 0;
 220 
 221         // Set active Tv override menu entry if present
 222         extern void set_tv_override_menu(CMenu *menu);
 223         set_tv_override_menu(curr_menu);
 224     }
 225 
 226     len_bool = rbf_str_width("\x95");
 227     len_int = rbf_str_width("99999");
 228     len_enum = rbf_str_width("WUBfS3a");
 229     len_space = rbf_char_width(' ');
 230     len_br1 = rbf_char_width('[');
 231     len_br2 = rbf_char_width(']');
 232     cl_rect = rbf_font_height() - 4;
 233     int_incr = 1;
 234 
 235     gui_menu_redraw=2;
 236 }
 237 
 238 //-------------------------------------------------------------------
 239 static int gui_menu_rows()
 240 {
 241     int n;
 242     // Count the number of rows in current menu
 243     for(n = 0; curr_menu->menu[n].text; n++);
 244     return n;
 245 }
 246 
 247 //-------------------------------------------------------------------
 248 // Full screen erase and redraw of menu
 249 void gui_menu_erase_and_redraw()
 250 {
 251     gui_menu_redraw = 2;
 252     gui_set_need_restore();
 253 }
 254 void gui_menu_cancel_redraw()
 255 {
 256     gui_menu_redraw = 0;
 257     gui_cancel_need_restore();
 258 }
 259 
 260 //-------------------------------------------------------------------
 261 // Function passed to gui_palette_init
 262 // This is called when a new color is selected to update the menu / config value
 263 static void gui_menu_color_selected(chdkColor clr)
 264 {
 265     if (item_color_type == MENUITEM_COLOR_FG)
 266     {
 267         item_color->fg = clr;
 268     }
 269     else
 270     {
 271         item_color->bg = clr;
 272     }
 273     gui_menu_erase_and_redraw();
 274 }
 275 
 276 //-------------------------------------------------------------------
 277 // Return to previous menu on stack
 278 void gui_menu_back()
 279 {
 280     if (gui_menu_stack_ptr > 0)
 281     {
 282         gui_menu_stack_ptr--;
 283         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);
 284         gui_menu_erase_and_redraw();
 285     }
 286     else
 287     {
 288         // 'Back' selected; but no menu to go back to
 289         // Occurs when script menu opened using 'Func/Set' button
 290         // Return to normal <ALT> mode.
 291         gui_set_mode(&altGuiHandler);
 292     }
 293 }
 294 
 295 //-------------------------------------------------------------------
 296 // Helper functions for gui_menu_kbd_process
 297 //  common code blocks extracted to try and make it easier to understand
 298 
 299 // After updating a value check for callback and on_change functions and call if necessary
 300 static void do_callback(const CMenuItem *mi)
 301 {
 302     if ((mi->type & MENUITEM_ARG_MASK) == MENUITEM_ARG_CALLBACK && mi->arg)
 303     {
 304         ((void (*)())(mi->arg))();
 305     }
 306 }
 307 
 308 // Update an 'int' value, direction = 1 for increment, -1 for decrement
 309 static void update_int_value(const CMenuItem *mi, int direction)
 310 {
 311     // do update
 312     *(mi->value) += int_incr * direction;
 313 
 314     // Limit new value to defined bounds
 315     if ((mi->type & MENUITEM_F_UNSIGNED) || (mi->type & MENUITEM_SD_INT))
 316     {
 317         if (*(mi->value) < 0) 
 318             *(mi->value) = 0;
 319 
 320         if ( mi->type & MENUITEM_F_MIN)
 321         {
 322             if (*(mi->value) < MENU_MIN_UNSIGNED(mi->arg)) 
 323                 *(mi->value) = MENU_MIN_UNSIGNED(mi->arg);
 324         }
 325     }
 326     else
 327     {
 328         if (*(mi->value) < -9999) 
 329             *(mi->value) = -9999;
 330 
 331         if ( mi->type & MENUITEM_F_MIN)
 332         {
 333             if (*(mi->value) < MENU_MIN_SIGNED(mi->arg)) 
 334                 *(mi->value) = MENU_MIN_SIGNED(mi->arg);
 335         }
 336     }
 337 
 338     int maxval = (mi->type & MENUITEM_SD_INT) ? 9999999 : 99999;
 339     if (*(mi->value) > maxval)
 340         *(mi->value) = maxval;
 341 
 342     if (mi->type & MENUITEM_F_UNSIGNED)
 343     {
 344         if ( mi->type & MENUITEM_F_MAX)
 345         {
 346             if (*(mi->value) > MENU_MAX_UNSIGNED(mi->arg)) 
 347                 *(mi->value) = MENU_MAX_UNSIGNED(mi->arg);
 348         }
 349     }
 350     else
 351     {
 352         if (mi->type & MENUITEM_F_MAX)
 353         {
 354             if (*(mi->value) > MENU_MAX_SIGNED(mi->arg)) 
 355                 *(mi->value) = MENU_MAX_SIGNED(mi->arg);
 356         }
 357     }
 358 
 359     // execute custom callback and on_change functions
 360     do_callback(mi);
 361 
 362     // force menu redraw
 363     gui_menu_redraw=1;
 364 }
 365 
 366 // Update a 'bool' value
 367 static void update_bool_value(const CMenuItem *mi)
 368 {
 369     // update value
 370     *(mi->value) = !(*(mi->value));
 371 
 372     // execute custom callback and on_change functions
 373     do_callback(mi);
 374 
 375     // force menu redraw
 376     gui_menu_redraw=1;
 377 }
 378 
 379 // Update an 'enum' value, direction = 1 for increment, -1 for decrement
 380 static void update_enum_value(const CMenuItem *mi, int direction)
 381 {
 382     // update value
 383     if (mi->value)
 384     {
 385         if (mi->type & (MENUITEM_DECIMAL | MENUITEM_SD_INT | MENUITEM_HHMMSS))
 386             direction *= int_incr;
 387         if ((mi->type & MENUITEM_MASK) == MENUITEM_ENUM)
 388         {
 389             ((const char* (*)(int change, int arg))(mi->value))(direction, mi->arg);
 390         }
 391         else
 392         {
 393             extern const char* gui_change_enum2(const CMenuItem *menu_item, int change);
 394             gui_change_enum2(mi, direction);
 395         }
 396     }
 397 
 398     // force menu redraw
 399     gui_menu_redraw=1;
 400 }
 401 
 402 static int isText(int n)
 403 {
 404     return (
 405             (curr_menu->menu[n].type & MENUITEM_MASK) == MENUITEM_TEXT ||
 406             (curr_menu->menu[n].type & MENUITEM_MASK) == MENUITEM_ERROR ||
 407             (curr_menu->menu[n].type & MENUITEM_MASK) == MENUITEM_WARNING ||
 408             (curr_menu->menu[n].type & MENUITEM_MASK) == MENUITEM_SEPARATOR
 409            );
 410 }
 411 
 412 // Open a sub-menu
 413 void gui_activate_sub_menu(CMenu *sub_menu)
 414 {
 415     // push current menu on stack
 416     gui_menu_stack[gui_menu_stack_ptr].menu = curr_menu;
 417     gui_menu_stack[gui_menu_stack_ptr].curpos = gui_menu_curr_item;
 418     gui_menu_stack[gui_menu_stack_ptr].toppos = gui_menu_top_item;
 419 
 420     // Select first item in menu, (or none)
 421     if (conf.menu_select_first_entry)
 422     {
 423         gui_menu_set_curr_menu(sub_menu, 0, 0);
 424         if (isText(gui_menu_curr_item))
 425         {
 426             //++gui_menu_top_item;
 427             ++gui_menu_curr_item;
 428         }
 429     }
 430     else 
 431         gui_menu_set_curr_menu(sub_menu, 0, -1);
 432 
 433     gui_menu_stack_ptr++;
 434 
 435     // FIXME check on stack overrun;
 436     if (gui_menu_stack_ptr > MENUSTACK_MAXDEPTH)
 437     {
 438         draw_string(1, 0, "E1", MAKE_COLOR(COLOR_RED, COLOR_YELLOW));
 439         gui_menu_stack_ptr = 0;
 440     }
 441 
 442     // Set active Tv override menu entry if present
 443     extern void set_tv_override_menu(CMenu *menu);
 444     set_tv_override_menu(curr_menu);
 445 
 446     // Force full redraw
 447     gui_menu_erase_and_redraw();
 448 }
 449 
 450 // Open a sub-menu
 451 static void select_sub_menu()
 452 {
 453     gui_activate_sub_menu((CMenu*)(curr_menu->menu[gui_menu_curr_item].value));
 454 }
 455 
 456 // Call a function to process a menu item (may be a sub-menu loaded via a module)
 457 static void select_proc()
 458 {
 459     if (curr_menu->menu[gui_menu_curr_item].value)
 460     {
 461         ((void (*)(int arg))(curr_menu->menu[gui_menu_curr_item].value))(curr_menu->menu[gui_menu_curr_item].arg);
 462         //gui_menu_set_curr_menu(curr_menu, 0, 0); // restore this if it causes problems
 463         gui_menu_redraw=2;
 464     }
 465 }
 466 
 467 // Move up / down in menu, adjusting scroll position if needed
 468 //   increment = -1 to move up, 1 to move down
 469 static void gui_menu_updown(int increment)
 470 {
 471     int c, j;
 472 
 473     // Determine number of rows to move (1 or 4)
 474     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;
 475 
 476     for (j = 0; j < c; ++j)
 477     {
 478         do
 479         {
 480             // Move to next or previous row
 481             gui_menu_curr_item += increment;
 482 
 483             if (gui_menu_curr_item < 0)                                     // Off top, move to bottom
 484             {
 485                 gui_menu_curr_item = gui_menu_rows() - 1;
 486                 gui_menu_top_item = gui_menu_curr_item - num_lines + 1;
 487             }
 488             else if (gui_menu_curr_item >= gui_menu_rows())                 // Off bottom, move to top
 489             {
 490                 gui_menu_curr_item = gui_menu_top_item = 0;
 491             }
 492             else if (increment == 1)                                        // Still in menu, if moving down adjust scroll if needed
 493             {
 494                 if (gui_menu_curr_item - gui_menu_top_item >= num_lines - 1)
 495                 {
 496                     gui_menu_top_item = gui_menu_curr_item - num_lines + 2;
 497                     if (gui_menu_top_item + num_lines > gui_menu_rows()) gui_menu_top_item = gui_menu_rows() - num_lines;
 498                 }
 499             }
 500             else                                                            // Still in menu, and moving up, adjust scroll
 501             {
 502                 if (gui_menu_curr_item == gui_menu_top_item) 
 503                     --gui_menu_top_item;
 504             }
 505 
 506             // Check in case scroll moved off top of menu
 507             if (gui_menu_top_item < 0) gui_menu_top_item = 0;
 508         } while (isText(gui_menu_curr_item));
 509 
 510         // Reset amount to increment integer values by
 511         int_incr = 1;
 512         if (((curr_menu->menu[gui_menu_curr_item].type & MENUITEM_MASK) == MENUITEM_STATE_VAL_PAIR) &&
 513             (curr_menu->menu[gui_menu_curr_item].arg > 0))
 514             int_incr = curr_menu->menu[gui_menu_curr_item].arg;
 515 
 516         // Redraw menu if needed
 517         if (gui_menu_redraw == 0) gui_menu_redraw=1;
 518     }
 519 }
 520 
 521 static int gui_menu_touch_handler(int tx, int ty)
 522 {
 523     int h = ((count > num_lines) ? num_lines : count) * rbf_font_height();
 524     if ((tx >= x) && (ty >= y) && (tx < (x + w)) && (ty < (y + h)))
 525     {
 526         int r = ((ty - y) / rbf_font_height()) + gui_menu_top_item;
 527         if (!isText(r))
 528         {
 529             if (gui_menu_curr_item != r)
 530             {
 531                 gui_menu_curr_item = r;
 532                 // Redraw menu if needed
 533                 if (gui_menu_redraw == 0) gui_menu_redraw = 1;
 534             }
 535             return KEY_SET;
 536         }
 537     }
 538     return 0;
 539 }
 540 
 541 //-------------------------------------------------------------------
 542 // Process button presses when in GUI_MODE_MENU mode
 543 int gui_menu_kbd_process() {
 544 
 545     switch (kbd_get_autoclicked_key() | get_jogdial_direction())
 546     {
 547         case KEY_ERASE:
 548         case KEY_SHOOT_HALF:
 549             if (!increment_factor())
 550                 int_incr = 1;
 551             gui_menu_redraw=1;
 552             break;
 553         case JOGDIAL_LEFT:
 554         case KEY_UP:
 555             gui_menu_updown(-1);
 556             break;
 557         case JOGDIAL_RIGHT:
 558         case KEY_DOWN: 
 559             gui_menu_updown(1);
 560             break;
 561         case FRONTDIAL_LEFT:
 562         case KEY_LEFT:
 563             if (gui_menu_curr_item >= 0) {
 564                 switch (curr_menu->menu[gui_menu_curr_item].type & MENUITEM_MASK) {
 565                     case MENUITEM_INT:
 566                         update_int_value(&curr_menu->menu[gui_menu_curr_item],-1);
 567                         break;
 568                     case MENUITEM_BOOL:
 569                         update_bool_value(&curr_menu->menu[gui_menu_curr_item]);
 570                         break;
 571                     case MENUITEM_ENUM:
 572                     case MENUITEM_ENUM2:
 573                         update_enum_value(&curr_menu->menu[gui_menu_curr_item],-1);
 574                         break;
 575                     case MENUITEM_UP:
 576                         gui_menu_back();
 577                         break;
 578                     case MENUITEM_STATE_VAL_PAIR:
 579                         {
 580                             CMenuItem *c = (CMenuItem*)(curr_menu->menu[gui_menu_curr_item].value);
 581                             if (*(c[1].value) == 0)
 582                                 update_bool_value(&c[1]);
 583                             switch (c[0].type & MENUITEM_MASK)
 584                             {
 585                                 case MENUITEM_INT:
 586                                     update_int_value(&c[0],-1);
 587                                     break;
 588                                 case MENUITEM_ENUM:
 589                                 case MENUITEM_ENUM2:
 590                                     update_enum_value(&c[0],-1);
 591                                     break;
 592                             }
 593                         }
 594                         break;
 595                 }
 596             } else {
 597                 gui_menu_back();
 598             }
 599             break;
 600         case FRONTDIAL_RIGHT:
 601         case KEY_RIGHT:
 602             if (gui_menu_curr_item >= 0) {
 603                 switch (curr_menu->menu[gui_menu_curr_item].type & MENUITEM_MASK){
 604                     case MENUITEM_INT:
 605                         update_int_value(&curr_menu->menu[gui_menu_curr_item],1);
 606                         break;
 607                     case MENUITEM_BOOL:
 608                         update_bool_value(&curr_menu->menu[gui_menu_curr_item]);
 609                         break;
 610                     case MENUITEM_ENUM:
 611                     case MENUITEM_ENUM2:
 612                         update_enum_value(&curr_menu->menu[gui_menu_curr_item],1);
 613                         break;
 614                     case MENUITEM_SUBMENU_PROC:
 615                         select_proc();
 616                         break;
 617                     case MENUITEM_SUBMENU:
 618                         select_sub_menu();
 619                         break;
 620                     case MENUITEM_STATE_VAL_PAIR:
 621                         {
 622                             CMenuItem *c = (CMenuItem*)(curr_menu->menu[gui_menu_curr_item].value);
 623                             if (*(c[1].value) == 0)
 624                                 update_bool_value(&c[1]);
 625                             switch (c[0].type & MENUITEM_MASK)
 626                             {
 627                                 case MENUITEM_INT:
 628                                     update_int_value(&c[0],1);
 629                                     break;
 630                                 case MENUITEM_ENUM:
 631                                 case MENUITEM_ENUM2:
 632                                     update_enum_value(&c[0],1);
 633                                     break;
 634                             }
 635                         }
 636                         break;
 637                 }
 638             }
 639             break;
 640         case KEY_SET:
 641             if (gui_menu_curr_item >= 0) {
 642                 switch (curr_menu->menu[gui_menu_curr_item].type & MENUITEM_MASK){
 643                     case MENUITEM_INT:
 644                         if (camera_info.state.is_shutter_half_press)
 645                         {
 646                             *(curr_menu->menu[gui_menu_curr_item].value) = 0;
 647                             gui_menu_redraw=1;
 648                         }
 649                         break;
 650                     case MENUITEM_BOOL:
 651                         update_bool_value(&curr_menu->menu[gui_menu_curr_item]);
 652                         break;
 653                     case MENUITEM_SUBMENU_PROC:
 654                     case MENUITEM_PROC:
 655                         select_proc();
 656                         break;
 657                     case MENUITEM_SUBMENU:
 658                         select_sub_menu();
 659                         break;
 660                     case MENUITEM_UP:
 661                         gui_menu_back();
 662                         break;
 663                     case MENUITEM_COLOR_FG:
 664                         item_color = (confColor*)(curr_menu->menu[gui_menu_curr_item].value);
 665                         item_color_type = MENUITEM_COLOR_FG;
 666                         libpalette->show_palette(PALETTE_MODE_SELECT, item_color->fg, gui_menu_color_selected);
 667                         gui_menu_redraw=2;
 668                         break;
 669                     case MENUITEM_COLOR_BG:
 670                         item_color = (confColor*)(curr_menu->menu[gui_menu_curr_item].value);
 671                         item_color_type = MENUITEM_COLOR_BG;
 672                         libpalette->show_palette(PALETTE_MODE_SELECT, item_color->bg, gui_menu_color_selected);
 673                         gui_menu_redraw=2;
 674                         break;
 675                     case MENUITEM_ENUM:
 676                     case MENUITEM_ENUM2:
 677                         update_enum_value(&curr_menu->menu[gui_menu_curr_item],1);
 678                         gui_menu_redraw=1;
 679                         break;
 680                     case MENUITEM_STATE_VAL_PAIR:
 681                         {
 682                             CMenuItem *c = (CMenuItem*)(curr_menu->menu[gui_menu_curr_item].value);
 683                             if ((c[1].type & MENUITEM_MASK) == MENUITEM_ENUM)
 684                                 update_enum_value(&c[1],1);
 685                             else
 686                                 update_bool_value(&c[1]);
 687                         }
 688                         break;
 689                 }
 690             }
 691             break;
 692         case KEY_SHOOT_FULL:                                // run script directly from User Menu ?
 693             if(    (gui_menu_curr_item >= 0) 
 694                 && ((curr_menu->menu[gui_menu_curr_item].type & MENUITEM_MASK) == MENUITEM_PROC)
 695                 &&  (curr_menu->menu[gui_menu_curr_item].value == (int *)gui_load_user_menu_script ))
 696                     select_proc();
 697             break;
 698         case KEY_ZOOM_IN:
 699             if (decrement_factor())
 700                 gui_menu_redraw = 1;
 701             break;
 702 
 703         case KEY_ZOOM_OUT:
 704             if (increment_factor())
 705                 gui_menu_redraw = 1;
 706             break;
 707 
 708         case KEY_DISPLAY:
 709             if (camera_info.cam_has_zoom_lever)
 710             {
 711                 gui_menu_back();
 712             }
 713             else
 714             {
 715                 // For cams without zoom lever, DISP adjusts increment factor
 716                 if (!increment_factor())
 717                     int_incr = 1;
 718                 gui_menu_redraw=1;
 719             }
 720             break;
 721     }
 722 
 723     return 0;
 724 }
 725 
 726 //-------------------------------------------------------------------
 727 // Draw menu scroll bar if needed, and title bar
 728 void gui_menu_draw_initial()
 729 { 
 730     count = gui_menu_rows();
 731 
 732     // Setup screen size
 733     num_lines = (camera_screen.height - camera_screen.ts_menu_border*2)/rbf_font_height()-1;
 734     y = (camera_screen.height - ((num_lines - 1) * rbf_font_height())) >> 1;
 735     x = camera_screen.disp_left  + camera_screen.menu_border_width;
 736     w = camera_screen.disp_width - camera_screen.menu_border_width*2;
 737 
 738     // Adjust top line to fit in case display size changes
 739     if ((count - gui_menu_top_item) < num_lines) {
 740         // Screen is larger, move top line up
 741         gui_menu_top_item = count - num_lines;
 742         if (gui_menu_top_item < 0) gui_menu_top_item = 0;
 743     }
 744     if ((gui_menu_curr_item - gui_menu_top_item + 1) > num_lines) {
 745         // Screen is smaller, move top line down
 746         gui_menu_top_item = gui_menu_curr_item - num_lines + 1;
 747     }
 748 
 749     if (count > num_lines)
 750     {
 751         wplus = 8; 
 752         // scrollbar background 
 753         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);
 754     }
 755     else
 756     {
 757         wplus = 0;
 758         if (conf.menu_center)
 759         {
 760             y = (camera_screen.height - ((count - 1) * rbf_font_height())) >> 1;
 761         }
 762     }
 763 
 764     rbf_draw_menu_header(x, y-rbf_font_height(), w+wplus, (conf.menu_symbol_enable)?curr_menu->symbol:0, lang_str(curr_menu->title), user_color(conf.menu_title_color));
 765 }
 766 
 767 //-------------------------------------------------------------------
 768 
 769 // Local variables used by menu draw functions
 770 static int imenu, yy, xx, symbol_width;
 771 static twoColors cl, cl_symbol;
 772 
 773 // Common code extracted from gui_menu_draw for displaying the symbol on the left
 774 static void gui_menu_draw_symbol(int num_symbols)
 775 {
 776     if (conf.menu_symbol_enable)
 777     {
 778         xx += rbf_draw_char(xx, yy, ' ', cl_symbol);
 779         xx += symbol_width = rbf_draw_symbol(xx, yy, curr_menu->menu[imenu].symbol, cl_symbol);
 780         symbol_width = (symbol_width * num_symbols) + len_space;
 781     }
 782     else
 783     {
 784         symbol_width = 0;
 785     }
 786 
 787     xx += rbf_draw_char(xx, yy, ' ', cl);
 788 }
 789 
 790 static void gui_set_int_cursor(int offset)
 791 {
 792     if (gui_menu_curr_item==imenu)
 793     {
 794         int n = int_incr;
 795         while (n > 1)
 796         {
 797             n /= 10;
 798             offset--;
 799         }
 800         rbf_enable_cursor(offset,offset);
 801     }
 802 }
 803 
 804 // Common code extracted from gui_menu_draw for displaying an int, enum or bool value on the right
 805 static void gui_menu_draw_value(const char *str, int len_str)
 806 {
 807     gui_menu_draw_symbol(1);
 808     xx += rbf_draw_string_len(xx, yy, w-len_space-len_space-len_br1-len_str-len_br2-len_space-symbol_width, lang_str(curr_menu->menu[imenu].text), cl);
 809     xx += rbf_draw_string(xx, yy, " [", cl);
 810     if (gui_menu_curr_item==imenu)
 811     {
 812         if (len_str == len_int)
 813             gui_set_int_cursor(4);
 814         else if (curr_menu->menu[imenu].type & MENUITEM_SD_INT)
 815             gui_set_int_cursor(6);
 816         else
 817             rbf_enable_cursor(0,6);
 818     }
 819     xx += rbf_draw_string_right_len(xx, yy, len_str, str, cl);
 820     rbf_disable_cursor();
 821     rbf_draw_string(xx, yy, "] ", cl);
 822 }
 823 
 824 // Common code extracted from gui_menu_draw for displaying a text menu string
 825 static void gui_menu_draw_text(char *str, int num_symbols)
 826 {
 827     gui_menu_draw_symbol(num_symbols);
 828     xx += rbf_draw_string_len(xx, yy, w-len_space-len_space-symbol_width, str, cl);
 829     if ((num_symbols == 2) && conf.menu_symbol_enable)
 830         xx += rbf_draw_symbol(xx, yy, 0x52, cl_symbol);
 831     rbf_draw_char(xx, yy, ' ', cl);
 832 }
 833 
 834 // Calculate how many display digits required to accomodate current int_incr value
 835 static int factor_disp_len()
 836 {
 837     int l = 0;
 838     if (gui_menu_curr_item==imenu)
 839     {
 840         l = -1;
 841         int n = int_incr;
 842         while (n > 0)
 843         {
 844             l++;
 845             n /= 10;
 846         }
 847     }
 848     return l;
 849 }
 850 
 851 static char tbuf[64];
 852 
 853 // Convert an int value to a display string, adjust position of '-' for negative values to
 854 // not clash with int_incr 'cursor' position
 855 static void get_int_disp_string(int value, int dlen)
 856 {
 857     if (dlen == 6)
 858         sprintf(tbuf, "%7d", value);
 859     else
 860         sprintf(tbuf, "%5d", value);
 861     if (value < 0)
 862     {
 863         int spos, cpos;
 864         for (spos=0; spos<5; spos++) if (tbuf[spos] == '-') break;
 865         cpos = dlen - factor_disp_len();
 866         if ((cpos > 0) && (cpos <= spos))
 867         {
 868             tbuf[spos] = ' ';
 869             tbuf[cpos-1] = '-';
 870         }
 871     }
 872 }
 873 
 874 // Common code extracted from gui_menu_draw for displaying an int or enum that can be enabled/disabled
 875 static void gui_menu_draw_state_value(CMenuItem *c)
 876 {
 877     const char *ch = "";
 878 
 879     int text = curr_menu->menu[imenu].text;
 880     if (c[0].text != 0)
 881         text = c[0].text;
 882 
 883     int wid = w-len_space-len_space-len_br1-len_enum-len_br2-len_space-symbol_width-len_br1-len_br2;
 884     if ((c[1].type & MENUITEM_MASK) == MENUITEM_ENUM)
 885         wid -= len_space*3;
 886     else
 887         wid -= len_bool;
 888 
 889     gui_menu_draw_symbol(1);
 890     xx += rbf_draw_string_len(xx, yy, wid, lang_str(text), cl);
 891     xx += rbf_draw_string(xx, yy, " [", cl);
 892     if ((c[1].type & MENUITEM_MASK) == MENUITEM_ENUM)
 893         xx += rbf_draw_string_len(xx, yy, len_space*3, ((const char* (*)(int change, int arg))(c[1].value))(0, c[1].arg), cl);
 894     else
 895         xx += rbf_draw_string_len(xx, yy, len_bool, (*(c[1].value))?"\x95":"", cl);
 896     xx += rbf_draw_string(xx, yy, "][", cl);
 897 
 898     switch (c[0].type & MENUITEM_MASK)
 899     {
 900     case MENUITEM_INT:
 901         get_int_disp_string(*(c[0].value), (c[0].type & MENUITEM_SD_INT)?6:4);
 902         gui_set_int_cursor((c[0].type & MENUITEM_SD_INT)?6:4);
 903         ch = tbuf;
 904         break;
 905     case MENUITEM_ENUM:
 906         if (c[0].value)
 907             ch = ((const char* (*)(int change, int arg))(c[0].value))(0, c[0].arg);
 908         if ((c[0].type & MENUITEM_HHMMSS) && (gui_menu_curr_item==imenu))
 909         {
 910             switch (int_incr)
 911             {
 912             case 1:
 913                 rbf_enable_cursor(5,6);
 914                 break;
 915             case 10:
 916                 rbf_enable_cursor(2,3);
 917                 break;
 918             default:
 919                 rbf_enable_cursor(0,0);
 920                 break;
 921             }
 922         }
 923         else if (c[0].type & MENUITEM_DECIMAL)
 924         {
 925             if (int_incr == 100000)
 926                 rbf_enable_cursor(0,0);     // Skip decimal point if incrementing leftmost digit
 927             else
 928                 gui_set_int_cursor(6);
 929         }
 930         else if (c[0].type & MENUITEM_SD_INT)
 931         {
 932             if (isdigit(ch[strlen(ch)-1]))
 933                 gui_set_int_cursor(6);
 934         }
 935         else if (gui_menu_curr_item==imenu)
 936         {
 937             rbf_enable_cursor(0,6);
 938         }
 939         break;
 940     case MENUITEM_ENUM2:
 941         if (c[0].value)
 942         {
 943             extern const char* gui_change_enum2(const CMenuItem *menu_item, int change);
 944             ch = gui_change_enum2(c, 0);
 945             if (gui_menu_curr_item==imenu)
 946                 rbf_enable_cursor(0,6);
 947         }
 948         break;
 949     }
 950 
 951     xx += rbf_draw_string_right_len(xx, yy, len_enum, ch, cl);
 952     rbf_disable_cursor();
 953     rbf_draw_string(xx, yy, "] ", cl);
 954 }
 955 
 956 //-------------------------------------------------------------------
 957 static void menu_text(color c)
 958 {
 959     twoColors save = cl;
 960     cl = MAKE_COLOR(BG_COLOR(cl), c);
 961     gui_menu_draw_text(lang_str(curr_menu->menu[imenu].text),1);
 962     cl = save;
 963 }
 964 
 965 void gui_menu_draw(int enforce_redraw)
 966 {
 967     int i, j;
 968     const char *ch = "";
 969 
 970         if ( enforce_redraw )
 971                 gui_menu_redraw = 2;
 972 
 973     if (gui_menu_redraw)
 974     {
 975         if (gui_menu_redraw==2)
 976             gui_menu_draw_initial();
 977 
 978         gui_menu_redraw=0;
 979 
 980         for (imenu=gui_menu_top_item, i=0, yy=y; curr_menu->menu[imenu].text && i<num_lines; ++imenu, ++i, yy+=rbf_font_height())
 981         {
 982             cl = user_color((gui_menu_curr_item==imenu) ? conf.menu_cursor_color : conf.menu_color);
 983             /*
 984             * When cursor is over a symbol, force symbol background color to be the menu cursor color but
 985             * keep the symbol color user defined.
 986             * old method was to set the symbol color to the symbol background color when the cursor highlighted it.
 987             * This method allows the user to have any symbol color and background color they want with the restriction
 988             * that the symbol background color will match the rest of the line when the cursor highlights it.
 989             * It creates a nice consistent look especially when the symbol color matches the menu text color.
 990             * without this mod, there is no way to ever make the symbol color match the color of the rest of text menu line
 991             * when the cursor highlights a line.
 992             */
 993             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); //color 8Bit=Hintergrund 8Bit=Vordergrund
 994 
 995             xx = x;
 996 
 997             switch (curr_menu->menu[imenu].type & MENUITEM_MASK)
 998             {
 999             case MENUITEM_STATE_VAL_PAIR:
1000                 gui_menu_draw_state_value((CMenuItem*)(curr_menu->menu[imenu].value));
1001                 break;
1002             case MENUITEM_BOOL:
1003                 gui_menu_draw_value((*(curr_menu->menu[imenu].value))?"\x95":" ", len_bool);
1004                 break;
1005             case MENUITEM_INT:
1006                 get_int_disp_string(*(curr_menu->menu[imenu].value), (curr_menu->menu[imenu].type & MENUITEM_SD_INT)?6:4);
1007                 gui_menu_draw_value(tbuf, (curr_menu->menu[imenu].type & MENUITEM_SD_INT)?len_enum:len_int);
1008                 break;
1009             case MENUITEM_SUBMENU_PROC:
1010             case MENUITEM_SUBMENU:
1011                 sprintf(tbuf, "%s%s", lang_str(curr_menu->menu[imenu].text),(conf.menu_symbol_enable)?"":" ->");
1012                 gui_menu_draw_text(tbuf,2);
1013                 break;
1014             case MENUITEM_UP:
1015                 sprintf(tbuf, "%s%s", (conf.menu_symbol_enable)?"":"<- ", lang_str(curr_menu->menu[imenu].text));
1016                 gui_menu_draw_text(tbuf,1);
1017                 break;
1018             case MENUITEM_ERROR:
1019                 menu_text(COLOR_RED);
1020                 break;
1021             case MENUITEM_WARNING:
1022                 menu_text(COLOR_YELLOW_DK);
1023                 break;
1024             case MENUITEM_PROC:
1025             case MENUITEM_TEXT:
1026                 gui_menu_draw_text(lang_str(curr_menu->menu[imenu].text),1);
1027                 break;
1028             case MENUITEM_SEPARATOR:
1029                 rbf_draw_char(x, yy, ' ', cl);
1030 
1031                 if (lang_str(curr_menu->menu[imenu].text)[0])
1032                     sprintf(tbuf," %s ",lang_str(curr_menu->menu[imenu].text));
1033                 else
1034                     tbuf[0] = 0;
1035 
1036                 j = rbf_str_width(tbuf);
1037                 xx += ((w - j) >> 1);
1038 
1039                 if (xx > (x + len_space))
1040                 {
1041                     draw_rectangle(x+len_space, yy, xx-1, yy+rbf_font_height()/2-1, MAKE_COLOR(BG_COLOR(cl), BG_COLOR(cl)), RECT_BORDER0|DRAW_FILLED);
1042                     draw_line(x+len_space, yy+rbf_font_height()/2, xx-1, yy+rbf_font_height()/2, FG_COLOR(cl));
1043                     draw_rectangle(x+len_space, yy+rbf_font_height()/2+1, xx-1, yy+rbf_font_height()-1, MAKE_COLOR(BG_COLOR(cl), BG_COLOR(cl)), RECT_BORDER0|DRAW_FILLED);
1044                 }
1045                 else
1046                 {
1047                     xx = x;
1048                 }
1049 
1050                 if (j) xx += rbf_draw_clipped_string(xx, yy, tbuf, cl, 0, w);
1051 
1052                 if (xx < (x+w-len_space))
1053                 {
1054                     draw_rectangle(xx, yy, x+w-len_space-1, yy+rbf_font_height()/2-1, MAKE_COLOR(BG_COLOR(cl), BG_COLOR(cl)), RECT_BORDER0|DRAW_FILLED);
1055                     draw_line(xx, yy+rbf_font_height()/2, x+w-1-len_space, yy+rbf_font_height()/2, FG_COLOR(cl));
1056                     draw_rectangle(xx, yy+rbf_font_height()/2+1, x+w-len_space-1, yy+rbf_font_height()-1, MAKE_COLOR(BG_COLOR(cl), BG_COLOR(cl)), RECT_BORDER0|DRAW_FILLED);
1057                 }
1058 
1059                 rbf_draw_char(x+w-len_space, yy, ' ', cl);
1060                 break;
1061             case MENUITEM_COLOR_FG:
1062                 {
1063                 gui_menu_draw_symbol(1);
1064                 xx+=rbf_draw_string_len(xx, yy, w-len_space-symbol_width, lang_str(curr_menu->menu[imenu].text), cl);
1065                 color mc = FG_COLOR(user_color(*((confColor*)curr_menu->menu[imenu].value)));
1066                 draw_rectangle(x+w-1-cl_rect-2-len_space, yy+2, x+w-1-2-len_space, yy+rbf_font_height()-1-2, MAKE_COLOR(mc,mc), RECT_BORDER0|DRAW_FILLED|RECT_ROUND_CORNERS);
1067                 }
1068                 break;
1069             case MENUITEM_COLOR_BG:
1070                 {
1071                 gui_menu_draw_symbol(1);
1072                 xx+=rbf_draw_string_len(xx, yy, w-len_space-symbol_width, lang_str(curr_menu->menu[imenu].text), cl);
1073                 color mc = BG_COLOR(user_color(*((confColor*)curr_menu->menu[imenu].value)));
1074                 draw_rectangle(x+w-1-cl_rect-2-len_space, yy+2, x+w-1-2-len_space, yy+rbf_font_height()-1-2, MAKE_COLOR(mc,mc), RECT_BORDER0|DRAW_FILLED|RECT_ROUND_CORNERS);
1075                 }
1076                 break;
1077             case MENUITEM_ENUM:
1078                 if (curr_menu->menu[imenu].value)
1079                     ch = ((const char* (*)(int change, int arg))(curr_menu->menu[imenu].value))(0, curr_menu->menu[imenu].arg);
1080                 gui_menu_draw_value(ch, len_enum);
1081                 break;
1082             case MENUITEM_ENUM2:
1083                 if (curr_menu->menu[imenu].value)
1084                 {
1085                     extern const char* gui_change_enum2(const CMenuItem *menu_item, int change);
1086                     ch = gui_change_enum2(&curr_menu->menu[imenu], 0);
1087                 }
1088                 gui_menu_draw_value(ch, len_enum);
1089                 break;
1090             }
1091         }
1092 
1093         // scrollbar
1094         if (count > num_lines)
1095         {
1096             i = num_lines*rbf_font_height()-1 -1;           // full height
1097             j = i*num_lines/count;                          // bar height
1098             if (j<20) j=20;
1099             i = (i-j)*((gui_menu_curr_item<0)?0:gui_menu_curr_item)/(count-1);   // top pos
1100             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);
1101             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);
1102             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);
1103         }
1104     }
1105 }
1106 
1107 //-------------------------------------------------------------------
1108 // Menu button handler for Menu mode
1109 void gui_menu_kbd_process_menu_btn()
1110 {
1111     extern int gui_user_menu_flag;
1112 
1113     conf_save();
1114 
1115     if ( gui_user_menu_flag )
1116     {
1117         gui_set_mode(&menuGuiHandler);
1118         gui_user_menu_flag = 0;
1119         gui_menu_init(&root_menu);
1120     }
1121     else
1122         gui_set_mode(&altGuiHandler);
1123 }
1124 
1125 //-------------------------------------------------------------------
1126 // GUI handler for menus
1127 gui_handler menuGuiHandler = { GUI_MODE_MENU, gui_menu_draw, gui_menu_kbd_process, gui_menu_kbd_process_menu_btn, gui_menu_touch_handler, 0 };
1128 //-------------------------------------------------------------------

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