add caret.
@@ -29,6 +29,7 @@ | ||
29 | 29 | #include <bstdio.h> |
30 | 30 | #include <tcode.h> |
31 | 31 | #include <btron/dp.h> |
32 | +#include <btron/libapp.h> | |
32 | 33 | |
33 | 34 | #include "bchank_view.h" |
34 | 35 | #include "bchank_tadutil.h" |
@@ -38,6 +39,14 @@ | ||
38 | 39 | #include <css/cssrendering_coordinate.h> |
39 | 40 | #include <hmi/texteditor_textfragment.h> |
40 | 41 | |
42 | +#ifdef BCHAN_CONFIG_DEBUG | |
43 | +# define DP(arg) printf arg | |
44 | +# define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err) | |
45 | +#else | |
46 | +# define DP(arg) /* */ | |
47 | +# define DP_ER(msg, err) /* */ | |
48 | +#endif | |
49 | + | |
41 | 50 | struct bchank_font_t_ { |
42 | 51 | FSSPEC spec; |
43 | 52 | FNTINFO info; |
@@ -159,6 +168,11 @@ | ||
159 | 168 | return line->base.base.content_edge.c.bottom; |
160 | 169 | } |
161 | 170 | |
171 | +LOCAL W bchank_viewline_getwidth(bchank_viewline_t *line) | |
172 | +{ | |
173 | + return line->base.base.content_edge.c.right - line->base.base.content_edge.c.left; | |
174 | +} | |
175 | + | |
162 | 176 | EXPORT VOID bchank_viewline_setleft(bchank_viewline_t *line, W left) |
163 | 177 | { |
164 | 178 | line->base.base.content_edge.c.left = left; |
@@ -184,6 +198,22 @@ | ||
184 | 198 | line->fragment = fragment; |
185 | 199 | } |
186 | 200 | |
201 | +LOCAL W bchank_viewline_getX(bchank_viewline_t *line, W pos) | |
202 | +{ | |
203 | + if (pos > line->pos_len) { | |
204 | + return -1; | |
205 | + } | |
206 | + if (pos == line->pos_len) { | |
207 | + return bchank_viewline_getwidth(line); | |
208 | + } | |
209 | + return line->pos[pos]; | |
210 | +} | |
211 | + | |
212 | +LOCAL W bchank_viewline_length(bchank_viewline_t *line) | |
213 | +{ | |
214 | + return line->pos_len; | |
215 | +} | |
216 | + | |
187 | 217 | EXPORT bchank_viewline_t* bchank_viewline_new() |
188 | 218 | { |
189 | 219 | bchank_viewline_t *line; |
@@ -207,6 +237,78 @@ | ||
207 | 237 | free(line); |
208 | 238 | } |
209 | 239 | |
240 | +struct bchank_caret_t_ { | |
241 | + CARET base; | |
242 | +}; | |
243 | +typedef struct bchank_caret_t_ bchank_caret_t; | |
244 | + | |
245 | +LOCAL W bchank_caret_appear(bchank_caret_t *caret) | |
246 | +{ | |
247 | + return idsp_car(&caret->base, 1); | |
248 | +} | |
249 | + | |
250 | +LOCAL W bchank_caret_disappear(bchank_caret_t *caret) | |
251 | +{ | |
252 | + return idsp_car(&caret->base, 0); | |
253 | +} | |
254 | + | |
255 | +LOCAL W bchank_caret_blink(bchank_caret_t *caret) | |
256 | +{ | |
257 | + return idsp_car(&caret->base, -1); | |
258 | +} | |
259 | + | |
260 | +LOCAL W bchank_caret_changepos(bchank_caret_t *caret, PNT p) | |
261 | +{ | |
262 | + W prev_sts = caret->base.sts; | |
263 | + W err; | |
264 | + | |
265 | + if (prev_sts != 0 && caret->base.gid > 0) { | |
266 | + err = idsp_car(&caret->base, 0); | |
267 | + if (err < 0) { | |
268 | + DP_ER("idsp_car erase", err); | |
269 | + return err; | |
270 | + } | |
271 | + } | |
272 | + | |
273 | + caret->base.pos = p; | |
274 | + | |
275 | + if (prev_sts != 0 && caret->base.gid > 0) { | |
276 | + err = idsp_car(&caret->base, 1); | |
277 | + if (err < 0) { | |
278 | + DP_ER("idsp_car draw", err); | |
279 | + return err; | |
280 | + } | |
281 | + } | |
282 | + | |
283 | + return 0; | |
284 | +} | |
285 | + | |
286 | +LOCAL W bchank_caret_scroll(bchank_caret_t *caret, W dh, W dv) | |
287 | +{ | |
288 | + PNT next; | |
289 | + next.x = caret->base.pos.x - dh; | |
290 | + next.y = caret->base.pos.y - dv; | |
291 | + return bchank_caret_changepos(caret, next); | |
292 | +} | |
293 | + | |
294 | +LOCAL VOID bchank_caret_initialize(bchank_caret_t *caret, GID target) | |
295 | +{ | |
296 | + caret->base.sts = 0; | |
297 | + caret->base.gid = target; | |
298 | + caret->base.pos.x = 0; | |
299 | + caret->base.pos.y = 16; | |
300 | + caret->base.height = 16; | |
301 | + caret->base.kind = 0; | |
302 | + caret->base.color = 0x10FFFFFF; | |
303 | +} | |
304 | + | |
305 | +LOCAL VOID bchank_caret_finalize(bchank_caret_t *caret) | |
306 | +{ | |
307 | + if (caret->base.gid > 0) { | |
308 | + idsp_car(&caret->base, 0); | |
309 | + } | |
310 | +} | |
311 | + | |
210 | 312 | struct bchank_view_t_ { |
211 | 313 | cssrendering_blockbox_t root; |
212 | 314 | cssrendering_blockbox_t line_container; |
@@ -213,6 +315,11 @@ | ||
213 | 315 | cssrendering_anonymousbox_t line_container_anon; |
214 | 316 | cssrendering_coordinate_t scroll; |
215 | 317 | bchank_viewconfig_t config; |
318 | + bchank_caret_t caret; | |
319 | + struct { | |
320 | + W x; | |
321 | + W y; | |
322 | + } insert_pos; | |
216 | 323 | GID target; |
217 | 324 | }; |
218 | 325 |
@@ -323,6 +430,7 @@ | ||
323 | 430 | EXPORT VOID bchank_view_scroll(bchank_view_t *view, W dh, W dv) |
324 | 431 | { |
325 | 432 | cssrendering_coordinate_scrollviewrect(&view->scroll, dh, dv); |
433 | + bchank_caret_scroll(&view->caret, dh, dv); | |
326 | 434 | } |
327 | 435 | |
328 | 436 | EXPORT VOID bchank_view_getviewrect(bchank_view_t *view, W *l, W *t, W *r, W *b) |
@@ -398,6 +506,42 @@ | ||
398 | 506 | return (bchank_viewline_t*)cssrendering_anonymousbox_getfirstchild(&view->line_container_anon); |
399 | 507 | } |
400 | 508 | |
509 | +LOCAL bchank_viewline_t* bchank_view_getline(bchank_view_t *view, W at) | |
510 | +{ | |
511 | + bchank_viewline_t *line; | |
512 | + W i; | |
513 | + | |
514 | + line = bchank_view_firstchild(view); | |
515 | + for (i = 0; i < at; i++) { | |
516 | + if (line == NULL) { | |
517 | + break; | |
518 | + } | |
519 | + line = bchank_viewline_nextsibling(line); | |
520 | + } | |
521 | + | |
522 | + if (i != at) { | |
523 | + return NULL; | |
524 | + } | |
525 | + | |
526 | + return line; | |
527 | +} | |
528 | + | |
529 | +LOCAL W bchank_view_length(bchank_view_t *view) | |
530 | +{ | |
531 | + bchank_viewline_t *line; | |
532 | + W i; | |
533 | + | |
534 | + line = bchank_view_firstchild(view); | |
535 | + for (i = 0; ; i++) { | |
536 | + if (line == NULL) { | |
537 | + break; | |
538 | + } | |
539 | + line = bchank_viewline_nextsibling(line); | |
540 | + } | |
541 | + | |
542 | + return i; | |
543 | +} | |
544 | + | |
401 | 545 | EXPORT VOID bchank_view_seteditsize(bchank_view_t *view, W width, W height) |
402 | 546 | { |
403 | 547 | view->root.base.content_edge.c.left = 0; |
@@ -493,6 +637,114 @@ | ||
493 | 637 | return w; |
494 | 638 | } |
495 | 639 | |
640 | +EXPORT W bchank_view_showcaret(bchank_view_t *view) | |
641 | +{ | |
642 | + return bchank_caret_appear(&view->caret); | |
643 | +} | |
644 | + | |
645 | +EXPORT W bchank_view_hidecaret(bchank_view_t *view) | |
646 | +{ | |
647 | + return bchank_caret_disappear(&view->caret); | |
648 | +} | |
649 | + | |
650 | +EXPORT W bchank_view_blinkcaret(bchank_view_t *view) | |
651 | +{ | |
652 | + return bchank_caret_blink(&view->caret); | |
653 | +} | |
654 | + | |
655 | +LOCAL W bchank_view_caretupdate(bchank_view_t *view) | |
656 | +{ | |
657 | + bchank_viewline_t *line; | |
658 | + W x, y; | |
659 | + | |
660 | + line = bchank_view_getline(view, view->insert_pos.y); | |
661 | + if (line == NULL) { | |
662 | + return -1; | |
663 | + } | |
664 | + x = bchank_viewline_getX(line, view->insert_pos.x); | |
665 | + if (x < 0) { | |
666 | + return -1; | |
667 | + } | |
668 | + y = (view->insert_pos.y + 1) * 18 - 2; | |
669 | + cssrendering_coordinate_getrelativepoint(&view->scroll, x, y, &x, &y); | |
670 | + return bchank_caret_changepos(&view->caret, (PNT){x, y}); | |
671 | +} | |
672 | + | |
673 | +EXPORT W bchank_view_upcaret(bchank_view_t *view) | |
674 | +{ | |
675 | + W chars; | |
676 | + bchank_viewline_t *line; | |
677 | + | |
678 | + if (view->insert_pos.y - 1 < 0) { | |
679 | + return 0; | |
680 | + } | |
681 | + view->insert_pos.y--; | |
682 | + line = bchank_view_getline(view, view->insert_pos.y); | |
683 | + chars = bchank_viewline_length(line); | |
684 | + if (view->insert_pos.x > chars) { | |
685 | + view->insert_pos.x = chars; | |
686 | + } | |
687 | + return bchank_view_caretupdate(view); | |
688 | +} | |
689 | + | |
690 | +EXPORT W bchank_view_downcaret(bchank_view_t *view) | |
691 | +{ | |
692 | + W lines, chars; | |
693 | + bchank_viewline_t *line; | |
694 | + | |
695 | + lines = bchank_view_length(view); | |
696 | + if (view->insert_pos.y + 1 >= lines) { | |
697 | + return 0; | |
698 | + } | |
699 | + view->insert_pos.y++; | |
700 | + line = bchank_view_getline(view, view->insert_pos.y); | |
701 | + chars = bchank_viewline_length(line); | |
702 | + if (view->insert_pos.x > chars) { | |
703 | + view->insert_pos.x = chars; | |
704 | + } | |
705 | + return bchank_view_caretupdate(view); | |
706 | +} | |
707 | + | |
708 | +EXPORT W bchank_view_leftcaret(bchank_view_t *view) | |
709 | +{ | |
710 | + W chars; | |
711 | + bchank_viewline_t *line; | |
712 | + | |
713 | + if (view->insert_pos.x - 1 < 0) { | |
714 | + if (view->insert_pos.y - 1 < 0) { | |
715 | + return 0; | |
716 | + } | |
717 | + line = bchank_view_getline(view, view->insert_pos.y - 1); | |
718 | + chars = bchank_viewline_length(line); | |
719 | + | |
720 | + view->insert_pos.x = chars; | |
721 | + view->insert_pos.y--; | |
722 | + } else { | |
723 | + view->insert_pos.x--; | |
724 | + } | |
725 | + return bchank_view_caretupdate(view); | |
726 | +} | |
727 | + | |
728 | +EXPORT W bchank_view_rightcaret(bchank_view_t *view) | |
729 | +{ | |
730 | + W lines, chars; | |
731 | + bchank_viewline_t *line; | |
732 | + | |
733 | + line = bchank_view_getline(view, view->insert_pos.y); | |
734 | + chars = bchank_viewline_length(line); | |
735 | + if (view->insert_pos.x + 1 > chars) { | |
736 | + lines = bchank_viewline_length(line); | |
737 | + if (view->insert_pos.y + 1 >= lines) { | |
738 | + return 0; | |
739 | + } | |
740 | + view->insert_pos.x = 0; | |
741 | + view->insert_pos.y++; | |
742 | + } else { | |
743 | + view->insert_pos.x++; | |
744 | + } | |
745 | + return bchank_view_caretupdate(view); | |
746 | +} | |
747 | + | |
496 | 748 | LOCAL W bchank_view_initialize(bchank_view_t *view, GID target) |
497 | 749 | { |
498 | 750 | W err; |
@@ -509,6 +761,9 @@ | ||
509 | 761 | if (err < 0) { |
510 | 762 | goto error_config; |
511 | 763 | } |
764 | + bchank_caret_initialize(&view->caret, target); | |
765 | + view->insert_pos.x = 0; | |
766 | + view->insert_pos.y = 0; | |
512 | 767 | |
513 | 768 | view->target = target; |
514 | 769 |
@@ -536,6 +791,7 @@ | ||
536 | 791 | bchank_viewline_delete(line); |
537 | 792 | } |
538 | 793 | |
794 | + bchank_caret_finalize(&view->caret); | |
539 | 795 | bchank_viewconfig_finalize(&view->config); |
540 | 796 | cssrendering_coordinate_finalize(&view->scroll); |
541 | 797 | cssrendering_anonymousbox_finalize(&view->line_container_anon); |
@@ -62,5 +62,12 @@ | ||
62 | 62 | IMPORT bchank_viewline_t* bchank_view_firstchild(bchank_view_t *view); |
63 | 63 | IMPORT VOID bchank_view_seteditsize(bchank_view_t *view, W w, W h); |
64 | 64 | IMPORT W bchank_view_calctextwidth(bchank_view_t *view, bchank_viewline_t *line); |
65 | +IMPORT W bchank_view_showcaret(bchank_view_t *view); | |
66 | +IMPORT W bchank_view_hidecaret(bchank_view_t *view); | |
67 | +IMPORT W bchank_view_blinkcaret(bchank_view_t *view); | |
68 | +IMPORT W bchank_view_upcaret(bchank_view_t *view); | |
69 | +IMPORT W bchank_view_downcaret(bchank_view_t *view); | |
70 | +IMPORT W bchank_view_leftcaret(bchank_view_t *view); | |
71 | +IMPORT W bchank_view_rightcaret(bchank_view_t *view); | |
65 | 72 | |
66 | 73 | #endif |