Changes in uspace/lib/ui/src/entry.c [b987eb4:db3895d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/entry.c
rb987eb4 rdb3895d 37 37 */ 38 38 39 #include <clipboard.h>40 39 #include <errno.h> 41 40 #include <gfx/context.h> 42 #include <gfx/cursor.h>43 41 #include <gfx/render.h> 44 42 #include <gfx/text.h> 45 #include <macros.h>46 43 #include <stdlib.h> 47 44 #include <str.h> … … 56 53 static void ui_entry_ctl_destroy(void *); 57 54 static errno_t ui_entry_ctl_paint(void *); 58 static ui_evclaim_t ui_entry_ctl_kbd_event(void *, kbd_event_t *);59 55 static ui_evclaim_t ui_entry_ctl_pos_event(void *, pos_event_t *); 60 56 … … 63 59 ui_entry_vpad = 4, 64 60 ui_entry_hpad_text = 1, 65 ui_entry_vpad_text = 0, 66 ui_entry_cursor_overshoot = 1, 67 ui_entry_cursor_width = 2, 68 ui_entry_sel_hpad = 0, 69 ui_entry_sel_vpad = 2, 70 /** Additional amount to scroll to the left after revealing cursor */ 71 ui_entry_left_scroll_margin = 30 61 ui_entry_vpad_text = 0 72 62 }; 73 63 … … 76 66 .destroy = ui_entry_ctl_destroy, 77 67 .paint = ui_entry_ctl_paint, 78 .kbd_event = ui_entry_ctl_kbd_event,79 68 .pos_event = ui_entry_ctl_pos_event 80 69 }; … … 113 102 entry->halign = gfx_halign_left; 114 103 *rentry = entry; 115 116 104 return EOK; 117 105 } … … 158 146 { 159 147 entry->halign = halign; 160 ui_entry_scroll_update(entry, true);161 ui_entry_paint(entry);162 }163 164 /** Set text entry read-only flag.165 *166 * @param entry Text entry167 * @param read_only True iff entry is to be read-only.168 */169 void ui_entry_set_read_only(ui_entry_t *entry, bool read_only)170 {171 entry->read_only = read_only;172 148 } 173 149 … … 188 164 free(entry->text); 189 165 entry->text = tcopy; 190 entry->pos = str_size(text);191 entry->sel_start = entry->pos;192 193 ui_entry_scroll_update(entry, false);194 ui_entry_paint(entry);195 166 196 167 return EOK; 197 168 } 198 169 199 /** Get entry text. 200 * 201 * @return Pointer to entry text. 202 */ 203 const char *ui_entry_get_text(ui_entry_t *entry) 204 { 205 return entry->text; 206 } 207 208 /** Paint cursor. 209 * 210 * @param entry Text entry 211 * @param pos Cursor position (top-left corner of next character) 170 /** Paint text entry. 171 * 172 * @param entry Text entry 212 173 * @return EOK on success or an error code 213 174 */ 214 static errno_t ui_entry_paint_cursor(ui_entry_t *entry, gfx_coord2_t *pos)175 errno_t ui_entry_paint(ui_entry_t *entry) 215 176 { 216 177 ui_resource_t *res; 217 gfx_rect_t rect;218 gfx_font_metrics_t metrics;219 errno_t rc;220 221 res = ui_window_get_res(entry->window);222 223 if (res->textmode) {224 rc = gfx_cursor_set_pos(res->gc, pos);225 return rc;226 }227 228 gfx_font_get_metrics(res->font, &metrics);229 230 rect.p0.x = pos->x;231 rect.p0.y = pos->y - ui_entry_cursor_overshoot;232 rect.p1.x = pos->x + ui_entry_cursor_width;233 rect.p1.y = pos->y + metrics.ascent + metrics.descent + 1 +234 ui_entry_cursor_overshoot;235 236 rc = gfx_set_color(res->gc, res->entry_fg_color);237 if (rc != EOK)238 goto error;239 240 rc = gfx_fill_rect(res->gc, &rect);241 if (rc != EOK)242 goto error;243 244 return EOK;245 error:246 return rc;247 }248 249 /** Return width of text before cursor.250 *251 * @param entry Text entry252 * @return Widht of text before cursor253 */254 static gfx_coord_t ui_entry_lwidth(ui_entry_t *entry)255 {256 ui_resource_t *res;257 uint8_t tmp;258 gfx_coord_t width;259 260 res = ui_window_get_res(entry->window);261 262 tmp = entry->text[entry->pos];263 264 entry->text[entry->pos] = '\0';265 width = gfx_text_width(res->font, entry->text);266 entry->text[entry->pos] = tmp;267 268 return width;269 }270 271 /** Paint text entry.272 *273 * @param entry Text entry274 * @return EOK on success or an error code275 */276 errno_t ui_entry_paint(ui_entry_t *entry)277 {278 ui_resource_t *res;279 ui_entry_geom_t geom;280 178 gfx_text_fmt_t fmt; 281 179 gfx_coord2_t pos; 282 gfx_ text_fmt_t cfmt;283 gfx_coord 2_t cpos;180 gfx_coord_t hpad; 181 gfx_coord_t vpad; 284 182 gfx_rect_t inside; 285 unsigned off1, off2;286 gfx_rect_t sel;287 char c;288 183 errno_t rc; 289 184 290 185 res = ui_window_get_res(entry->window); 291 186 292 ui_entry_get_geom(entry, &geom); 187 if (res->textmode) { 188 hpad = ui_entry_hpad_text; 189 vpad = ui_entry_vpad_text; 190 } else { 191 hpad = ui_entry_hpad; 192 vpad = ui_entry_vpad; 193 } 293 194 294 195 if (res->textmode == false) { … … 311 212 goto error; 312 213 313 pos = geom.text_pos; 214 switch (entry->halign) { 215 case gfx_halign_left: 216 case gfx_halign_justify: 217 pos.x = inside.p0.x + hpad; 218 break; 219 case gfx_halign_center: 220 pos.x = (inside.p0.x + inside.p1.x) / 2; 221 break; 222 case gfx_halign_right: 223 pos.x = inside.p1.x - hpad - 1; 224 break; 225 } 226 227 pos.y = inside.p0.y + vpad; 314 228 315 229 gfx_text_fmt_init(&fmt); 316 fmt.font = res->font;317 230 fmt.color = res->entry_fg_color; 318 fmt.halign = gfx_halign_left;231 fmt.halign = entry->halign; 319 232 fmt.valign = gfx_valign_top; 320 233 321 rc = gfx_set_clip_rect(res->gc, &inside); 322 if (rc != EOK) 323 goto error; 324 325 off1 = min(entry->pos, entry->sel_start); 326 off2 = max(entry->pos, entry->sel_start); 327 328 /* Render initial segment before start of selection */ 329 c = entry->text[off1]; 330 entry->text[off1] = '\0'; 331 332 rc = gfx_puttext(&pos, &fmt, entry->text); 333 if (rc != EOK) { 334 (void) gfx_set_clip_rect(res->gc, NULL); 335 goto error; 336 } 337 338 gfx_text_cont(&pos, &fmt, entry->text, &cpos, &cfmt); 339 entry->text[off1] = c; 340 341 /* Render selected text */ 342 343 if (off1 != off2) { 344 c = entry->text[off2]; 345 entry->text[off2] = '\0'; 346 cfmt.color = res->entry_sel_text_fg_color; 347 348 gfx_text_rect(&cpos, &cfmt, entry->text + off1, &sel); 349 sel.p0.x -= ui_entry_sel_hpad; 350 sel.p0.y -= ui_entry_sel_vpad; 351 sel.p1.x += ui_entry_sel_hpad; 352 sel.p1.y += ui_entry_sel_vpad; 353 354 rc = gfx_set_color(res->gc, res->entry_sel_text_bg_color); 355 if (rc != EOK) 356 goto error; 357 358 rc = gfx_fill_rect(res->gc, &sel); 359 if (rc != EOK) 360 goto error; 361 362 rc = gfx_puttext(&cpos, &cfmt, entry->text + off1); 363 if (rc != EOK) { 364 (void) gfx_set_clip_rect(res->gc, NULL); 365 goto error; 366 } 367 368 gfx_text_cont(&cpos, &cfmt, entry->text + off1, &cpos, &cfmt); 369 370 entry->text[off2] = c; 371 } 372 373 /* Render trailing, non-selected text */ 374 cfmt.color = res->entry_fg_color; 375 376 rc = gfx_puttext(&cpos, &cfmt, entry->text + off2); 377 if (rc != EOK) { 378 (void) gfx_set_clip_rect(res->gc, NULL); 379 goto error; 380 } 381 382 if (entry->active) { 383 /* Cursor */ 384 pos.x += ui_entry_lwidth(entry); 385 386 rc = ui_entry_paint_cursor(entry, &pos); 387 if (rc != EOK) { 388 (void) gfx_set_clip_rect(res->gc, NULL); 389 goto error; 390 } 391 } 392 393 rc = gfx_set_clip_rect(res->gc, NULL); 234 rc = gfx_puttext(res->font, &pos, &fmt, entry->text); 394 235 if (rc != EOK) 395 236 goto error; … … 404 245 } 405 246 406 /** Find position in text entry.407 *408 * @param entry Text entry409 * @param fpos Position for which we need to find text offset410 * @return Corresponding byte offset in entry text411 */412 size_t ui_entry_find_pos(ui_entry_t *entry, gfx_coord2_t *fpos)413 {414 ui_resource_t *res;415 ui_entry_geom_t geom;416 gfx_text_fmt_t fmt;417 418 res = ui_window_get_res(entry->window);419 420 ui_entry_get_geom(entry, &geom);421 422 gfx_text_fmt_init(&fmt);423 fmt.font = res->font;424 fmt.halign = gfx_halign_left;425 fmt.valign = gfx_valign_top;426 427 return gfx_text_find_pos(&geom.text_pos, &fmt, entry->text, fpos);428 }429 430 247 /** Destroy text entry control. 431 248 * … … 451 268 } 452 269 453 /** Delete selected text. 454 * 455 * @param entry Text entry 456 */ 457 void ui_entry_delete_sel(ui_entry_t *entry) 458 { 459 size_t off1; 460 size_t off2; 461 462 off1 = min(entry->sel_start, entry->pos); 463 off2 = max(entry->sel_start, entry->pos); 464 465 memmove(entry->text + off1, entry->text + off2, 466 str_size(entry->text + off2) + 1); 467 468 entry->pos = off1; 469 entry->sel_start = off1; 470 ui_entry_scroll_update(entry, false); 471 ui_entry_paint(entry); 472 } 473 474 /** Insert string at cursor position. 475 * 476 * @param entry Text entry 477 * @param str String 478 * @return EOK on success, ENOMEM if out of memory 479 */ 480 errno_t ui_entry_insert_str(ui_entry_t *entry, const char *str) 481 { 482 uint8_t tmp; 483 char *ltext = NULL; 484 char *newtext; 485 char *oldtext; 486 int rc; 487 488 /* Do we have a selection? */ 489 if (entry->sel_start != entry->pos) 490 ui_entry_delete_sel(entry); 491 492 tmp = entry->text[entry->pos]; 493 entry->text[entry->pos] = '\0'; 494 ltext = str_dup(entry->text); 495 if (ltext == NULL) 496 return ENOMEM; 497 498 entry->text[entry->pos] = tmp; 499 500 rc = asprintf(&newtext, "%s%s%s", ltext, str, entry->text + entry->pos); 501 if (rc < 0) { 502 free(ltext); 503 return ENOMEM; 504 } 505 506 oldtext = entry->text; 507 entry->text = newtext; 508 entry->pos += str_size(str); 509 free(oldtext); 510 free(ltext); 511 512 entry->sel_start = entry->pos; 513 ui_entry_scroll_update(entry, false); 514 ui_entry_paint(entry); 515 516 return EOK; 517 } 518 519 /** Delete character before cursor. 520 * 521 * @param entry Text entry 522 */ 523 void ui_entry_backspace(ui_entry_t *entry) 524 { 525 size_t off; 526 527 /* Do we have a selection? */ 528 if (entry->sel_start != entry->pos) { 529 ui_entry_delete_sel(entry); 530 return; 531 } 532 533 if (entry->pos == 0) 534 return; 535 536 /* Find offset where character before cursor starts */ 537 off = entry->pos; 538 (void) str_decode_reverse(entry->text, &off, 539 str_size(entry->text)); 540 541 memmove(entry->text + off, entry->text + entry->pos, 542 str_size(entry->text + entry->pos) + 1); 543 entry->pos = off; 544 entry->sel_start = off; 545 546 ui_entry_scroll_update(entry, false); 547 ui_entry_paint(entry); 548 } 549 550 /** Delete character after cursor. 551 * 552 * @param entry Text entry 553 */ 554 void ui_entry_delete(ui_entry_t *entry) 555 { 556 size_t off; 557 558 /* Do we have a selection? */ 559 if (entry->sel_start != entry->pos) { 560 ui_entry_delete_sel(entry); 561 return; 562 } 563 564 /* Find offset where character after cursor ends */ 565 off = entry->pos; 566 (void) str_decode(entry->text, &off, 567 str_size(entry->text)); 568 569 memmove(entry->text + entry->pos, entry->text + off, 570 str_size(entry->text + off) + 1); 571 572 ui_entry_scroll_update(entry, false); 573 ui_entry_paint(entry); 574 } 575 576 /** Copy selected text to clipboard. 577 * 578 * @param entry Text entry 579 */ 580 void ui_entry_copy(ui_entry_t *entry) 581 { 582 unsigned off1; 583 unsigned off2; 584 char c; 585 586 off1 = min(entry->pos, entry->sel_start); 587 off2 = max(entry->pos, entry->sel_start); 588 589 c = entry->text[off2]; 590 entry->text[off2] = '\0'; 591 592 (void) clipboard_put_str(entry->text + off1); 593 594 entry->text[off2] = c; 595 } 596 597 /** Cut selected text to clipboard. 598 * 599 * @param entry Text entry 600 */ 601 void ui_entry_cut(ui_entry_t *entry) 602 { 603 ui_entry_copy(entry); 604 ui_entry_delete_sel(entry); 605 } 606 607 /** Paste text from clipboard. 608 * 609 * @param entry Text entry 610 */ 611 void ui_entry_paste(ui_entry_t *entry) 612 { 613 char *str; 614 errno_t rc; 615 616 rc = clipboard_get_str(&str); 617 if (rc != EOK) 618 return; 619 620 ui_entry_insert_str(entry, str); 621 free(str); 622 } 623 624 /** Handle text entry key press without modifiers. 625 * 626 * @param entry Text entry 627 * @param kbd_event Keyboard event 628 * @return @c ui_claimed iff the event is claimed 629 */ 630 ui_evclaim_t ui_entry_key_press_unmod(ui_entry_t *entry, kbd_event_t *event) 631 { 632 assert(event->type == KEY_PRESS); 633 634 switch (event->key) { 635 case KC_BACKSPACE: 636 ui_entry_backspace(entry); 637 break; 638 639 case KC_DELETE: 640 ui_entry_delete(entry); 641 break; 642 643 case KC_ESCAPE: 644 ui_entry_deactivate(entry); 645 break; 646 647 case KC_HOME: 648 ui_entry_seek_start(entry, false); 649 break; 650 651 case KC_END: 652 ui_entry_seek_end(entry, false); 653 break; 654 655 case KC_LEFT: 656 ui_entry_seek_prev_char(entry, false); 657 break; 658 659 case KC_RIGHT: 660 ui_entry_seek_next_char(entry, false); 661 break; 662 663 default: 664 break; 665 } 666 return ui_claimed; 667 } 668 669 /** Handle text entry key press with shift modifier. 670 * 671 * @param entry Text entry 672 * @param kbd_event Keyboard event 673 * @return @c ui_claimed iff the event is claimed 674 */ 675 ui_evclaim_t ui_entry_key_press_shift(ui_entry_t *entry, kbd_event_t *event) 676 { 677 assert(event->type == KEY_PRESS); 678 679 switch (event->key) { 680 case KC_HOME: 681 ui_entry_seek_start(entry, true); 682 break; 683 684 case KC_END: 685 ui_entry_seek_end(entry, true); 686 break; 687 688 case KC_LEFT: 689 ui_entry_seek_prev_char(entry, true); 690 break; 691 692 case KC_RIGHT: 693 ui_entry_seek_next_char(entry, true); 694 break; 695 696 default: 697 break; 698 } 699 700 return ui_claimed; 701 } 702 703 /** Handle text entry key press with control modifier. 704 * 705 * @param entry Text entry 706 * @param kbd_event Keyboard event 707 * @return @c ui_claimed iff the event is claimed 708 */ 709 ui_evclaim_t ui_entry_key_press_ctrl(ui_entry_t *entry, kbd_event_t *event) 710 { 711 assert(event->type == KEY_PRESS); 712 713 switch (event->key) { 714 case KC_C: 715 ui_entry_copy(entry); 716 break; 717 case KC_V: 718 ui_entry_paste(entry); 719 break; 720 case KC_X: 721 ui_entry_cut(entry); 722 break; 723 default: 724 break; 725 } 726 727 return ui_claimed; 728 } 729 730 /** Handle text entry keyboard event. 731 * 732 * @param entry Text entry 733 * @param kbd_event Keyboard event 734 * @return @c ui_claimed iff the event is claimed 735 */ 736 ui_evclaim_t ui_entry_kbd_event(ui_entry_t *entry, kbd_event_t *event) 737 { 738 char buf[STR_BOUNDS(1) + 1]; 739 size_t off; 740 errno_t rc; 741 742 if (!entry->active) 743 return ui_unclaimed; 744 745 /* 746 * Need to keep track if any shift is held for the case 747 * of selecting by shift-click. This could be simplified 748 * if position events were decorated with modifier 749 * state. 750 */ 751 752 if (event->type == KEY_PRESS && event->key == KC_LSHIFT) 753 entry->lshift_held = true; 754 if (event->type == KEY_RELEASE && event->key == KC_LSHIFT) 755 entry->lshift_held = false; 756 if (event->type == KEY_PRESS && event->key == KC_RSHIFT) 757 entry->rshift_held = true; 758 if (event->type == KEY_RELEASE && event->key == KC_RSHIFT) 759 entry->rshift_held = false; 760 761 if (event->type == KEY_PRESS && 762 (event->mods & (KM_CTRL | KM_ALT)) == 0 && event->c >= ' ') { 763 off = 0; 764 rc = chr_encode(event->c, buf, &off, sizeof(buf)); 765 if (rc == EOK) { 766 buf[off] = '\0'; 767 (void) ui_entry_insert_str(entry, buf); 768 } 769 } 770 771 if (event->type == KEY_PRESS && 772 (event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) 773 return ui_entry_key_press_unmod(entry, event); 774 775 if (event->type == KEY_PRESS && 776 (event->mods & KM_SHIFT) != 0 && 777 (event->mods & (KM_CTRL | KM_ALT)) == 0) 778 return ui_entry_key_press_shift(entry, event); 779 780 if (event->type == KEY_PRESS && 781 (event->mods & KM_CTRL) != 0 && 782 (event->mods & (KM_ALT | KM_SHIFT)) == 0) 783 return ui_entry_key_press_ctrl(entry, event); 784 785 return ui_claimed; 786 } 787 788 /** Handle text entry position event. 789 * 790 * @param entry Text entry 270 /** Handle text entry control position event. 271 * 272 * @param arg Argument (ui_entry_t *) 791 273 * @param pos_event Position event 792 274 * @return @c ui_claimed iff the event is claimed 793 275 */ 794 ui_evclaim_t ui_entry_pos_event(ui_entry_t *entry, pos_event_t *event) 795 { 276 ui_evclaim_t ui_entry_ctl_pos_event(void *arg, pos_event_t *event) 277 { 278 ui_entry_t *entry = (ui_entry_t *) arg; 796 279 gfx_coord2_t pos; 797 798 if (entry->read_only)799 return ui_unclaimed;800 280 801 281 if (event->type == POS_UPDATE) { … … 803 283 pos.y = event->vpos; 804 284 805 /* Change cursor shape when pointer is entering/leaving */806 285 if (gfx_pix_inside_rect(&pos, &entry->rect)) { 807 286 if (!entry->pointer_inside) { … … 817 296 } 818 297 } 819 820 if (entry->held) {821 /*822 * Selecting using mouse drag: Change pos,823 * keep sel_start824 */825 entry->pos = ui_entry_find_pos(entry, &pos);826 ui_entry_paint(entry);827 }828 }829 830 if (event->type == POS_PRESS) {831 pos.x = event->hpos;832 pos.y = event->vpos;833 834 if (gfx_pix_inside_rect(&pos, &entry->rect)) {835 /* Clicked inside - activate, set position */836 entry->held = true;837 entry->pos = ui_entry_find_pos(entry, &pos);838 839 /* Clear selection if no shift key is held */840 if (!entry->lshift_held && !entry->rshift_held)841 entry->sel_start = entry->pos;842 843 if (entry->active)844 ui_entry_paint(entry);845 else846 ui_entry_activate(entry);847 848 return ui_claimed;849 } else {850 /* Clicked outside - deactivate */851 ui_entry_deactivate(entry);852 }853 }854 855 if (event->type == POS_RELEASE) {856 entry->held = false;857 298 } 858 299 … … 860 301 } 861 302 862 /** Handle text entry control keyboard event.863 *864 * @param arg Argument (ui_entry_t *)865 * @param kbd_event Keyboard event866 * @return @c ui_claimed iff the event is claimed867 */868 static ui_evclaim_t ui_entry_ctl_kbd_event(void *arg, kbd_event_t *event)869 {870 ui_entry_t *entry = (ui_entry_t *) arg;871 872 return ui_entry_kbd_event(entry, event);873 }874 875 /** Handle text entry control position event.876 *877 * @param arg Argument (ui_entry_t *)878 * @param pos_event Position event879 * @return @c ui_claimed iff the event is claimed880 */881 static ui_evclaim_t ui_entry_ctl_pos_event(void *arg, pos_event_t *event)882 {883 ui_entry_t *entry = (ui_entry_t *) arg;884 885 return ui_entry_pos_event(entry, event);886 }887 888 /** Get text entry geometry.889 *890 * @param entry Text entry891 * @param geom Structure to fill in with computed geometry892 */893 void ui_entry_get_geom(ui_entry_t *entry, ui_entry_geom_t *geom)894 {895 gfx_coord_t hpad;896 gfx_coord_t vpad;897 ui_resource_t *res;898 899 res = ui_window_get_res(entry->window);900 901 if (res->textmode) {902 hpad = ui_entry_hpad_text;903 vpad = ui_entry_vpad_text;904 } else {905 hpad = ui_entry_hpad;906 vpad = ui_entry_vpad;907 }908 909 if (res->textmode == false) {910 ui_paint_get_inset_frame_inside(res, &entry->rect,911 &geom->interior_rect);912 } else {913 geom->interior_rect = entry->rect;914 }915 916 geom->text_rect.p0.x = geom->interior_rect.p0.x + hpad;917 geom->text_rect.p0.y = geom->interior_rect.p0.y + vpad;918 geom->text_rect.p1.x = geom->interior_rect.p1.x - hpad;919 geom->text_rect.p1.y = geom->interior_rect.p1.y - vpad;920 921 geom->text_pos.x = geom->interior_rect.p0.x + hpad +922 entry->scroll_pos;923 geom->text_pos.y = geom->interior_rect.p0.y + vpad;924 925 switch (entry->halign) {926 case gfx_halign_left:927 case gfx_halign_justify:928 geom->anchor_x = geom->text_rect.p0.x;929 break;930 case gfx_halign_center:931 geom->anchor_x = (geom->text_rect.p0.x +932 geom->text_rect.p1.x) / 2;933 break;934 case gfx_halign_right:935 geom->anchor_x = geom->text_rect.p1.x;936 break;937 }938 }939 940 /** Activate text entry.941 *942 * @param entry Text entry943 */944 void ui_entry_activate(ui_entry_t *entry)945 {946 ui_resource_t *res;947 948 res = ui_window_get_res(entry->window);949 950 if (entry->active)951 return;952 953 entry->active = true;954 (void) ui_entry_paint(entry);955 956 if (res->textmode)957 gfx_cursor_set_visible(res->gc, true);958 }959 960 /** Move text cursor to the beginning of text.961 *962 * @param entry Text entry963 * @param shift @c true iff shift key is pressed964 */965 void ui_entry_seek_start(ui_entry_t *entry, bool shift)966 {967 entry->pos = 0;968 969 if (!shift)970 entry->sel_start = entry->pos;971 972 ui_entry_scroll_update(entry, false);973 (void) ui_entry_paint(entry);974 }975 976 /** Move text cursor to the end of text.977 *978 * @param entry Text entry979 * @param shift @c true iff shift key is pressed980 */981 void ui_entry_seek_end(ui_entry_t *entry, bool shift)982 {983 entry->pos = str_size(entry->text);984 985 if (!shift)986 entry->sel_start = entry->pos;987 988 ui_entry_scroll_update(entry, false);989 (void) ui_entry_paint(entry);990 }991 992 /** Move text cursor one character backward.993 *994 * @param entry Text entry995 * @param shift @c true iff shift key is pressed996 */997 void ui_entry_seek_prev_char(ui_entry_t *entry, bool shift)998 {999 size_t off;1000 1001 off = entry->pos;1002 (void) str_decode_reverse(entry->text, &off,1003 str_size(entry->text));1004 entry->pos = off;1005 1006 if (!shift)1007 entry->sel_start = entry->pos;1008 1009 ui_entry_scroll_update(entry, false);1010 (void) ui_entry_paint(entry);1011 }1012 1013 /** Move text cursor one character forward.1014 *1015 * @param entry Text entry1016 * @param shift @c true iff shift key is pressed1017 */1018 void ui_entry_seek_next_char(ui_entry_t *entry, bool shift)1019 {1020 size_t off;1021 1022 off = entry->pos;1023 (void) str_decode(entry->text, &off,1024 str_size(entry->text));1025 entry->pos = off;1026 1027 if (!shift)1028 entry->sel_start = entry->pos;1029 1030 ui_entry_scroll_update(entry, false);1031 (void) ui_entry_paint(entry);1032 }1033 1034 /** Deactivate text entry.1035 *1036 * @param entry Text entry1037 */1038 void ui_entry_deactivate(ui_entry_t *entry)1039 {1040 ui_resource_t *res;1041 1042 res = ui_window_get_res(entry->window);1043 1044 if (!entry->active)1045 return;1046 1047 entry->active = false;1048 entry->sel_start = entry->pos;1049 (void) ui_entry_paint(entry);1050 1051 if (res->textmode)1052 gfx_cursor_set_visible(res->gc, false);1053 }1054 1055 /** Update text entry scroll position.1056 *1057 * @param entry Text entry1058 * @param realign @c true iff we should left-align short text.1059 * This should be only used when changing text alignment,1060 * because left-aligned text entries should not realign1061 * the text to the left side under normal circumstances.1062 */1063 void ui_entry_scroll_update(ui_entry_t *entry, bool realign)1064 {1065 ui_entry_geom_t geom;1066 gfx_coord_t x;1067 gfx_coord_t width;1068 gfx_coord2_t tpos;1069 gfx_coord2_t anchor;1070 gfx_text_fmt_t fmt;1071 ui_resource_t *res;1072 1073 res = ui_window_get_res(entry->window);1074 1075 ui_entry_get_geom(entry, &geom);1076 1077 /* Compute position where cursor is currently displayed at */1078 x = geom.text_pos.x + ui_entry_lwidth(entry);1079 1080 /* Is cursor off to the left? */1081 if (x < geom.text_rect.p0.x) {1082 /*1083 * Scroll to make cursor visible and put some space between it1084 * and the left edge of the text rectangle.1085 */1086 entry->scroll_pos += geom.text_rect.p0.x - x +1087 ui_entry_left_scroll_margin;1088 1089 /*1090 * We don't want to scroll further than what's needed1091 * to reveal the beginning of the text.1092 */1093 if (entry->scroll_pos > 0)1094 entry->scroll_pos = 0;1095 }1096 1097 /*1098 * Is cursor off to the right? Note that the width of the cursor1099 * is deliberately not taken into account (i.e. we only care1100 * about the left edge of the cursor).1101 */1102 if (x > geom.text_rect.p1.x)1103 entry->scroll_pos -= x - geom.text_rect.p1.x;1104 1105 width = gfx_text_width(res->font, entry->text);1106 1107 if (width < geom.text_rect.p1.x - geom.text_rect.p0.x &&1108 (realign || entry->halign != gfx_halign_left)) {1109 /* Text fits inside entry, so we need to align it */1110 anchor.x = geom.anchor_x;1111 anchor.y = 0;1112 gfx_text_fmt_init(&fmt);1113 fmt.font = res->font;1114 fmt.halign = entry->halign;1115 gfx_text_start_pos(&anchor, &fmt, entry->text, &tpos);1116 entry->scroll_pos = tpos.x - geom.text_rect.p0.x;1117 } else if (geom.text_pos.x + width < geom.text_rect.p1.x &&1118 entry->halign != gfx_halign_left) {1119 /* Text is long, unused space on the right */1120 entry->scroll_pos += geom.text_rect.p1.x -1121 geom.text_pos.x - width;1122 }1123 }1124 1125 303 /** @} 1126 304 */
Note:
See TracChangeset
for help on using the changeset viewer.