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

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