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

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