diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/recorder/keyboard.c | 680 |
1 files changed, 341 insertions, 339 deletions
diff --git a/apps/recorder/keyboard.c b/apps/recorder/keyboard.c index 856a1482e3..76e7df0509 100644 --- a/apps/recorder/keyboard.c +++ b/apps/recorder/keyboard.c | |||
@@ -147,7 +147,6 @@ static const unsigned char morse_codes[] = { | |||
147 | 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c, | 147 | 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c, |
148 | 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f, | 148 | 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f, |
149 | 0x73,0x55,0x4c,0x61,0x5a,0x80 }; | 149 | 0x73,0x55,0x4c,0x61,0x5a,0x80 }; |
150 | |||
151 | #endif | 150 | #endif |
152 | 151 | ||
153 | /* Loads a custom keyboard into memory | 152 | /* Loads a custom keyboard into memory |
@@ -158,14 +157,6 @@ int load_kbd(unsigned char* filename) | |||
158 | int i = 0; | 157 | int i = 0; |
159 | unsigned char buf[4]; | 158 | unsigned char buf[4]; |
160 | 159 | ||
161 | FOR_NB_SCREENS(l) | ||
162 | { | ||
163 | /* initialize parameters */ | ||
164 | struct keyboard_parameters *pm = &kbd_param[l]; | ||
165 | pm->x = pm->y = pm->page = 0; | ||
166 | pm->default_lines = 0; | ||
167 | } | ||
168 | |||
169 | if (filename == NULL) | 160 | if (filename == NULL) |
170 | { | 161 | { |
171 | kbd_loaded = false; | 162 | kbd_loaded = false; |
@@ -212,7 +203,13 @@ int load_kbd(unsigned char* filename) | |||
212 | kbd_loaded = true; | 203 | kbd_loaded = true; |
213 | 204 | ||
214 | FOR_NB_SCREENS(l) | 205 | FOR_NB_SCREENS(l) |
215 | kbd_param[l].nchars = i; | 206 | { |
207 | struct keyboard_parameters *pm = &kbd_param[l]; | ||
208 | pm->nchars = i; | ||
209 | /* initialize parameters */ | ||
210 | pm->x = pm->y = pm->page = 0; | ||
211 | pm->default_lines = 0; | ||
212 | } | ||
216 | 213 | ||
217 | return 0; | 214 | return 0; |
218 | } | 215 | } |
@@ -285,6 +282,13 @@ static unsigned short get_kbd_ch(const struct keyboard_parameters *pm) | |||
285 | return (k < pm->nchars)? pm->kbd_buf[k]: ' '; | 282 | return (k < pm->nchars)? pm->kbd_buf[k]: ' '; |
286 | } | 283 | } |
287 | 284 | ||
285 | static void kbd_calc_params(struct keyboard_parameters *pm, | ||
286 | struct screen *sc, struct edit_state *state); | ||
287 | static void kbd_draw_picker(struct keyboard_parameters *pm, | ||
288 | struct screen *sc, struct edit_state *state); | ||
289 | static void kbd_draw_edit_line(struct keyboard_parameters *pm, | ||
290 | struct screen *sc, struct edit_state *state); | ||
291 | |||
288 | int kbd_input(char* text, int buflen) | 292 | int kbd_input(char* text, int buflen) |
289 | { | 293 | { |
290 | bool done = false; | 294 | bool done = false; |
@@ -303,7 +307,6 @@ int kbd_input(char* text, int buflen) | |||
303 | viewportmanager_theme_enable(l, false, NULL); | 307 | viewportmanager_theme_enable(l, false, NULL); |
304 | } | 308 | } |
305 | 309 | ||
306 | char outline[8]; | ||
307 | #ifdef HAVE_BUTTONBAR | 310 | #ifdef HAVE_BUTTONBAR |
308 | struct gui_buttonbar buttonbar; | 311 | struct gui_buttonbar buttonbar; |
309 | bool buttonbar_config = global_settings.buttonbar; | 312 | bool buttonbar_config = global_settings.buttonbar; |
@@ -316,6 +319,8 @@ int kbd_input(char* text, int buflen) | |||
316 | /* initialize state */ | 319 | /* initialize state */ |
317 | state.text = text; | 320 | state.text = text; |
318 | state.buflen = buflen; | 321 | state.buflen = buflen; |
322 | /* Initial edit position is after last character */ | ||
323 | state.editpos = utf8length(state.text); | ||
319 | state.cur_blink = true; | 324 | state.cur_blink = true; |
320 | #ifdef HAVE_MORSE_INPUT | 325 | #ifdef HAVE_MORSE_INPUT |
321 | state.morse_mode = global_settings.morse_input; | 326 | state.morse_mode = global_settings.morse_input; |
@@ -332,9 +337,6 @@ int kbd_input(char* text, int buflen) | |||
332 | const unsigned char *p; | 337 | const unsigned char *p; |
333 | int i = 0; | 338 | int i = 0; |
334 | 339 | ||
335 | /* initialize parameters */ | ||
336 | pm->x = pm->y = pm->page = 0; | ||
337 | |||
338 | #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 | 340 | #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 |
339 | struct screen *sc = &screens[l]; | 341 | struct screen *sc = &screens[l]; |
340 | 342 | ||
@@ -376,6 +378,8 @@ int kbd_input(char* text, int buflen) | |||
376 | p = utf8decode(p, &pm->kbd_buf[i++]); | 378 | p = utf8decode(p, &pm->kbd_buf[i++]); |
377 | 379 | ||
378 | pm->nchars = i; | 380 | pm->nchars = i; |
381 | /* initialize parameters */ | ||
382 | pm->x = pm->y = pm->page = 0; | ||
379 | } | 383 | } |
380 | kbd_loaded = true; | 384 | kbd_loaded = true; |
381 | } | 385 | } |
@@ -384,153 +388,9 @@ int kbd_input(char* text, int buflen) | |||
384 | { | 388 | { |
385 | struct keyboard_parameters *pm = ¶m[l]; | 389 | struct keyboard_parameters *pm = ¶m[l]; |
386 | struct screen *sc = &screens[l]; | 390 | struct screen *sc = &screens[l]; |
387 | struct font* font; | 391 | kbd_calc_params(pm, sc, &state); |
388 | const unsigned char *p; | ||
389 | int icon_w, sc_w; | ||
390 | int i, w; | ||
391 | |||
392 | pm->curfont = pm->default_lines ? FONT_SYSFIXED : FONT_UI; | ||
393 | font = font_get(pm->curfont); | ||
394 | pm->font_h = font->height; | ||
395 | |||
396 | /* check if FONT_UI fits the screen */ | ||
397 | if (2*pm->font_h + 3 + BUTTONBAR_HEIGHT > sc->getheight()) | ||
398 | { | ||
399 | pm->curfont = FONT_SYSFIXED; | ||
400 | font = font_get(FONT_SYSFIXED); | ||
401 | pm->font_h = font->height; | ||
402 | } | ||
403 | |||
404 | /* find max width of keyboard glyphs. | ||
405 | * since we're going to be adding spaces, | ||
406 | * max width is at least their width */ | ||
407 | pm->font_w = font_get_width(font, ' '); | ||
408 | for (i = 0; i < pm->nchars; i++) | ||
409 | { | ||
410 | if (pm->kbd_buf[i] != '\n') | ||
411 | { | ||
412 | w = font_get_width(font, pm->kbd_buf[i]); | ||
413 | if (pm->font_w < w) | ||
414 | pm->font_w = w; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | /* Find max width for text string */ | ||
419 | pm->text_w = pm->font_w; | ||
420 | p = state.text; | ||
421 | while (*p) | ||
422 | { | ||
423 | p = utf8decode(p, &ch); | ||
424 | w = font_get_width(font, ch); | ||
425 | if (pm->text_w < w) | ||
426 | pm->text_w = w; | ||
427 | } | ||
428 | |||
429 | /* calculate how many characters to put in a row. */ | ||
430 | icon_w = get_icon_width(l); | ||
431 | sc_w = sc->getwidth(); | ||
432 | pm->max_chars = sc_w / pm->font_w; | ||
433 | pm->max_chars_text = (sc_w - icon_w * 2 - 2) / pm->text_w; | ||
434 | if (pm->max_chars_text < 3 && icon_w > pm->text_w) | ||
435 | pm->max_chars_text = sc_w / pm->text_w - 2; | ||
436 | } | 392 | } |
437 | 393 | ||
438 | FOR_NB_SCREENS(l) | ||
439 | { | ||
440 | struct keyboard_parameters *pm = ¶m[l]; | ||
441 | int i = 0; | ||
442 | |||
443 | /* Pad lines with spaces */ | ||
444 | while (i < pm->nchars) | ||
445 | { | ||
446 | if (pm->kbd_buf[i] == '\n') | ||
447 | { | ||
448 | int k = pm->max_chars - i % ( pm->max_chars ) - 1; | ||
449 | int j; | ||
450 | |||
451 | if (k == pm->max_chars - 1) | ||
452 | { | ||
453 | pm->nchars--; | ||
454 | |||
455 | for (j = i; j < pm->nchars; j++) | ||
456 | { | ||
457 | pm->kbd_buf[j] = pm->kbd_buf[j + 1]; | ||
458 | } | ||
459 | } | ||
460 | else | ||
461 | { | ||
462 | if (pm->nchars + k - 1 >= KBD_BUF_SIZE) | ||
463 | { /* We don't want to overflow the buffer */ | ||
464 | k = KBD_BUF_SIZE - pm->nchars; | ||
465 | } | ||
466 | |||
467 | for (j = pm->nchars + k - 1; j > i + k; j--) | ||
468 | { | ||
469 | pm->kbd_buf[j] = pm->kbd_buf[j-k]; | ||
470 | } | ||
471 | |||
472 | pm->nchars += k; | ||
473 | k++; | ||
474 | |||
475 | while (k--) | ||
476 | { | ||
477 | pm->kbd_buf[i++] = ' '; | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | else | ||
482 | { | ||
483 | i++; | ||
484 | } | ||
485 | } | ||
486 | } | ||
487 | |||
488 | /* calculate pm->pages and pm->lines */ | ||
489 | FOR_NB_SCREENS(l) | ||
490 | { | ||
491 | struct keyboard_parameters *pm = ¶m[l]; | ||
492 | struct screen *sc = &screens[l]; | ||
493 | int sc_h, total_lines; | ||
494 | |||
495 | sc_h = sc->getheight(); | ||
496 | pm->lines = (sc_h - BUTTONBAR_HEIGHT) / pm->font_h - 1; | ||
497 | |||
498 | if (pm->default_lines && pm->lines > pm->default_lines) | ||
499 | pm->lines = pm->default_lines; | ||
500 | |||
501 | pm->keyboard_margin = sc_h - BUTTONBAR_HEIGHT | ||
502 | - (pm->lines+1)*pm->font_h; | ||
503 | |||
504 | if (pm->keyboard_margin < 3 && pm->lines > 1) | ||
505 | { | ||
506 | pm->lines--; | ||
507 | pm->keyboard_margin += pm->font_h; | ||
508 | } | ||
509 | |||
510 | if (pm->keyboard_margin > DEFAULT_MARGIN) | ||
511 | pm->keyboard_margin = DEFAULT_MARGIN; | ||
512 | |||
513 | total_lines = (pm->nchars + pm->max_chars - 1) / pm->max_chars; | ||
514 | pm->pages = (total_lines + pm->lines - 1) / pm->lines; | ||
515 | pm->lines = (total_lines + pm->pages - 1) / pm->pages; | ||
516 | |||
517 | pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin; | ||
518 | pm->keyboard_margin -= pm->keyboard_margin/2; | ||
519 | |||
520 | #ifdef HAVE_MORSE_INPUT | ||
521 | pm->old_main_y = sc_h - pm->font_h - BUTTONBAR_HEIGHT; | ||
522 | if (state.morse_mode) | ||
523 | { | ||
524 | int y = pm->main_y; | ||
525 | pm->main_y = pm->old_main_y; | ||
526 | pm->old_main_y = y; | ||
527 | } | ||
528 | #endif | ||
529 | } | ||
530 | |||
531 | /* Initial edit position is after last character */ | ||
532 | state.editpos = utf8length(state.text); | ||
533 | |||
534 | if (global_settings.talk_menu) /* voice UI? */ | 394 | if (global_settings.talk_menu) /* voice UI? */ |
535 | talk_spell(state.text, true); /* spell initial text */ | 395 | talk_spell(state.text, true); /* spell initial text */ |
536 | 396 | ||
@@ -551,189 +411,14 @@ int kbd_input(char* text, int buflen) | |||
551 | state.len_utf8 = utf8length(state.text); | 411 | state.len_utf8 = utf8length(state.text); |
552 | 412 | ||
553 | FOR_NB_SCREENS(l) | 413 | FOR_NB_SCREENS(l) |
554 | screens[l].clear_display(); | ||
555 | |||
556 | FOR_NB_SCREENS(l) | ||
557 | { | ||
558 | #ifdef HAVE_MORSE_INPUT | ||
559 | if (state.morse_mode) | ||
560 | { | ||
561 | /* declare scoped pointers inside screen loops - hide the | ||
562 | declarations from previous block level */ | ||
563 | const int w = 6, h = 8; /* sysfixed font width, height */ | ||
564 | struct keyboard_parameters *pm = ¶m[l]; | ||
565 | struct screen *sc = &screens[l]; | ||
566 | int i, x, y; | ||
567 | int sc_w = sc->getwidth(), sc_h = pm->main_y - pm->keyboard_margin - 1; | ||
568 | |||
569 | /* Draw morse code screen with sysfont */ | ||
570 | sc->setfont(FONT_SYSFIXED); | ||
571 | x = 0; | ||
572 | y = 0; | ||
573 | outline[1] = '\0'; | ||
574 | |||
575 | /* Draw morse code table with code descriptions. */ | ||
576 | for (i = 0; morse_alphabets[i] != '\0'; i++) | ||
577 | { | ||
578 | int morse_code, j; | ||
579 | |||
580 | outline[0] = morse_alphabets[i]; | ||
581 | sc->putsxy(x, y, outline); | ||
582 | |||
583 | morse_code = morse_codes[i]; | ||
584 | for (j = 0; morse_code > 0x01; morse_code >>= 1) | ||
585 | j++; | ||
586 | |||
587 | x += w + 3 + j*4; | ||
588 | morse_code = morse_codes[i]; | ||
589 | for (; morse_code > 0x01; morse_code >>= 1) | ||
590 | { | ||
591 | x -= 4; | ||
592 | if (morse_code & 0x01) | ||
593 | sc->fillrect(x, y + 2, 3, 4); | ||
594 | else | ||
595 | sc->fillrect(x, y + 3, 1, 2); | ||
596 | } | ||
597 | |||
598 | x += w*5 - 3; | ||
599 | if (x + w*6 >= sc_w) | ||
600 | { | ||
601 | x = 0; | ||
602 | y += h; | ||
603 | if (y + h >= sc_h) | ||
604 | break; | ||
605 | } | ||
606 | } | ||
607 | } | ||
608 | else | ||
609 | #endif /* HAVE_MORSE_INPUT */ | ||
610 | { | ||
611 | /* draw page */ | ||
612 | struct keyboard_parameters *pm = ¶m[l]; | ||
613 | struct screen *sc = &screens[l]; | ||
614 | int i, j, k; | ||
615 | |||
616 | sc->setfont(pm->curfont); | ||
617 | |||
618 | k = pm->page*pm->max_chars*pm->lines; | ||
619 | |||
620 | for (i = j = 0; k < pm->nchars; k++) | ||
621 | { | ||
622 | int w; | ||
623 | unsigned char *utf8; | ||
624 | utf8 = utf8encode(pm->kbd_buf[k], outline); | ||
625 | *utf8 = 0; | ||
626 | |||
627 | sc->getstringsize(outline, &w, NULL); | ||
628 | sc->putsxy(i*pm->font_w + (pm->font_w-w) / 2, | ||
629 | j*pm->font_h, outline); | ||
630 | |||
631 | if (++i >= pm->max_chars) | ||
632 | { | ||
633 | i = 0; | ||
634 | if (++j >= pm->lines) | ||
635 | break; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | #ifdef KBD_MODES | ||
640 | if (!pm->line_edit) | ||
641 | #endif | ||
642 | { | ||
643 | /* highlight the key that has focus */ | ||
644 | sc->set_drawmode(DRMODE_COMPLEMENT); | ||
645 | sc->fillrect(pm->font_w*pm->x, pm->font_h*pm->y, | ||
646 | pm->font_w, pm->font_h); | ||
647 | sc->set_drawmode(DRMODE_SOLID); | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | |||
652 | FOR_NB_SCREENS(l) | ||
653 | { | 414 | { |
415 | /* declare scoped pointers inside screen loops - hide the | ||
416 | declarations from previous block level */ | ||
654 | struct keyboard_parameters *pm = ¶m[l]; | 417 | struct keyboard_parameters *pm = ¶m[l]; |
655 | struct screen *sc = &screens[l]; | 418 | struct screen *sc = &screens[l]; |
656 | unsigned char *utf8; | 419 | sc->clear_display(); |
657 | int i = 0, j = 0, icon_w; | 420 | kbd_draw_picker(pm, sc, &state); |
658 | int text_w = pm->text_w; | 421 | kbd_draw_edit_line(pm, sc, &state); |
659 | int sc_w = sc->getwidth(); | ||
660 | int y = pm->main_y - pm->keyboard_margin, w; | ||
661 | int text_margin = (sc_w - text_w * pm->max_chars_text) / 2; | ||
662 | |||
663 | /* Clear text area one pixel above separator line so any overdraw | ||
664 | doesn't collide */ | ||
665 | screen_clear_area(sc, 0, y - 1, sc_w, pm->font_h + 4); | ||
666 | |||
667 | sc->hline(0, sc_w - 1, y); | ||
668 | |||
669 | /* write out the text */ | ||
670 | sc->setfont(pm->curfont); | ||
671 | |||
672 | pm->curpos = MIN(state.editpos, pm->max_chars_text | ||
673 | - MIN(state.len_utf8 - state.editpos, 2)); | ||
674 | pm->leftpos = state.editpos - pm->curpos; | ||
675 | utf8 = state.text + utf8seek(state.text, pm->leftpos); | ||
676 | |||
677 | while (*utf8 && i < pm->max_chars_text) | ||
678 | { | ||
679 | j = utf8seek(utf8, 1); | ||
680 | strlcpy(outline, utf8, j+1); | ||
681 | sc->getstringsize(outline, &w, NULL); | ||
682 | sc->putsxy(text_margin + i*text_w + (text_w-w)/2, | ||
683 | pm->main_y, outline); | ||
684 | utf8 += j; | ||
685 | i++; | ||
686 | } | ||
687 | |||
688 | icon_w = get_icon_width(l); | ||
689 | if (pm->leftpos > 0) | ||
690 | { | ||
691 | /* Draw nicer bitmap arrow if room, else settle for "<". */ | ||
692 | if (text_margin >= icon_w) | ||
693 | { | ||
694 | screen_put_icon_with_offset(sc, 0, 0, | ||
695 | (text_margin - icon_w) / 2, | ||
696 | pm->main_y, Icon_Reverse_Cursor); | ||
697 | } | ||
698 | else | ||
699 | { | ||
700 | sc->getstringsize("<", &w, NULL); | ||
701 | sc->putsxy(text_margin - w, pm->main_y, "<"); | ||
702 | } | ||
703 | } | ||
704 | |||
705 | if (state.len_utf8 - pm->leftpos > pm->max_chars_text) | ||
706 | { | ||
707 | /* Draw nicer bitmap arrow if room, else settle for ">". */ | ||
708 | if (text_margin >= icon_w) | ||
709 | { | ||
710 | screen_put_icon_with_offset(sc, 0, 0, | ||
711 | sc_w - (text_margin + icon_w) / 2, | ||
712 | pm->main_y, Icon_Cursor); | ||
713 | } | ||
714 | else | ||
715 | { | ||
716 | sc->putsxy(sc_w - text_margin, pm->main_y, ">"); | ||
717 | } | ||
718 | } | ||
719 | |||
720 | /* cursor */ | ||
721 | i = text_margin + pm->curpos * text_w; | ||
722 | |||
723 | if (state.cur_blink) | ||
724 | sc->vline(i, pm->main_y, pm->main_y + pm->font_h - 1); | ||
725 | |||
726 | if (state.hangul) /* draw underbar */ | ||
727 | sc->hline(i - text_w, i, pm->main_y + pm->font_h - 1); | ||
728 | |||
729 | #ifdef KBD_MODES | ||
730 | if (pm->line_edit) | ||
731 | { | ||
732 | sc->set_drawmode(DRMODE_COMPLEMENT); | ||
733 | sc->fillrect(0, y + 2, sc_w, pm->font_h + 2); | ||
734 | sc->set_drawmode(DRMODE_SOLID); | ||
735 | } | ||
736 | #endif | ||
737 | } | 422 | } |
738 | 423 | ||
739 | state.cur_blink = !state.cur_blink; | 424 | state.cur_blink = !state.cur_blink; |
@@ -1145,3 +830,320 @@ int kbd_input(char* text, int buflen) | |||
1145 | } | 830 | } |
1146 | return ret; | 831 | return ret; |
1147 | } | 832 | } |
833 | |||
834 | static void kbd_calc_params(struct keyboard_parameters *pm, | ||
835 | struct screen *sc, struct edit_state *state) | ||
836 | { | ||
837 | struct font* font; | ||
838 | const unsigned char *p; | ||
839 | unsigned short ch; | ||
840 | int icon_w, sc_w, sc_h, w; | ||
841 | int i, total_lines; | ||
842 | |||
843 | pm->curfont = pm->default_lines ? FONT_SYSFIXED : FONT_UI; | ||
844 | font = font_get(pm->curfont); | ||
845 | pm->font_h = font->height; | ||
846 | |||
847 | /* check if FONT_UI fits the screen */ | ||
848 | if (2*pm->font_h + 3 + BUTTONBAR_HEIGHT > sc->getheight()) | ||
849 | { | ||
850 | pm->curfont = FONT_SYSFIXED; | ||
851 | font = font_get(FONT_SYSFIXED); | ||
852 | pm->font_h = font->height; | ||
853 | } | ||
854 | |||
855 | /* find max width of keyboard glyphs. | ||
856 | * since we're going to be adding spaces, | ||
857 | * max width is at least their width */ | ||
858 | pm->font_w = font_get_width(font, ' '); | ||
859 | for (i = 0; i < pm->nchars; i++) | ||
860 | { | ||
861 | if (pm->kbd_buf[i] != '\n') | ||
862 | { | ||
863 | w = font_get_width(font, pm->kbd_buf[i]); | ||
864 | if (pm->font_w < w) | ||
865 | pm->font_w = w; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | /* Find max width for text string */ | ||
870 | pm->text_w = pm->font_w; | ||
871 | p = state->text; | ||
872 | while (*p) | ||
873 | { | ||
874 | p = utf8decode(p, &ch); | ||
875 | w = font_get_width(font, ch); | ||
876 | if (pm->text_w < w) | ||
877 | pm->text_w = w; | ||
878 | } | ||
879 | |||
880 | /* calculate how many characters to put in a row. */ | ||
881 | icon_w = get_icon_width(sc->screen_type); | ||
882 | sc_w = sc->getwidth(); | ||
883 | pm->max_chars = sc_w / pm->font_w; | ||
884 | pm->max_chars_text = (sc_w - icon_w * 2 - 2) / pm->text_w; | ||
885 | if (pm->max_chars_text < 3 && icon_w > pm->text_w) | ||
886 | pm->max_chars_text = sc_w / pm->text_w - 2; | ||
887 | |||
888 | |||
889 | i = 0; | ||
890 | /* Pad lines with spaces */ | ||
891 | while (i < pm->nchars) | ||
892 | { | ||
893 | if (pm->kbd_buf[i] == '\n') | ||
894 | { | ||
895 | int k = pm->max_chars - i % ( pm->max_chars ) - 1; | ||
896 | int j; | ||
897 | |||
898 | if (k == pm->max_chars - 1) | ||
899 | { | ||
900 | pm->nchars--; | ||
901 | |||
902 | for (j = i; j < pm->nchars; j++) | ||
903 | { | ||
904 | pm->kbd_buf[j] = pm->kbd_buf[j + 1]; | ||
905 | } | ||
906 | } | ||
907 | else | ||
908 | { | ||
909 | if (pm->nchars + k - 1 >= KBD_BUF_SIZE) | ||
910 | { /* We don't want to overflow the buffer */ | ||
911 | k = KBD_BUF_SIZE - pm->nchars; | ||
912 | } | ||
913 | |||
914 | for (j = pm->nchars + k - 1; j > i + k; j--) | ||
915 | { | ||
916 | pm->kbd_buf[j] = pm->kbd_buf[j-k]; | ||
917 | } | ||
918 | |||
919 | pm->nchars += k; | ||
920 | k++; | ||
921 | |||
922 | while (k--) | ||
923 | { | ||
924 | pm->kbd_buf[i++] = ' '; | ||
925 | } | ||
926 | } | ||
927 | } | ||
928 | else | ||
929 | { | ||
930 | i++; | ||
931 | } | ||
932 | } | ||
933 | |||
934 | /* calculate pm->pages and pm->lines */ | ||
935 | sc_h = sc->getheight(); | ||
936 | pm->lines = (sc_h - BUTTONBAR_HEIGHT) / pm->font_h - 1; | ||
937 | |||
938 | if (pm->default_lines && pm->lines > pm->default_lines) | ||
939 | pm->lines = pm->default_lines; | ||
940 | |||
941 | pm->keyboard_margin = sc_h - BUTTONBAR_HEIGHT | ||
942 | - (pm->lines+1)*pm->font_h; | ||
943 | |||
944 | if (pm->keyboard_margin < 3 && pm->lines > 1) | ||
945 | { | ||
946 | pm->lines--; | ||
947 | pm->keyboard_margin += pm->font_h; | ||
948 | } | ||
949 | |||
950 | if (pm->keyboard_margin > DEFAULT_MARGIN) | ||
951 | pm->keyboard_margin = DEFAULT_MARGIN; | ||
952 | |||
953 | total_lines = (pm->nchars + pm->max_chars - 1) / pm->max_chars; | ||
954 | pm->pages = (total_lines + pm->lines - 1) / pm->lines; | ||
955 | pm->lines = (total_lines + pm->pages - 1) / pm->pages; | ||
956 | |||
957 | pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin; | ||
958 | pm->keyboard_margin -= pm->keyboard_margin/2; | ||
959 | |||
960 | #ifdef HAVE_MORSE_INPUT | ||
961 | pm->old_main_y = sc_h - pm->font_h - BUTTONBAR_HEIGHT; | ||
962 | if (state->morse_mode) | ||
963 | { | ||
964 | int y = pm->main_y; | ||
965 | pm->main_y = pm->old_main_y; | ||
966 | pm->old_main_y = y; | ||
967 | } | ||
968 | #endif | ||
969 | } | ||
970 | |||
971 | static void kbd_draw_picker(struct keyboard_parameters *pm, | ||
972 | struct screen *sc, struct edit_state *state) | ||
973 | { | ||
974 | char outline[8]; | ||
975 | #ifdef HAVE_MORSE_INPUT | ||
976 | if (state->morse_mode) | ||
977 | { | ||
978 | const int w = 6, h = 8; /* sysfixed font width, height */ | ||
979 | int i, j, x, y; | ||
980 | int sc_w = sc->getwidth(), sc_h = pm->main_y - pm->keyboard_margin - 1; | ||
981 | |||
982 | /* Draw morse code screen with sysfont */ | ||
983 | sc->setfont(FONT_SYSFIXED); | ||
984 | x = 0; | ||
985 | y = 0; | ||
986 | outline[1] = '\0'; | ||
987 | |||
988 | /* Draw morse code table with code descriptions. */ | ||
989 | for (i = 0; morse_alphabets[i] != '\0'; i++) | ||
990 | { | ||
991 | int morse_code; | ||
992 | |||
993 | outline[0] = morse_alphabets[i]; | ||
994 | sc->putsxy(x, y, outline); | ||
995 | |||
996 | morse_code = morse_codes[i]; | ||
997 | for (j = 0; morse_code > 0x01; morse_code >>= 1) | ||
998 | j++; | ||
999 | |||
1000 | x += w + 3 + j*4; | ||
1001 | morse_code = morse_codes[i]; | ||
1002 | for (; morse_code > 0x01; morse_code >>= 1) | ||
1003 | { | ||
1004 | x -= 4; | ||
1005 | if (morse_code & 0x01) | ||
1006 | sc->fillrect(x, y + 2, 3, 4); | ||
1007 | else | ||
1008 | sc->fillrect(x, y + 3, 1, 2); | ||
1009 | } | ||
1010 | |||
1011 | x += w*5 - 3; | ||
1012 | if (x + w*6 >= sc_w) | ||
1013 | { | ||
1014 | x = 0; | ||
1015 | y += h; | ||
1016 | if (y + h >= sc_h) | ||
1017 | break; | ||
1018 | } | ||
1019 | } | ||
1020 | } | ||
1021 | else | ||
1022 | #else | ||
1023 | (void) state; | ||
1024 | #endif /* HAVE_MORSE_INPUT */ | ||
1025 | { | ||
1026 | /* draw page */ | ||
1027 | int i, j, k; | ||
1028 | |||
1029 | sc->setfont(pm->curfont); | ||
1030 | |||
1031 | k = pm->page*pm->max_chars*pm->lines; | ||
1032 | |||
1033 | for (i = j = 0; k < pm->nchars; k++) | ||
1034 | { | ||
1035 | int w; | ||
1036 | unsigned char *utf8; | ||
1037 | utf8 = utf8encode(pm->kbd_buf[k], outline); | ||
1038 | *utf8 = 0; | ||
1039 | |||
1040 | sc->getstringsize(outline, &w, NULL); | ||
1041 | sc->putsxy(i*pm->font_w + (pm->font_w-w) / 2, | ||
1042 | j*pm->font_h, outline); | ||
1043 | |||
1044 | if (++i >= pm->max_chars) | ||
1045 | { | ||
1046 | i = 0; | ||
1047 | if (++j >= pm->lines) | ||
1048 | break; | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | #ifdef KBD_MODES | ||
1053 | if (!pm->line_edit) | ||
1054 | #endif | ||
1055 | { | ||
1056 | /* highlight the key that has focus */ | ||
1057 | sc->set_drawmode(DRMODE_COMPLEMENT); | ||
1058 | sc->fillrect(pm->font_w*pm->x, pm->font_h*pm->y, | ||
1059 | pm->font_w, pm->font_h); | ||
1060 | sc->set_drawmode(DRMODE_SOLID); | ||
1061 | } | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1065 | static void kbd_draw_edit_line(struct keyboard_parameters *pm, | ||
1066 | struct screen *sc, struct edit_state *state) | ||
1067 | { | ||
1068 | char outline[8]; | ||
1069 | unsigned char *utf8; | ||
1070 | int i = 0, j = 0, icon_w, w; | ||
1071 | int sc_w = sc->getwidth(); | ||
1072 | int y = pm->main_y - pm->keyboard_margin; | ||
1073 | int text_margin = (sc_w - pm->text_w * pm->max_chars_text) / 2; | ||
1074 | |||
1075 | /* Clear text area one pixel above separator line so any overdraw | ||
1076 | doesn't collide */ | ||
1077 | screen_clear_area(sc, 0, y - 1, sc_w, pm->font_h + 6); | ||
1078 | |||
1079 | sc->hline(0, sc_w - 1, y); | ||
1080 | |||
1081 | /* write out the text */ | ||
1082 | sc->setfont(pm->curfont); | ||
1083 | |||
1084 | pm->leftpos = MAX(0, MIN(state->len_utf8, state->editpos + 2) | ||
1085 | - pm->max_chars_text); | ||
1086 | pm->curpos = state->editpos - pm->leftpos; | ||
1087 | utf8 = state->text + utf8seek(state->text, pm->leftpos); | ||
1088 | |||
1089 | while (*utf8 && i < pm->max_chars_text) | ||
1090 | { | ||
1091 | j = utf8seek(utf8, 1); | ||
1092 | strlcpy(outline, utf8, j+1); | ||
1093 | sc->getstringsize(outline, &w, NULL); | ||
1094 | sc->putsxy(text_margin + i*pm->text_w + (pm->text_w-w)/2, | ||
1095 | pm->main_y, outline); | ||
1096 | utf8 += j; | ||
1097 | i++; | ||
1098 | } | ||
1099 | |||
1100 | icon_w = get_icon_width(sc->screen_type); | ||
1101 | if (pm->leftpos > 0) | ||
1102 | { | ||
1103 | /* Draw nicer bitmap arrow if room, else settle for "<". */ | ||
1104 | if (text_margin >= icon_w) | ||
1105 | { | ||
1106 | screen_put_icon_with_offset(sc, 0, 0, | ||
1107 | (text_margin - icon_w) / 2, | ||
1108 | pm->main_y, Icon_Reverse_Cursor); | ||
1109 | } | ||
1110 | else | ||
1111 | { | ||
1112 | sc->getstringsize("<", &w, NULL); | ||
1113 | sc->putsxy(text_margin - w, pm->main_y, "<"); | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | if (state->len_utf8 - pm->leftpos > pm->max_chars_text) | ||
1118 | { | ||
1119 | /* Draw nicer bitmap arrow if room, else settle for ">". */ | ||
1120 | if (text_margin >= icon_w) | ||
1121 | { | ||
1122 | screen_put_icon_with_offset(sc, 0, 0, | ||
1123 | sc_w - (text_margin + icon_w) / 2, | ||
1124 | pm->main_y, Icon_Cursor); | ||
1125 | } | ||
1126 | else | ||
1127 | { | ||
1128 | sc->putsxy(sc_w - text_margin, pm->main_y, ">"); | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | /* cursor */ | ||
1133 | i = text_margin + pm->curpos * pm->text_w; | ||
1134 | |||
1135 | if (state->cur_blink) | ||
1136 | sc->vline(i, pm->main_y, pm->main_y + pm->font_h - 1); | ||
1137 | |||
1138 | if (state->hangul) /* draw underbar */ | ||
1139 | sc->hline(i - pm->text_w, i, pm->main_y + pm->font_h - 1); | ||
1140 | |||
1141 | #ifdef KBD_MODES | ||
1142 | if (pm->line_edit) | ||
1143 | { | ||
1144 | sc->set_drawmode(DRMODE_COMPLEMENT); | ||
1145 | sc->fillrect(0, y + 2, sc_w, pm->font_h + 2); | ||
1146 | sc->set_drawmode(DRMODE_SOLID); | ||
1147 | } | ||
1148 | #endif | ||
1149 | } | ||