This source file includes following definitions.
- map_chars
- textbox_init
- gui_tbox_draw_buttons
- gui_tbox_draw
- tbox_move_cursor
- tbox_move_text
- insert_space
- backspace
- tbox_keyboard_key
- gui_tbox_kbd_process_menu_btn
- gui_tbox_kbd_process
- _module_unloader
- _module_can_unload
- _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_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;
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
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
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
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;
90
91 int tbox_button_active, line;
92 int curchar;
93 int curgroup;
94 int cursor;
95 char lastKey;
96
97 #define MODE_KEYBOARD 0
98 #define MODE_NAVIGATE 1
99 #define MODE_BUTTON 2
100 char Mode;
101
102 char text_buf[MAX_TEXT_SIZE+1];
103 char *text = 0;
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;
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
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;
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;
154 if (tbox_width < MAX_MSG_LENGTH)
155 tbox_width = MAX_MSG_LENGTH;
156 if (tbox_width < maxlen)
157 {
158 if (maxlen < MAX_TEXT_WIDTH)
159 tbox_width = maxlen + 2;
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);
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);
194
195 draw_text_justified(x, y, tbox_title, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE), tbox_width, 1, TEXT_CENTER);
196 y += FONT_HEIGHT+2+SPACING_TITLE;
197
198
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;
206
207 if (Mode == MODE_BUTTON)
208 gui_tbox_draw_buttons();
209 }
210
211
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
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
219 if (Mode == MODE_NAVIGATE)
220 {
221
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
229
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
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));
247 }
248 }
249 gui_tbox_redraw = 0;
250 }
251
252 if (text_limit_reached)
253 {
254
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
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
297 for (i=cursor; i<strlen(text); i++)
298 {
299 text[i] = text[i+1];
300 }
301 }
302 if (direction > 0)
303 {
304
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);
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);
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 {
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);
481 else
482 tbox_on_select(0);
483 tbox_on_select = 0;
484 }
485 running = 0;
486 break;
487 }
488 }
489 return 0;
490 }
491
492
493
494
495
496
497
498 int _module_unloader()
499 {
500
501 if (tbox_on_select)
502 {
503 tbox_on_select(0);
504 tbox_on_select = 0;
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
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,
537
538 ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,
539 ANY_PLATFORM_ALLOWED,
540
541 (int32_t)"Virtual keyboard",
542 MTYPE_EXTENSION,
543
544 &_libtextbox.base,
545
546 CONF_VERSION,
547 CAM_SCREEN_VERSION,
548 ANY_VERSION,
549 ANY_VERSION,
550
551 0,
552 };