root/modules/gui_tbox.c

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

DEFINITIONS

This source file includes following definitions.
  1. map_chars
  2. textbox_init
  3. gui_tbox_draw_buttons
  4. gui_tbox_draw
  5. tbox_move_cursor
  6. tbox_move_text
  7. insert_space
  8. backspace
  9. tbox_keyboard_key
  10. gui_tbox_kbd_process_menu_btn
  11. gui_tbox_kbd_process
  12. _module_unloader
  13. _module_can_unload
  14. _module_exit_alt

   1 #include "camera_info.h"
   2 #include "stdlib.h"
   3 #include "keyboard.h"
   4 #include "conf.h"
   5 #include "lang.h"
   6 #include "gui.h"
   7 #include "gui_draw.h"
   8 #include "gui_lang.h"
   9 #include "gui_mbox.h"
  10 
  11 #include "gui_tbox.h"
  12 #include "module_def.h"
  13 
  14 //-------------------------------------------------------------------
  15 int gui_tbox_kbd_process();
  16 void gui_tbox_kbd_process_menu_btn();
  17 void gui_tbox_draw();
  18 
  19 gui_handler GUI_MODE_TBOX =
  20     /*GUI_MODE_TBOX*/ { GUI_MODE_MODULE, gui_tbox_draw, gui_tbox_kbd_process, gui_tbox_kbd_process_menu_btn, 0, 0 };
  21 
  22 static gui_handler *gui_tbox_mode_old; // stored previous gui_mode
  23 static int running = 0;
  24 
  25 static int gui_tbox_redraw;
  26 static char text_limit_reached;
  27 
  28 static const char*  tbox_title;
  29 static const char*  tbox_msg;
  30 static char         cursor_to_draw;
  31 
  32 // height of prompt
  33 #define MAX_LINES               6
  34 #define MAX_WIDTH               40
  35 #define MIN_WIDTH               28
  36 #define SPACING_TITLE           4
  37 #define SPACING_BTN             4
  38 #define SPACING_BELOW_TEXT      10
  39 #define BUTTON_SEP              18
  40 #define BUTTON_SIZE             6
  41 #define BUTTON_AREA_WIDTH       (2*BUTTON_SIZE*FONT_WIDTH+BUTTON_SEP)
  42 #define BUTTON_CHAR_WIDTH       ((BUTTON_AREA_WIDTH + BUTTON_SEP) / FONT_WIDTH + 1)
  43 
  44 #define MAX_TEXT_WIDTH          (MAX_WIDTH-2)
  45 
  46 #define RESET_CHAR              lastKey = '\0'; curchar = -1; curgroup = -1;
  47 
  48 #define MAX_MSG_LENGTH          20  //max length of hardcoded messages (>navigate cursor<, text limit reached)
  49 
  50 typedef void (*tbox_on_select_t)(const char* newstr);
  51 tbox_on_select_t tbox_on_select = 0;
  52 
  53 static coord    tbox_buttons_x, tbox_buttons_y;
  54 
  55 typedef char    *cmap[][4];
  56 
  57 // Char maps
  58 cmap tbox_chars_default = 
  59     {
  60         {"ABCDEF","GHIJKL","MNOPQRS","TUVWXYZ"},
  61         {"abcdef","ghijkl","mnopqrs","tuvwxyz"},
  62         {"123","456","789","0+-=/"},
  63         {".,:;?!","@#$%^&","()[]{}","<>\"'`~_"},
  64         {0}
  65     };
  66 
  67 cmap tbox_chars_german = 
  68     {
  69         {"ABCDEF","GHIJKL","MNOPQRS","TUVWXYZ"},
  70         {"abcdef","ghijkl","mnopqrs","tuvwxyz"},
  71         {"123","456","789","0+-=/"},
  72         {".,:;?!","@#$%^&","()[]{}","<>\"'`~_"},
  73         {"","","",""},
  74         {0}
  75     };
  76 
  77 cmap tbox_chars_russian =
  78     {
  79         {"ABCDEF","GKLHIJ","MNOPQRS","TUVWXYZ"},
  80         {"abcdef","ghijkl","mnopqrs","tuvwxyz"},
  81         {"","","",""},
  82         {"","","",""},
  83         {"123","456","789","0+-="},
  84         {" .:,",";/\\","'\"*","#%&"},
  85         {0}
  86     };
  87 
  88 cmap *charmaps[] = { &tbox_chars_default, &tbox_chars_german, &tbox_chars_russian };
  89 
  90 int lines = 0;                  // num of valid lines in active charmap
  91 
  92 int tbox_button_active, line;
  93 int curchar;                    // idx of current entered char in current tmap
  94 int curgroup;
  95 int cursor;
  96 char lastKey;                   // Last pressed key (Left, Right, Up, Down)
  97 
  98 #define MODE_KEYBOARD   0
  99 #define MODE_NAVIGATE   1
 100 #define MODE_BUTTON     2
 101 char Mode;                      // K=keyboard, T=textnavigate, B=button
 102 
 103 char text_buf[MAX_TEXT_SIZE+1]; // Default buffer if not supplied by caller
 104 char *text = 0;                 // Entered text
 105 int maxlen, offset, fldlen, window_width;
 106 coord text_offset_x, text_offset_y, key_offset_x;
 107 static int tbox_width, tbox_height;     //size of the 'window'
 108 
 109 //-------------------------------------------------------
 110 static char *map_chars(int line, int group)
 111 {
 112     return (*charmaps[conf.tbox_char_map])[line][group];
 113 }
 114 
 115 //-------------------------------------------------------
 116 int textbox_init(int title, int msg, const char* defaultstr, unsigned int maxsize, void (*on_select)(const char* newstr), char *input_buffer)
 117 {
 118     running = 1;
 119 
 120     if (input_buffer)
 121         text = input_buffer;
 122     else
 123     {
 124         if (maxsize > MAX_TEXT_SIZE) maxsize = MAX_TEXT_SIZE;
 125         text = text_buf;
 126     }
 127 
 128     // Count number of entries in selected 'charmap'
 129     for (lines=0; map_chars(lines,0); lines++) ;
 130 
 131     memset(text, '\0', sizeof(char)*(maxsize+1));
 132 
 133     if ( defaultstr )
 134         strncpy(text, defaultstr, maxsize);
 135 
 136     tbox_button_active = 0;
 137 
 138     tbox_title = lang_str(title);
 139     tbox_msg = lang_str(msg);
 140     tbox_on_select = on_select;
 141 
 142     Mode = MODE_KEYBOARD;
 143     line = 0;
 144     RESET_CHAR
 145     cursor = -1;
 146     maxlen = maxsize;
 147     fldlen = (maxlen < MAX_TEXT_WIDTH) ? maxlen : MAX_TEXT_WIDTH; // length of edit field
 148     offset = 0;
 149 
 150     tbox_width = strlen(tbox_title);
 151     if (tbox_width < BUTTON_CHAR_WIDTH)
 152         tbox_width = BUTTON_CHAR_WIDTH;
 153     if (tbox_width < MIN_WIDTH)
 154         tbox_width = MIN_WIDTH;         // keyboard length
 155     if (tbox_width < MAX_MSG_LENGTH)
 156         tbox_width = MAX_MSG_LENGTH;    // max message length
 157     if (tbox_width < maxlen)
 158     {
 159         if (maxlen < MAX_TEXT_WIDTH)
 160             tbox_width = maxlen + 2;    // text length
 161         else if (tbox_width < MAX_WIDTH)
 162             tbox_width = MAX_WIDTH;
 163     }
 164 
 165     tbox_height = MAX_LINES;
 166     tbox_width = text_dimensions(tbox_msg, tbox_width, MAX_WIDTH, &tbox_height) + 2;
 167 
 168     gui_tbox_redraw = 2;
 169     gui_tbox_mode_old = gui_set_mode( &GUI_MODE_TBOX );
 170 
 171     return 1;
 172 }
 173 
 174 static void gui_tbox_draw_buttons()
 175 {
 176     draw_button(tbox_buttons_x, tbox_buttons_y+FONT_HEIGHT, BUTTON_SIZE, LANG_MBOX_BTN_OK, (tbox_button_active == 0));
 177     draw_button(tbox_buttons_x + (BUTTON_SIZE*FONT_WIDTH+BUTTON_SEP), tbox_buttons_y+FONT_HEIGHT, BUTTON_SIZE, LANG_MBOX_BTN_CANCEL, (tbox_button_active == 1));
 178 }
 179 
 180 void gui_tbox_draw()
 181 {
 182     if ((gui_tbox_redraw && !text_limit_reached) || gui_tbox_redraw == 2)
 183     {
 184         if (gui_tbox_redraw==2)
 185         {
 186             text_limit_reached = 0;
 187             
 188             key_offset_x = (camera_screen.width - tbox_width*FONT_WIDTH) >> 1;
 189 
 190             coord x = (camera_screen.width - tbox_width * FONT_WIDTH) >> 1;
 191             coord y = (camera_screen.height - (tbox_height+6) * FONT_HEIGHT-SPACING_BELOW_TEXT) >> 1;
 192             draw_rectangle(x-4, y-4, x+tbox_width*FONT_WIDTH+4, y+(tbox_height+6)*FONT_HEIGHT+SPACING_BTN+2+SPACING_TITLE+11,
 193                            MAKE_COLOR(COLOR_GREY, COLOR_WHITE), RECT_BORDER3|DRAW_FILLED|RECT_SHADOW3); // main box
 194             draw_rectangle(x-2, y-2, x+tbox_width*FONT_WIDTH+2, y+FONT_HEIGHT+2, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE), RECT_BORDER1|DRAW_FILLED); //title
 195 
 196             draw_text_justified(x, y, tbox_title, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE), tbox_width, 1, TEXT_CENTER); //title text
 197             y += FONT_HEIGHT+2+SPACING_TITLE;
 198 
 199             // draw prompt
 200             draw_text_justified(x, y, tbox_msg, MAKE_COLOR(COLOR_GREY, COLOR_WHITE), tbox_width, MAX_LINES, TEXT_CENTER);
 201 
 202             text_offset_x = x+((tbox_width-fldlen)>>1)*FONT_WIDTH;
 203             text_offset_y = y+(tbox_height*FONT_HEIGHT)+SPACING_BELOW_TEXT;
 204 
 205             tbox_buttons_x = x+((tbox_width*FONT_WIDTH-BUTTON_AREA_WIDTH)>>1);
 206             tbox_buttons_y = text_offset_y+FONT_HEIGHT+SPACING_BELOW_TEXT; // on place of symbol line
 207 
 208             if (Mode == MODE_BUTTON)
 209                 gui_tbox_draw_buttons();
 210         }
 211 
 212         // draw edit field
 213         draw_string_justified(text_offset_x, text_offset_y, text+offset, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE), 0, fldlen*FONT_WIDTH, TEXT_LEFT|TEXT_FILL);
 214         
 215         // draw long text marker
 216         draw_char(text_offset_x+fldlen*FONT_WIDTH, text_offset_y, ((strlen(text)-offset)>fldlen) ? '\20' : ' ', MAKE_COLOR(COLOR_GREY, COLOR_RED));
 217         draw_char(text_offset_x-FONT_WIDTH, text_offset_y, (offset>0) ? '\21' : ' ', MAKE_COLOR(COLOR_GREY, COLOR_RED));
 218 
 219         // symbol line
 220         if (Mode == MODE_NAVIGATE)
 221         {
 222             //rect clears any previous message
 223             draw_rectangle(key_offset_x+((tbox_width-MAX_MSG_LENGTH)>>1)*FONT_WIDTH, tbox_buttons_y,
 224                            key_offset_x+((tbox_width+MAX_MSG_LENGTH)>>1)*FONT_WIDTH, tbox_buttons_y+3*FONT_HEIGHT, MAKE_COLOR(COLOR_GREY,COLOR_GREY), RECT_BORDER0|DRAW_FILLED);
 225             draw_text_justified(key_offset_x, tbox_buttons_y+FONT_HEIGHT, ">navigate cursor<", MAKE_COLOR(COLOR_GREY, COLOR_WHITE), tbox_width, 1, TEXT_CENTER);
 226         }
 227         else if (Mode == MODE_KEYBOARD)
 228         {
 229             // draw keyboard
 230             // clean previous symbols line
 231             draw_rectangle(key_offset_x, tbox_buttons_y, key_offset_x+(tbox_width-1)*FONT_WIDTH, tbox_buttons_y+3*FONT_HEIGHT, MAKE_COLOR(COLOR_GREY, COLOR_GREY), RECT_BORDER0|DRAW_FILLED);
 232 
 233             // draw current symbols line
 234             int group;
 235             static int y_offset[4] = { FONT_HEIGHT, 0, FONT_HEIGHT, 2*FONT_HEIGHT };
 236             static int x_just[4] = { TEXT_LEFT, TEXT_CENTER, TEXT_RIGHT, TEXT_CENTER };
 237 
 238             for (group = 0; group < 4; group++)
 239             {
 240                 char *tstr = map_chars(line,group);
 241 
 242                 int y = tbox_buttons_y + y_offset[group];
 243                 int x = key_offset_x + 4*FONT_WIDTH;
 244 
 245                 x = draw_text_justified(x, y, tstr, MAKE_COLOR(COLOR_GREY, COLOR_WHITE), tbox_width-8, 1, x_just[group]);
 246                 if ((group == curgroup) && (curchar >= 0))
 247                     draw_char(x+(curchar*FONT_WIDTH), y, tstr[curchar], MAKE_COLOR(COLOR_RED, COLOR_WHITE));    // Selected char cursor
 248             }
 249         }
 250         gui_tbox_redraw = 0;
 251     }
 252 
 253     if (text_limit_reached)
 254     {
 255         // clean max_keyboard_length chars long field
 256         if (text_limit_reached%4 == 0)
 257             draw_rectangle(key_offset_x+3, tbox_buttons_y,
 258                            key_offset_x+tbox_width*FONT_WIDTH-3, tbox_buttons_y+3*FONT_HEIGHT, MAKE_COLOR(COLOR_GREY, COLOR_GREY), RECT_BORDER0|DRAW_FILLED);
 259         draw_text_justified(key_offset_x, tbox_buttons_y+FONT_HEIGHT, "text limit reached", MAKE_COLOR(COLOR_GREY, COLOR_RED), tbox_width, 1, TEXT_CENTER);
 260         text_limit_reached--;
 261     }
 262 
 263     // Insertion point cursor
 264     draw_line(text_offset_x+(1+cursor-offset)*FONT_WIDTH, text_offset_y+1, text_offset_x+(1+cursor-offset)*FONT_WIDTH, text_offset_y+FONT_HEIGHT-3, cursor_to_draw ? COLOR_YELLOW : COLOR_GREY);
 265     cursor_to_draw = !cursor_to_draw;
 266 }
 267 
 268 static void tbox_move_cursor(int direction)
 269 {
 270     draw_line(text_offset_x+(1+cursor-offset)*FONT_WIDTH, text_offset_y+1, text_offset_x+(1+cursor-offset)*FONT_WIDTH, text_offset_y+FONT_HEIGHT-3, COLOR_BLACK);
 271     if (direction < 0)
 272     {
 273         if (cursor >= 0)
 274         {
 275             cursor--;
 276             if (maxlen>MAX_TEXT_WIDTH && offset != 0 && cursor<offset)
 277                 offset--;
 278         }
 279     }
 280     if (direction > 0)
 281     {
 282         if (cursor < (maxlen-1))
 283         {
 284             cursor++;
 285             if (maxlen>MAX_TEXT_WIDTH && (cursor-offset)>=MAX_TEXT_WIDTH)
 286                 offset++;
 287         }
 288     }
 289     gui_tbox_redraw = 1;
 290 }
 291 
 292 static void tbox_move_text(int direction)
 293 {
 294     int i;
 295     if (direction < 0)
 296     {
 297         //This loop moves all characters on the right of the cursor one place left
 298         for (i=cursor; i<strlen(text); i++)
 299         {
 300             text[i] = text[i+1];
 301         }
 302     }
 303     if (direction > 0)
 304     {
 305         //This loop moves all characters on the right of the cursor one place right
 306         for (i=(strlen(text) < maxlen-1)?strlen(text):maxlen-1; i>cursor; i--)
 307         {
 308             text[i] = text[i-1];
 309         }
 310     }
 311     gui_tbox_redraw = 1;
 312 }
 313 
 314 static void insert_space()
 315 {
 316     if (strlen(text) < maxlen)
 317     {
 318         if (text[cursor+1] != '\0')
 319             tbox_move_text(1); //check whether cursor is at the end of the string
 320         tbox_move_cursor(1);
 321         text[cursor] = ' ';
 322     }
 323     else
 324     {
 325         text_limit_reached = 8;
 326     }
 327     RESET_CHAR
 328 }
 329 
 330 static void backspace()
 331 {
 332     if (cursor >= 0)
 333     {
 334         tbox_move_text(-1);
 335         tbox_move_cursor(-1);
 336         if ((strlen(text) >= MAX_TEXT_WIDTH) && ((cursor-offset) >= MAX_TEXT_WIDTH-1))
 337             offset--;
 338         RESET_CHAR
 339     }
 340 }
 341 
 342 static void tbox_keyboard_key(char curKey, int subgroup)
 343 {
 344     if (lastKey == curKey)
 345     {
 346         curchar++;
 347         curgroup = subgroup;
 348         char *tstr = map_chars(line,subgroup);
 349         if (tstr[curchar] == 0) curchar = 0;
 350         text[cursor] = tstr[curchar];
 351     }
 352     else if (curKey == 'O')
 353     {
 354         RESET_CHAR
 355     }
 356     else
 357     {
 358         if (strlen(text)<maxlen)
 359         {
 360             curchar = 0; curgroup = subgroup;
 361             if (cursor < (maxlen-1))
 362             {
 363                 if (text[cursor+1] != '\0') tbox_move_text(1); //check whether cursor is at the end of the string
 364                 tbox_move_cursor(1);
 365             }
 366             lastKey = curKey;
 367             char *tstr = map_chars(line,subgroup);
 368             text[cursor] = tstr[curchar];
 369         }
 370         else
 371         {
 372             text_limit_reached = 8;
 373             RESET_CHAR
 374         }
 375     }
 376     gui_tbox_redraw = 1;
 377 }
 378 
 379 void gui_tbox_kbd_process_menu_btn()
 380 {
 381     Mode = (Mode + 1) % 3;
 382     gui_tbox_redraw=2;
 383 }
 384 
 385 int gui_tbox_kbd_process()
 386 {
 387     if (Mode == MODE_KEYBOARD)
 388     {
 389         switch (kbd_get_autoclicked_key() | get_jogdial_direction())
 390         {
 391             case KEY_SHOOT_HALF:
 392                 line = (line+1)%lines;
 393                 RESET_CHAR
 394                 gui_tbox_redraw = 1;
 395                 break;
 396             case KEY_UP:
 397                 tbox_keyboard_key('U',1);
 398                 break;
 399             case KEY_DOWN:
 400                 tbox_keyboard_key('D',3);
 401                 break;
 402             case KEY_LEFT:
 403                 tbox_keyboard_key('L',0);
 404                 break;
 405             case KEY_RIGHT:
 406                 tbox_keyboard_key('R',2);
 407                 break;
 408             case KEY_SET:
 409                 tbox_keyboard_key('O',0);
 410                 break;
 411             case KEY_ZOOM_IN:
 412             case KEY_DISPLAY:
 413                 insert_space();
 414                 break;
 415             case KEY_ZOOM_OUT:
 416                 backspace();
 417                 break;
 418             case JOGDIAL_LEFT:
 419                 tbox_move_cursor(-1);
 420                 RESET_CHAR
 421                 break;
 422             case JOGDIAL_RIGHT:
 423                 if (text[cursor+1] != '\0') tbox_move_cursor(1);
 424                 RESET_CHAR
 425                 break;
 426         }
 427     }
 428     else if (Mode == MODE_NAVIGATE)
 429     {
 430         switch (kbd_get_autoclicked_key() | get_jogdial_direction())
 431         {
 432             case JOGDIAL_LEFT:
 433             case KEY_LEFT:
 434                 tbox_move_cursor(-1);
 435                 RESET_CHAR
 436                 break;
 437             case JOGDIAL_RIGHT:
 438             case KEY_RIGHT:
 439                 if (text[cursor+1] != '\0') tbox_move_cursor(1);
 440                 RESET_CHAR
 441                 break;
 442             case KEY_SHOOT_HALF:
 443                 backspace();
 444                 break;
 445             case KEY_DISPLAY:
 446                 insert_space();
 447                 break;
 448             case KEY_ZOOM_IN:
 449                 if (offset<(strlen(text)-MAX_TEXT_WIDTH))
 450                 {
 451                     offset++;
 452                     if ((cursor+1)<offset) cursor++;
 453                     gui_tbox_redraw = 1;
 454                 }
 455                 break;
 456             case KEY_ZOOM_OUT:
 457                 if (offset > 0)
 458                 {
 459                     offset--;
 460                     if ((cursor-offset)>=MAX_TEXT_WIDTH) cursor--;
 461                     gui_tbox_redraw = 1;
 462                 }
 463                 break;
 464         }
 465     }
 466     else { // Mode == MODE_BUTTON
 467         switch (kbd_get_autoclicked_key() | get_jogdial_direction())
 468         {
 469             case JOGDIAL_LEFT:
 470             case JOGDIAL_RIGHT:
 471             case KEY_LEFT:
 472             case KEY_RIGHT:
 473                 tbox_button_active = !tbox_button_active;
 474                 gui_tbox_draw_buttons();
 475                 break;
 476             case KEY_SET:
 477                 gui_set_mode(gui_tbox_mode_old);
 478                 if (tbox_on_select)
 479                 {
 480                     if (tbox_button_active == 0)
 481                         tbox_on_select(text);   // ok
 482                     else
 483                         tbox_on_select(0);      // cancel
 484                     tbox_on_select = 0;         // Prevent unloader from calling this function again
 485                 }
 486                 running = 0;
 487                 break;
 488         }
 489     }
 490     return 0;
 491 }
 492 
 493 //==================================================
 494 
 495 //---------------------------------------------------------
 496 // PURPOSE: Finalize module operations (close allocs, etc)
 497 // RETURN VALUE: 0-ok, 1-fail
 498 //---------------------------------------------------------
 499 int _module_unloader()
 500 {
 501     // clean allocated resource
 502     if (tbox_on_select)
 503     {
 504         tbox_on_select(0);      // notify callback about exit as cancel
 505         tbox_on_select = 0;     // prevent calling twice in the (unlikely) event of the unload called twice
 506     }
 507 
 508     return 0;
 509 }
 510 
 511 int _module_can_unload()
 512 {
 513     return running == 0;
 514 }
 515 
 516 int _module_exit_alt()
 517 {
 518     running = 0;
 519     return 0;
 520 }
 521 
 522 /******************** Module Information structure ******************/
 523 
 524 libtextbox_sym _libtextbox =
 525 {
 526     {
 527          0, _module_unloader, _module_can_unload, _module_exit_alt, 0
 528     },
 529 
 530     textbox_init,
 531 };
 532 
 533 ModuleInfo _module_info =
 534 {
 535     MODULEINFO_V1_MAGICNUM,
 536     sizeof(ModuleInfo),
 537     GUI_TBOX_VERSION,           // Module version
 538 
 539     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,         // Requirements of CHDK version
 540     ANY_PLATFORM_ALLOWED,       // Specify platform dependency
 541 
 542     (int32_t)"Virtual keyboard",
 543     MTYPE_EXTENSION,
 544 
 545     &_libtextbox.base,
 546 
 547     CONF_VERSION,               // CONF version
 548     CAM_SCREEN_VERSION,         // CAM SCREEN version
 549     ANY_VERSION,                // CAM SENSOR version
 550     ANY_VERSION,                // CAM INFO version
 551 };

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