1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
29 #include "rbunicode.h"
30 #include "buttonbar.h"
47 #define DEFAULT_MARGIN 6
48 #define KBD_BUF_SIZE 500
50 #if (CONFIG_KEYPAD == ONDIO_PAD) \
51 || (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
52 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
53 || (CONFIG_KEYPAD == IPOD_4G_PAD) \
54 || (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD) \
55 || (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) \
56 || (CONFIG_KEYPAD == IAUDIO_M3_PAD) \
57 || (CONFIG_KEYPAD == IRIVER_H10_PAD) \
58 || (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
59 /* no key combos to move the cursor if not in line edit mode */
60 #define KBD_MODES /* uses 2 modes, picker and line edit */
62 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) \
63 || (CONFIG_KEYPAD == IRIVER_H300_PAD) \
64 || (CONFIG_KEYPAD == GIGABEAT_PAD) \
65 || (CONFIG_KEYPAD == GIGABEAT_S_PAD) \
66 || (CONFIG_KEYPAD == SANSA_E200_PAD) \
67 || (CONFIG_KEYPAD == SANSA_FUZE_PAD) \
68 || (CONFIG_KEYPAD == SANSA_C200_PAD) \
69 || (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
70 /* certain key combos move the cursor even if not in line edit mode */
71 #define KBD_CURSOR_KEYS
72 #define KBD_MODES /* uses 2 modes, picker and line edit */
75 #define KBD_CURSOR_KEYS /* certain keys move the cursor, no line edit mode */
78 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) \
79 || (CONFIG_KEYPAD == IRIVER_H300_PAD) \
80 || (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
81 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
82 || (CONFIG_KEYPAD == IPOD_4G_PAD) \
83 || (CONFIG_KEYPAD == IRIVER_H10_PAD) \
84 || (CONFIG_KEYPAD == GIGABEAT_PAD) \
85 || (CONFIG_KEYPAD == GIGABEAT_S_PAD) \
86 || (CONFIG_KEYPAD == MROBE100_PAD) \
87 || (CONFIG_KEYPAD == SANSA_E200_PAD) \
88 || (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) \
89 || (CONFIG_KEYPAD == PHILIPS_SA9200_PAD) \
90 || (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
91 /* certain key combos toggle input mode between keyboard input and Morse input */
92 #define KBD_TOGGLE_INPUT
95 struct keyboard_parameters
97 unsigned short kbd_buf
[KBD_BUF_SIZE
];
98 unsigned short max_line_len
;
106 #ifdef HAVE_MORSE_INPUT
129 int editpos
; /* Edit position on all screens */
130 bool cur_blink
; /* Cursor on/off flag */
132 unsigned short hlead
, hvowel
, htail
;
133 #ifdef HAVE_MORSE_INPUT
136 unsigned char morse_code
;
141 static struct keyboard_parameters kbd_param
[NB_SCREENS
];
142 static bool kbd_loaded
= false;
144 #ifdef HAVE_MORSE_INPUT
145 /* FIXME: We should put this to a configuration file. */
146 static const char *morse_alphabets
=
147 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
148 static const unsigned char morse_codes
[] = {
149 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
150 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
151 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
152 0x73,0x55,0x4c,0x61,0x5a,0x80 };
155 /* Loads a custom keyboard into memory
156 call with NULL to reset keyboard */
157 int load_kbd(unsigned char* filename
)
160 int i
, line_len
, max_line_len
;
161 unsigned char buf
[4];
163 if (filename
== NULL
)
169 fd
= open_utf8(filename
, O_RDONLY
|O_BINARY
);
176 while (read(fd
, buf
, 1) == 1 && i
< KBD_BUF_SIZE
)
178 /* check how many bytes to read for this character */
179 static const unsigned char sizes
[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
183 for (count
= 0; count
< ARRAYLEN(sizes
); count
++)
185 if (buf
[0] < sizes
[count
])
189 if (count
>= ARRAYLEN(sizes
))
190 continue; /* Invalid size. */
192 if (read(fd
, &buf
[1], count
) != (ssize_t
)count
)
199 utf8decode(buf
, &ch
);
200 if (ch
!= 0xFEFF && ch
!= '\r') /* skip BOM & carriage returns */
203 kbd_param
[l
].kbd_buf
[i
] = ch
;
207 if (max_line_len
< line_len
)
208 max_line_len
= line_len
;
219 if (max_line_len
< line_len
)
220 max_line_len
= line_len
;
224 struct keyboard_parameters
*pm
= &kbd_param
[l
];
226 /* initialize parameters */
227 pm
->x
= pm
->y
= pm
->page
= 0;
228 pm
->default_lines
= 0;
229 pm
->max_line_len
= max_line_len
;
235 /* helper function to spell a char if voice UI is enabled */
236 static void kbd_spellchar(unsigned short c
)
238 if (global_settings
.talk_menu
) /* voice UI? */
240 unsigned char tmp
[5];
241 /* store char to pass to talk_spell */
242 unsigned char* utf8
= utf8encode(c
, tmp
);
246 talk_id(VOICE_BLANK
, false);
248 talk_spell(tmp
, false);
253 static void say_edit(void)
255 if (global_settings
.talk_menu
)
256 talk_id(VOICE_EDIT
, false);
260 static void kbd_inschar(struct edit_state
*state
, unsigned short ch
)
263 unsigned char tmp
[4];
266 len
= strlen(state
->text
);
267 utf8
= utf8encode(ch
, tmp
);
268 j
= (long)utf8
- (long)tmp
;
270 if (len
+ j
< state
->buflen
)
272 i
= utf8seek(state
->text
, state
->editpos
);
273 utf8
= state
->text
+ i
;
274 memmove(utf8
+ j
, utf8
, len
- i
+ 1);
275 memcpy(utf8
, tmp
, j
);
280 static void kbd_delchar(struct edit_state
*state
)
285 if (state
->editpos
> 0)
288 len
= strlen(state
->text
);
289 i
= utf8seek(state
->text
, state
->editpos
);
290 utf8
= state
->text
+ i
;
291 j
= utf8seek(utf8
, 1);
292 memmove(utf8
, utf8
+ j
, len
- i
- j
+ 1);
296 /* Lookup k value based on state of param (pm) */
297 static unsigned short get_kbd_ch(const struct keyboard_parameters
*pm
)
299 int k
= (pm
->page
*pm
->lines
+ pm
->y
)*pm
->max_chars
+ pm
->x
;
300 return (k
< pm
->nchars
)? pm
->kbd_buf
[k
]: ' ';
303 static void kbd_calc_params(struct keyboard_parameters
*pm
,
304 struct screen
*sc
, struct edit_state
*state
);
305 static void kbd_draw_picker(struct keyboard_parameters
*pm
,
306 struct screen
*sc
, struct edit_state
*state
);
307 static void kbd_draw_edit_line(struct keyboard_parameters
*pm
,
308 struct screen
*sc
, struct edit_state
*state
);
310 int kbd_input(char* text
, int buflen
)
314 /* This seems to keep the sizes for ARM way down */
315 struct keyboard_parameters
* volatile param
= kbd_param
;
317 struct keyboard_parameters
* const param
= kbd_param
;
319 struct edit_state state
;
320 int l
; /* screen loop variable */
322 int ret
= 0; /* assume success */
325 viewportmanager_theme_enable(l
, false, NULL
);
328 #ifdef HAVE_BUTTONBAR
329 struct gui_buttonbar buttonbar
;
330 bool buttonbar_config
= global_settings
.buttonbar
;
332 global_settings
.buttonbar
= true;
333 gui_buttonbar_init(&buttonbar
);
334 gui_buttonbar_set_display(&buttonbar
, &screens
[SCREEN_MAIN
]);
337 /* initialize state */
339 state
.buflen
= buflen
;
340 /* Initial edit position is after last character */
341 state
.editpos
= utf8length(state
.text
);
342 state
.cur_blink
= true;
343 #ifdef HAVE_MORSE_INPUT
344 state
.morse_mode
= global_settings
.morse_input
;
345 state
.morse_reading
= false;
347 state
.hangul
= false;
351 /* Copy default keyboard to buffer */
354 struct keyboard_parameters
*pm
= ¶m
[l
];
355 const unsigned char *p
;
358 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
359 struct screen
*sc
= &screens
[l
];
361 if (sc
->getwidth() >= 160 && sc
->getheight() >= 96)
363 p
= "ABCDEFG abcdefg !?\" @#$%+'\n"
364 "HIJKLMN hijklmn 789 &_()-`\n"
365 "OPQRSTU opqrstu 456 §|{}/<\n"
366 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
367 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
368 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
369 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
370 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
372 pm
->default_lines
= 8;
373 pm
->max_line_len
= 26;
376 #endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
378 p
= "ABCDEFG !?\" @#$%+'\n"
379 "HIJKLMN 789 &_()-`\n"
380 "OPQRSTU 456 §|{}/<\n"
381 "VWXYZ.,0123 ~=[]*>\n"
383 "abcdefg ¢£¤¥¦§©®¬\n"
384 "hijklmn «»°ºª¹²³¶\n"
385 "opqrstu ¯±×÷¡¿µ·¨\n"
388 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
389 "àáâãäåæ ìíîï èéêë\n"
390 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
393 pm
->default_lines
= 4;
394 pm
->max_line_len
= 18;
398 p
= utf8decode(p
, &pm
->kbd_buf
[i
++]);
401 /* initialize parameters */
402 pm
->x
= pm
->y
= pm
->page
= 0;
409 struct keyboard_parameters
*pm
= ¶m
[l
];
410 struct screen
*sc
= &screens
[l
];
411 kbd_calc_params(pm
, sc
, &state
);
414 if (global_settings
.talk_menu
) /* voice UI? */
415 talk_spell(state
.text
, true); /* spell initial text */
419 /* These declarations are assigned to the screen on which the key
420 action occurred - pointers save a lot of space over array notation
421 when accessing the same array element countless times */
426 const int button_screen
= 0;
428 struct keyboard_parameters
*pm
;
431 state
.len_utf8
= utf8length(state
.text
);
435 /* declare scoped pointers inside screen loops - hide the
436 declarations from previous block level */
437 struct keyboard_parameters
*pm
= ¶m
[l
];
438 struct screen
*sc
= &screens
[l
];
440 kbd_draw_picker(pm
, sc
, &state
);
441 kbd_draw_edit_line(pm
, sc
, &state
);
444 state
.cur_blink
= !state
.cur_blink
;
446 #ifdef HAVE_BUTTONBAR
447 /* draw the button bar */
448 gui_buttonbar_set(&buttonbar
, "Shift", "OK", "Del");
449 gui_buttonbar_draw(&buttonbar
);
456 #ifdef HAVE_MORSE_INPUT
457 state
.morse_mode
? CONTEXT_MORSE_INPUT
:
459 CONTEXT_KEYBOARD
, HZ
/2);
461 button_screen
= (get_action_statuscode(NULL
) & ACTION_REMOTE
) ? 1 : 0;
463 pm
= ¶m
[button_screen
];
464 sc
= &screens
[button_screen
];
466 #if defined(KBD_MODES) || defined(HAVE_MORSE_INPUT)
467 /* Remap some buttons to allow to move
468 * cursor in line edit mode and morse mode. */
469 #if defined(KBD_MODES) && defined(HAVE_MORSE_INPUT)
470 if (pm
->line_edit
|| state
.morse_mode
)
471 #elif defined(KBD_MODES)
473 #else /* defined(HAVE_MORSE_INPUT) */
474 if (state
.morse_mode
)
477 if (button
== ACTION_KBD_LEFT
)
478 button
= ACTION_KBD_CURSOR_LEFT
;
479 if (button
== ACTION_KBD_RIGHT
)
480 button
= ACTION_KBD_CURSOR_RIGHT
;
482 /* select doubles as backspace in line_edit */
483 if (pm
->line_edit
&& button
== ACTION_KBD_SELECT
)
484 button
= ACTION_KBD_BACKSPACE
;
487 #endif /* defined(KBD_MODES) || defined(HAVE_MORSE_INPUT) */
491 case ACTION_KBD_DONE
:
492 /* accepts what was entered and continues */
497 case ACTION_KBD_ABORT
:
502 case ACTION_KBD_PAGE_FLIP
:
503 #ifdef HAVE_MORSE_INPUT
504 if (state
.morse_mode
)
507 if (++pm
->page
>= pm
->pages
)
514 #if defined(HAVE_MORSE_INPUT) && defined(KBD_TOGGLE_INPUT)
515 case ACTION_KBD_MORSE_INPUT
:
516 state
.morse_mode
= !state
.morse_mode
;
520 struct keyboard_parameters
*pm
= ¶m
[l
];
522 pm
->main_y
= pm
->old_main_y
;
525 /* FIXME: We should talk something like Morse mode.. */
527 #endif /* HAVE_MORSE_INPUT && KBD_TOGGLE_INPUT */
529 case ACTION_KBD_RIGHT
:
530 if (++pm
->x
>= pm
->max_chars
)
532 #ifndef KBD_PAGE_FLIP
533 /* no dedicated flip key - flip page on wrap */
534 if (++pm
->page
>= pm
->pages
)
544 case ACTION_KBD_LEFT
:
547 #ifndef KBD_PAGE_FLIP
548 /* no dedicated flip key - flip page on wrap */
550 pm
->page
= pm
->pages
- 1;
552 pm
->x
= pm
->max_chars
- 1;
559 case ACTION_KBD_DOWN
:
560 #ifdef HAVE_MORSE_INPUT
561 if (state
.morse_mode
)
564 pm
->line_edit
= !pm
->line_edit
;
570 #endif /* HAVE_MORSE_INPUT */
575 pm
->line_edit
= false;
577 else if (++pm
->y
>= pm
->lines
)
579 pm
->line_edit
= true;
583 if (++pm
->y
>= pm
->lines
)
596 #ifdef HAVE_MORSE_INPUT
597 if (state
.morse_mode
)
600 pm
->line_edit
= !pm
->line_edit
;
606 #endif /* HAVE_MORSE_INPUT */
610 pm
->y
= pm
->lines
- 1;
611 pm
->line_edit
= false;
613 else if (--pm
->y
< 0)
615 pm
->line_edit
= true;
620 pm
->y
= pm
->lines
- 1;
631 #ifdef HAVE_MORSE_INPUT
632 case ACTION_KBD_MORSE_SELECT
:
633 if (state
.morse_mode
&& state
.morse_reading
)
635 state
.morse_code
<<= 1;
636 if ((current_tick
- state
.morse_tick
) > HZ
/5)
637 state
.morse_code
|= 0x01;
640 #endif /* HAVE_MORSE_INPUT */
642 case ACTION_KBD_SELECT
:
643 #ifdef HAVE_MORSE_INPUT
644 if (state
.morse_mode
)
646 state
.morse_tick
= current_tick
;
648 if (!state
.morse_reading
)
650 state
.morse_reading
= true;
651 state
.morse_code
= 1;
655 #endif /* HAVE_MORSE_INPUT */
657 /* inserts the selected char */
658 /* find input char */
661 /* check for hangul input */
662 if (ch
>= 0x3131 && ch
<= 0x3163)
668 state
.hlead
= state
.hvowel
= state
.htail
= 0;
676 else if (!state
.htail
)
682 /* previous hangul complete */
683 /* check whether tail is actually lead of next char */
684 tmp
= hangul_join(state
.htail
, ch
, 0);
688 tmp
= hangul_join(state
.hlead
, state
.hvowel
, 0);
690 kbd_inschar(&state
, tmp
);
691 /* insert dummy char */
692 kbd_inschar(&state
, ' ');
693 state
.hlead
= state
.htail
;
699 state
.hvowel
= state
.htail
= 0;
704 /* combine into hangul */
705 tmp
= hangul_join(state
.hlead
, state
.hvowel
, state
.htail
);
714 state
.hvowel
= state
.htail
= 0;
720 state
.hangul
= false;
724 kbd_inschar(&state
, ch
);
726 if (global_settings
.talk_menu
) /* voice UI? */
727 talk_spell(state
.text
, false); /* speak revised text */
731 case ACTION_KBD_BACKSPACE
:
736 else if (state
.hvowel
)
739 state
.hangul
= false;
747 ch
= hangul_join(state
.hlead
, state
.hvowel
, state
.htail
);
750 kbd_inschar(&state
, ch
);
753 if (global_settings
.talk_menu
) /* voice UI? */
754 talk_spell(state
.text
, false); /* speak revised text */
757 case ACTION_KBD_CURSOR_RIGHT
:
758 state
.hangul
= false;
760 if (state
.editpos
< state
.len_utf8
)
762 int c
= utf8seek(state
.text
, ++state
.editpos
);
763 kbd_spellchar(state
.text
[c
]);
765 #if CONFIG_CODEC == SWCODEC
766 else if (global_settings
.talk_menu
)
767 pcmbuf_beep(1000, 150, 1500);
771 case ACTION_KBD_CURSOR_LEFT
:
772 state
.hangul
= false;
774 if (state
.editpos
> 0)
776 int c
= utf8seek(state
.text
, --state
.editpos
);
777 kbd_spellchar(state
.text
[c
]);
779 #if CONFIG_CODEC == SWCODEC
780 else if (global_settings
.talk_menu
)
781 pcmbuf_beep(1000, 150, 1500);
786 #ifdef HAVE_MORSE_INPUT
787 if (state
.morse_reading
)
790 logf("Morse: 0x%02x", state
.morse_code
);
791 state
.morse_reading
= false;
793 for (j
= 0; morse_alphabets
[j
] != '\0'; j
++)
795 if (morse_codes
[j
] == state
.morse_code
)
799 if (morse_alphabets
[j
] == '\0')
801 logf("Morse code not found");
805 /* turn off hangul input */
806 state
.hangul
= false;
807 kbd_inschar(&state
, morse_alphabets
[j
]);
809 if (global_settings
.talk_menu
) /* voice UI? */
810 talk_spell(state
.text
, false); /* speak revised text */
812 #endif /* HAVE_MORSE_INPUT */
816 if (default_event_handler(button
) == SYS_USB_CONNECTED
)
819 screens
[l
].setfont(FONT_SYSFIXED
);
825 if (button
!= ACTION_NONE
)
827 state
.cur_blink
= true;
831 #ifdef HAVE_BUTTONBAR
832 global_settings
.buttonbar
= buttonbar_config
;
836 splash(HZ
/2, ID2P(LANG_CANCEL
));
838 #if defined(HAVE_MORSE_INPUT) && defined(KBD_TOGGLE_INPUT)
839 if (global_settings
.morse_input
!= state
.morse_mode
)
841 global_settings
.morse_input
= state
.morse_mode
;
844 #endif /* HAVE_MORSE_INPUT && KBD_TOGGLE_INPUT */
848 screens
[l
].setfont(FONT_UI
);
849 viewportmanager_theme_undo(l
, false);
854 static void kbd_calc_params(struct keyboard_parameters
*pm
,
855 struct screen
*sc
, struct edit_state
*state
)
858 const unsigned char *p
;
860 int icon_w
, sc_w
, sc_h
, w
;
863 pm
->curfont
= pm
->default_lines
? FONT_SYSFIXED
: FONT_UI
;
864 font
= font_get(pm
->curfont
);
865 pm
->font_h
= font
->height
;
867 /* check if FONT_UI fits the screen */
868 if (2*pm
->font_h
+ 3 + BUTTONBAR_HEIGHT
> sc
->getheight())
870 pm
->curfont
= FONT_SYSFIXED
;
871 font
= font_get(FONT_SYSFIXED
);
872 pm
->font_h
= font
->height
;
875 /* find max width of keyboard glyphs.
876 * since we're going to be adding spaces,
877 * max width is at least their width */
878 pm
->font_w
= font_get_width(font
, ' ');
879 for (i
= 0; i
< pm
->nchars
; i
++)
881 if (pm
->kbd_buf
[i
] != '\n')
883 w
= font_get_width(font
, pm
->kbd_buf
[i
]);
889 /* Find max width for text string */
890 pm
->text_w
= pm
->font_w
;
894 p
= utf8decode(p
, &ch
);
895 w
= font_get_width(font
, ch
);
900 /* calculate how many characters to put in a row. */
901 icon_w
= get_icon_width(sc
->screen_type
);
902 sc_w
= sc
->getwidth();
903 if (pm
->font_w
< sc_w
/ pm
->max_line_len
)
904 pm
->font_w
= sc_w
/ pm
->max_line_len
;
905 pm
->max_chars
= sc_w
/ pm
->font_w
;
906 pm
->max_chars_text
= (sc_w
- icon_w
* 2 - 2) / pm
->text_w
;
907 if (pm
->max_chars_text
< 3 && icon_w
> pm
->text_w
)
908 pm
->max_chars_text
= sc_w
/ pm
->text_w
- 2;
912 /* Pad lines with spaces */
913 while (i
< pm
->nchars
)
915 if (pm
->kbd_buf
[i
] == '\n')
917 int k
= pm
->max_chars
- i
% ( pm
->max_chars
) - 1;
920 if (k
== pm
->max_chars
- 1)
924 for (j
= i
; j
< pm
->nchars
; j
++)
926 pm
->kbd_buf
[j
] = pm
->kbd_buf
[j
+ 1];
931 if (pm
->nchars
+ k
- 1 >= KBD_BUF_SIZE
)
932 { /* We don't want to overflow the buffer */
933 k
= KBD_BUF_SIZE
- pm
->nchars
;
936 for (j
= pm
->nchars
+ k
- 1; j
> i
+ k
; j
--)
938 pm
->kbd_buf
[j
] = pm
->kbd_buf
[j
-k
];
946 pm
->kbd_buf
[i
++] = ' ';
956 pm
->kbd_buf
[pm
->nchars
++] = ' ';
958 /* calculate pm->pages and pm->lines */
959 sc_h
= sc
->getheight();
960 pm
->lines
= (sc_h
- BUTTONBAR_HEIGHT
) / pm
->font_h
- 1;
962 if (pm
->default_lines
&& pm
->lines
> pm
->default_lines
)
963 pm
->lines
= pm
->default_lines
;
965 pm
->keyboard_margin
= sc_h
- BUTTONBAR_HEIGHT
966 - (pm
->lines
+1)*pm
->font_h
;
968 if (pm
->keyboard_margin
< 3 && pm
->lines
> 1)
971 pm
->keyboard_margin
+= pm
->font_h
;
974 if (pm
->keyboard_margin
> DEFAULT_MARGIN
)
975 pm
->keyboard_margin
= DEFAULT_MARGIN
;
977 total_lines
= (pm
->nchars
+ pm
->max_chars
- 1) / pm
->max_chars
;
978 pm
->pages
= (total_lines
+ pm
->lines
- 1) / pm
->lines
;
979 pm
->lines
= (total_lines
+ pm
->pages
- 1) / pm
->pages
;
981 pm
->main_y
= pm
->font_h
*pm
->lines
+ pm
->keyboard_margin
;
982 pm
->keyboard_margin
-= pm
->keyboard_margin
/2;
984 #ifdef HAVE_MORSE_INPUT
985 pm
->old_main_y
= sc_h
- pm
->font_h
- BUTTONBAR_HEIGHT
;
986 if (state
->morse_mode
)
989 pm
->main_y
= pm
->old_main_y
;
995 static void kbd_draw_picker(struct keyboard_parameters
*pm
,
996 struct screen
*sc
, struct edit_state
*state
)
999 #ifdef HAVE_MORSE_INPUT
1000 if (state
->morse_mode
)
1002 const int w
= 6, h
= 8; /* sysfixed font width, height */
1004 int sc_w
= sc
->getwidth(), sc_h
= pm
->main_y
- pm
->keyboard_margin
- 1;
1006 /* Draw morse code screen with sysfont */
1007 sc
->setfont(FONT_SYSFIXED
);
1012 /* Draw morse code table with code descriptions. */
1013 for (i
= 0; morse_alphabets
[i
] != '\0'; i
++)
1017 outline
[0] = morse_alphabets
[i
];
1018 sc
->putsxy(x
, y
, outline
);
1020 morse_code
= morse_codes
[i
];
1021 for (j
= 0; morse_code
> 0x01; morse_code
>>= 1)
1025 morse_code
= morse_codes
[i
];
1026 for (; morse_code
> 0x01; morse_code
>>= 1)
1029 if (morse_code
& 0x01)
1030 sc
->fillrect(x
, y
+ 2, 3, 4);
1032 sc
->fillrect(x
, y
+ 3, 1, 2);
1036 if (x
+ w
*6 >= sc_w
)
1048 #endif /* HAVE_MORSE_INPUT */
1053 sc
->setfont(pm
->curfont
);
1055 k
= pm
->page
*pm
->max_chars
*pm
->lines
;
1057 for (i
= j
= 0; k
< pm
->nchars
; k
++)
1060 unsigned char *utf8
;
1061 utf8
= utf8encode(pm
->kbd_buf
[k
], outline
);
1064 sc
->getstringsize(outline
, &w
, NULL
);
1065 sc
->putsxy(i
*pm
->font_w
+ (pm
->font_w
-w
) / 2,
1066 j
*pm
->font_h
, outline
);
1068 if (++i
>= pm
->max_chars
)
1071 if (++j
>= pm
->lines
)
1080 /* highlight the key that has focus */
1081 sc
->set_drawmode(DRMODE_COMPLEMENT
);
1082 sc
->fillrect(pm
->font_w
*pm
->x
, pm
->font_h
*pm
->y
,
1083 pm
->font_w
, pm
->font_h
);
1084 sc
->set_drawmode(DRMODE_SOLID
);
1089 static void kbd_draw_edit_line(struct keyboard_parameters
*pm
,
1090 struct screen
*sc
, struct edit_state
*state
)
1093 unsigned char *utf8
;
1094 int i
= 0, j
= 0, icon_w
, w
;
1095 int sc_w
= sc
->getwidth();
1096 int y
= pm
->main_y
- pm
->keyboard_margin
;
1097 int text_margin
= (sc_w
- pm
->text_w
* pm
->max_chars_text
) / 2;
1099 /* Clear text area one pixel above separator line so any overdraw
1101 screen_clear_area(sc
, 0, y
- 1, sc_w
, pm
->font_h
+ 6);
1103 sc
->hline(0, sc_w
- 1, y
);
1105 /* write out the text */
1106 sc
->setfont(pm
->curfont
);
1108 pm
->leftpos
= MAX(0, MIN(state
->len_utf8
, state
->editpos
+ 2)
1109 - pm
->max_chars_text
);
1110 pm
->curpos
= state
->editpos
- pm
->leftpos
;
1111 utf8
= state
->text
+ utf8seek(state
->text
, pm
->leftpos
);
1113 while (*utf8
&& i
< pm
->max_chars_text
)
1115 j
= utf8seek(utf8
, 1);
1116 strlcpy(outline
, utf8
, j
+1);
1117 sc
->getstringsize(outline
, &w
, NULL
);
1118 sc
->putsxy(text_margin
+ i
*pm
->text_w
+ (pm
->text_w
-w
)/2,
1119 pm
->main_y
, outline
);
1124 icon_w
= get_icon_width(sc
->screen_type
);
1125 if (pm
->leftpos
> 0)
1127 /* Draw nicer bitmap arrow if room, else settle for "<". */
1128 if (text_margin
>= icon_w
)
1130 screen_put_icon_with_offset(sc
, 0, 0,
1131 (text_margin
- icon_w
) / 2,
1132 pm
->main_y
, Icon_Reverse_Cursor
);
1136 sc
->getstringsize("<", &w
, NULL
);
1137 sc
->putsxy(text_margin
- w
, pm
->main_y
, "<");
1141 if (state
->len_utf8
- pm
->leftpos
> pm
->max_chars_text
)
1143 /* Draw nicer bitmap arrow if room, else settle for ">". */
1144 if (text_margin
>= icon_w
)
1146 screen_put_icon_with_offset(sc
, 0, 0,
1147 sc_w
- (text_margin
+ icon_w
) / 2,
1148 pm
->main_y
, Icon_Cursor
);
1152 sc
->putsxy(sc_w
- text_margin
, pm
->main_y
, ">");
1157 i
= text_margin
+ pm
->curpos
* pm
->text_w
;
1159 if (state
->cur_blink
)
1160 sc
->vline(i
, pm
->main_y
, pm
->main_y
+ pm
->font_h
- 1);
1162 if (state
->hangul
) /* draw underbar */
1163 sc
->hline(i
- pm
->text_w
, i
, pm
->main_y
+ pm
->font_h
- 1);
1168 sc
->set_drawmode(DRMODE_COMPLEMENT
);
1169 sc
->fillrect(0, y
+ 2, sc_w
, pm
->font_h
+ 2);
1170 sc
->set_drawmode(DRMODE_SOLID
);