Changes in uspace/lib/ui/src/paint.c [d63623f:1eaead4] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/paint.c
rd63623f r1eaead4 1 1 /* 2 * Copyright (c) 202 1Jiri Svoboda2 * Copyright (c) 2023 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 38 38 #include <gfx/context.h> 39 39 #include <gfx/render.h> 40 #include <gfx/text.h> 41 #include <ui/accel.h> 40 42 #include <ui/paint.h> 43 #include <stdlib.h> 44 #include <str.h> 41 45 #include "../private/resource.h" 46 47 /** Single box characters */ 48 static ui_box_chars_t single_box_chars = { 49 { 50 { "\u250c", "\u2500", "\u2510" }, 51 { "\u2502", " ", "\u2502" }, 52 { "\u2514", "\u2500", "\u2518" } 53 } 54 }; 55 56 /** Double box characters */ 57 static ui_box_chars_t double_box_chars = { 58 { 59 { "\u2554", "\u2550", "\u2557" }, 60 { "\u2551", " ", "\u2551" }, 61 { "\u255a", "\u2550", "\u255d" } 62 } 63 }; 64 65 /** Single horizontal brace characters */ 66 static ui_brace_chars_t single_hbrace_chars = { 67 .start = "\u251c", 68 .middle = "\u2500", 69 .end = "\u2524" 70 }; 71 72 /** Double horizontal brace characters */ 73 static ui_brace_chars_t double_hbrace_chars = { 74 .start = "\u2560", 75 .middle = "\u2550", 76 .end = "\u2563" 77 }; 42 78 43 79 /** Paint bevel. … … 324 360 } 325 361 362 /** Paint upward pointing triangle. 363 * 364 * @param gc Graphic context 365 * @param pos Center position 366 * @param n Length of triangle side 367 * @return EOK on success or an error code 368 */ 369 errno_t ui_paint_up_triangle(gfx_context_t *gc, gfx_coord2_t *pos, 370 gfx_coord_t n) 371 { 372 gfx_coord_t i; 373 errno_t rc; 374 gfx_rect_t rect; 375 376 for (i = 0; i < n; i++) { 377 rect.p0.x = pos->x - i; 378 rect.p0.y = pos->y - n / 2 + i; 379 rect.p1.x = pos->x + i + 1; 380 rect.p1.y = pos->y - n / 2 + i + 1; 381 rc = gfx_fill_rect(gc, &rect); 382 if (rc != EOK) 383 return rc; 384 } 385 386 return EOK; 387 } 388 389 /** Paint downward pointing triangle. 390 * 391 * @param gc Graphic context 392 * @param pos Center position 393 * @param n Length of triangle side 394 * @return EOK on success or an error code 395 */ 396 errno_t ui_paint_down_triangle(gfx_context_t *gc, gfx_coord2_t *pos, 397 gfx_coord_t n) 398 { 399 gfx_coord_t i; 400 errno_t rc; 401 gfx_rect_t rect; 402 403 for (i = 0; i < n; i++) { 404 rect.p0.x = pos->x - i; 405 rect.p0.y = pos->y + n / 2 - i; 406 rect.p1.x = pos->x + i + 1; 407 rect.p1.y = pos->y + n / 2 - i + 1; 408 rc = gfx_fill_rect(gc, &rect); 409 if (rc != EOK) 410 return rc; 411 } 412 413 return EOK; 414 } 415 416 /** Paint left pointing triangle. 417 * 418 * @param gc Graphic context 419 * @param pos Center position 420 * @param n Length of triangle side 421 * @return EOK on success or an error code 422 */ 423 errno_t ui_paint_left_triangle(gfx_context_t *gc, gfx_coord2_t *pos, 424 gfx_coord_t n) 425 { 426 gfx_coord_t i; 427 errno_t rc; 428 gfx_rect_t rect; 429 430 for (i = 0; i < n; i++) { 431 rect.p0.x = pos->x - n / 2 + i; 432 rect.p0.y = pos->y - i; 433 rect.p1.x = pos->x - n / 2 + i + 1; 434 rect.p1.y = pos->y + i + 1; 435 rc = gfx_fill_rect(gc, &rect); 436 if (rc != EOK) 437 return rc; 438 } 439 440 return EOK; 441 } 442 443 /** Paint right pointing triangle. 444 * 445 * @param gc Graphic context 446 * @param pos Center position 447 * @param n Length of triangle side 448 * @return EOK on success or an error code 449 */ 450 errno_t ui_paint_right_triangle(gfx_context_t *gc, gfx_coord2_t *pos, 451 gfx_coord_t n) 452 { 453 gfx_coord_t i; 454 errno_t rc; 455 gfx_rect_t rect; 456 457 for (i = 0; i < n; i++) { 458 rect.p0.x = pos->x + n / 2 - i; 459 rect.p0.y = pos->y - i; 460 rect.p1.x = pos->x + n / 2 - i + 1; 461 rect.p1.y = pos->y + i + 1; 462 rc = gfx_fill_rect(gc, &rect); 463 if (rc != EOK) 464 return rc; 465 } 466 467 return EOK; 468 } 469 470 /** Paint diagonal cross (X). 471 * 472 * @param gc Graphic context 473 * @param pos Center position 474 * @param n Length of each leg 475 * @param w Pen width 476 * @param h Pen height 477 * @return EOK on success or an error code 478 */ 479 errno_t ui_paint_cross(gfx_context_t *gc, gfx_coord2_t *pos, 480 gfx_coord_t n, gfx_coord_t w, gfx_coord_t h) 481 { 482 gfx_coord_t i; 483 gfx_rect_t rect; 484 errno_t rc; 485 486 rect.p0.x = pos->x; 487 rect.p0.y = pos->y; 488 rect.p1.x = pos->x + w; 489 rect.p1.y = pos->y + h; 490 rc = gfx_fill_rect(gc, &rect); 491 if (rc != EOK) 492 return rc; 493 494 for (i = 1; i < n; i++) { 495 rect.p0.x = pos->x - i; 496 rect.p0.y = pos->y - i; 497 rect.p1.x = pos->x - i + w; 498 rect.p1.y = pos->y - i + h; 499 rc = gfx_fill_rect(gc, &rect); 500 if (rc != EOK) 501 return rc; 502 503 rect.p0.x = pos->x - i; 504 rect.p0.y = pos->y + i; 505 rect.p1.x = pos->x - i + w; 506 rect.p1.y = pos->y + i + h; 507 rc = gfx_fill_rect(gc, &rect); 508 if (rc != EOK) 509 return rc; 510 511 rect.p0.x = pos->x + i; 512 rect.p0.y = pos->y - i; 513 rect.p1.x = pos->x + i + w; 514 rect.p1.y = pos->y - i + h; 515 rc = gfx_fill_rect(gc, &rect); 516 if (rc != EOK) 517 return rc; 518 519 rect.p0.x = pos->x + i; 520 rect.p0.y = pos->y + i; 521 rect.p1.x = pos->x + i + w; 522 rect.p1.y = pos->y + i + h; 523 rc = gfx_fill_rect(gc, &rect); 524 if (rc != EOK) 525 return rc; 526 } 527 528 return EOK; 529 } 530 531 /** Paint minimize icon. 532 * 533 * @param resource UI resource 534 * @param pos Center position 535 * @param w Icon width 536 * @param h Icon height 537 * @return EOK on success or an error code 538 */ 539 errno_t ui_paint_minicon(ui_resource_t *resource, gfx_coord2_t *pos, 540 gfx_coord_t w, gfx_coord_t h) 541 { 542 gfx_rect_t rect; 543 errno_t rc; 544 545 rc = gfx_set_color(resource->gc, resource->btn_text_color); 546 if (rc != EOK) 547 return rc; 548 549 rect.p0.x = pos->x - w / 2; 550 rect.p0.y = pos->y + h / 2 - 2; 551 rect.p1.x = rect.p0.x + w; 552 rect.p1.y = rect.p0.y + 2; 553 rc = gfx_fill_rect(resource->gc, &rect); 554 if (rc != EOK) 555 return rc; 556 557 return EOK; 558 } 559 560 /** Paint maximize icon. 561 * 562 * @param resource UI resource 563 * @param pos Center position 564 * @param w Icon width 565 * @param h Icon height 566 * @return EOK on success or an error code 567 */ 568 errno_t ui_paint_maxicon(ui_resource_t *resource, gfx_coord2_t *pos, 569 gfx_coord_t w, gfx_coord_t h) 570 { 571 gfx_rect_t rect; 572 errno_t rc; 573 574 rc = gfx_set_color(resource->gc, resource->btn_text_color); 575 if (rc != EOK) 576 return rc; 577 578 rect.p0.x = pos->x - w / 2; 579 rect.p0.y = pos->y - h / 2; 580 rect.p1.x = rect.p0.x + w; 581 rect.p1.y = rect.p0.y + h; 582 rc = gfx_fill_rect(resource->gc, &rect); 583 if (rc != EOK) 584 return rc; 585 586 rc = gfx_set_color(resource->gc, resource->btn_face_color); 587 if (rc != EOK) 588 return rc; 589 590 rect.p0.x += 1; 591 rect.p0.y += 2; 592 rect.p1.x -= 1; 593 rect.p1.y -= 1; 594 rc = gfx_fill_rect(resource->gc, &rect); 595 if (rc != EOK) 596 return rc; 597 598 return EOK; 599 } 600 601 /** Paint unmaximize icon. 602 * 603 * Unmaximize icon consists of two overlapping window icons. 604 * 605 * @param resource UI resource 606 * @param pos Center position 607 * @param w Window icon width 608 * @param h Window icon height 609 * @param dw Horizontal distance between window icon centers 610 * @param dh Vertical distance between window icon centers 611 * @return EOK on success or an error code 612 */ 613 errno_t ui_paint_unmaxicon(ui_resource_t *resource, gfx_coord2_t *pos, 614 gfx_coord_t w, gfx_coord_t h, gfx_coord_t dw, gfx_coord_t dh) 615 { 616 gfx_coord2_t p; 617 errno_t rc; 618 619 p.x = pos->x + dw / 2; 620 p.y = pos->y - dh / 2; 621 rc = ui_paint_maxicon(resource, &p, w, h); 622 if (rc != EOK) 623 return rc; 624 625 p.x = pos->x - dw / 2; 626 p.y = pos->y + dh / 2; 627 rc = ui_paint_maxicon(resource, &p, w, h); 628 if (rc != EOK) 629 return rc; 630 631 return EOK; 632 } 633 634 /** Paint a custom text box. 635 * 636 * Paint a text box using user-provided box chars. 637 * 638 * @param resource UI resource 639 * @param rect Rectangle inside which to paint the box 640 * @param style Box style 641 * @param boxc Box characters 642 * @param color Color 643 * @return EOK on success or an error code 644 */ 645 errno_t ui_paint_text_box_custom(ui_resource_t *resource, gfx_rect_t *rect, 646 ui_box_chars_t *boxc, gfx_color_t *color) 647 { 648 errno_t rc; 649 gfx_text_fmt_t fmt; 650 gfx_rect_t srect; 651 gfx_coord2_t pos; 652 gfx_coord2_t dim; 653 size_t bufsz; 654 size_t off; 655 int i; 656 gfx_coord_t y; 657 char *str = NULL; 658 659 gfx_rect_points_sort(rect, &srect); 660 gfx_rect_dims(&srect, &dim); 661 662 /* Is rectangle large enough to hold box? */ 663 if (dim.x < 2 || dim.y < 2) 664 return EOK; 665 666 gfx_text_fmt_init(&fmt); 667 fmt.font = resource->font; 668 fmt.color = color; 669 670 bufsz = str_size(boxc->c[0][0]) + 671 str_size(boxc->c[0][1]) * (dim.x - 2) + 672 str_size(boxc->c[0][2]) + 1; 673 674 str = malloc(bufsz); 675 if (str == NULL) 676 return ENOMEM; 677 678 /* Top edge and corners */ 679 680 str_cpy(str, bufsz, boxc->c[0][0]); 681 off = str_size(boxc->c[0][0]); 682 683 for (i = 1; i < dim.x - 1; i++) { 684 str_cpy(str + off, bufsz - off, boxc->c[0][1]); 685 off += str_size(boxc->c[0][1]); 686 } 687 688 str_cpy(str + off, bufsz - off, boxc->c[0][2]); 689 off += str_size(boxc->c[0][2]); 690 str[off] = '\0'; 691 692 pos = rect->p0; 693 rc = gfx_puttext(&pos, &fmt, str); 694 if (rc != EOK) 695 goto error; 696 697 /* Vertical edges */ 698 for (y = rect->p0.y + 1; y < rect->p1.y - 1; y++) { 699 pos.y = y; 700 701 pos.x = rect->p0.x; 702 rc = gfx_puttext(&pos, &fmt, boxc->c[1][0]); 703 if (rc != EOK) 704 goto error; 705 706 pos.x = rect->p1.x - 1; 707 rc = gfx_puttext(&pos, &fmt, boxc->c[1][2]); 708 if (rc != EOK) 709 goto error; 710 } 711 712 /* Bottom edge and corners */ 713 714 str_cpy(str, bufsz, boxc->c[2][0]); 715 off = str_size(boxc->c[2][0]); 716 717 for (i = 1; i < dim.x - 1; i++) { 718 str_cpy(str + off, bufsz - off, boxc->c[2][1]); 719 off += str_size(boxc->c[2][1]); 720 } 721 722 str_cpy(str + off, bufsz - off, boxc->c[2][2]); 723 off += str_size(boxc->c[2][2]); 724 str[off] = '\0'; 725 726 pos.x = rect->p0.x; 727 pos.y = rect->p1.y - 1; 728 rc = gfx_puttext(&pos, &fmt, str); 729 if (rc != EOK) 730 goto error; 731 732 free(str); 733 return EOK; 734 error: 735 if (str != NULL) 736 free(str); 737 return rc; 738 } 739 740 /** Paint a text box. 741 * 742 * Paint a text box with the specified style. 743 * 744 * @param resource UI resource 745 * @param rect Rectangle inside which to paint the box 746 * @param style Box style 747 * @param color Color 748 * @return EOK on success or an error code 749 */ 750 errno_t ui_paint_text_box(ui_resource_t *resource, gfx_rect_t *rect, 751 ui_box_style_t style, gfx_color_t *color) 752 { 753 ui_box_chars_t *boxc = NULL; 754 755 switch (style) { 756 case ui_box_single: 757 boxc = &single_box_chars; 758 break; 759 case ui_box_double: 760 boxc = &double_box_chars; 761 break; 762 } 763 764 if (boxc == NULL) 765 return EINVAL; 766 767 return ui_paint_text_box_custom(resource, rect, boxc, color); 768 } 769 770 /** Paint a text horizontal brace. 771 * 772 * @param resource UI resource 773 * @param rect Rectangle inside which to paint the brace (height should 774 * be 1). 775 * @param style Box style 776 * @param color Color 777 * @return EOK on success or an error code 778 */ 779 errno_t ui_paint_text_hbrace(ui_resource_t *resource, gfx_rect_t *rect, 780 ui_box_style_t style, gfx_color_t *color) 781 { 782 errno_t rc; 783 gfx_text_fmt_t fmt; 784 gfx_rect_t srect; 785 gfx_coord2_t pos; 786 gfx_coord2_t dim; 787 size_t bufsz; 788 size_t off; 789 int i; 790 char *str = NULL; 791 ui_brace_chars_t *hbc = NULL; 792 793 gfx_rect_points_sort(rect, &srect); 794 gfx_rect_dims(&srect, &dim); 795 796 /* Is rectangle large enough to hold brace? */ 797 if (dim.x < 2 || dim.y < 1) 798 return EOK; 799 800 switch (style) { 801 case ui_box_single: 802 hbc = &single_hbrace_chars; 803 break; 804 case ui_box_double: 805 hbc = &double_hbrace_chars; 806 break; 807 } 808 809 if (hbc == NULL) 810 return EINVAL; 811 812 gfx_text_fmt_init(&fmt); 813 fmt.font = resource->font; 814 fmt.color = color; 815 816 bufsz = str_size(hbc->start) + 817 str_size(hbc->middle) * (dim.x - 2) + 818 str_size(hbc->end) + 1; 819 820 str = malloc(bufsz); 821 if (str == NULL) 822 return ENOMEM; 823 824 str_cpy(str, bufsz, hbc->start); 825 off = str_size(hbc->start); 826 827 for (i = 1; i < dim.x - 1; i++) { 828 str_cpy(str + off, bufsz - off, hbc->middle); 829 off += str_size(hbc->middle); 830 } 831 832 str_cpy(str + off, bufsz - off, hbc->end); 833 off += str_size(hbc->end); 834 str[off] = '\0'; 835 836 pos = rect->p0; 837 rc = gfx_puttext(&pos, &fmt, str); 838 if (rc != EOK) 839 goto error; 840 841 free(str); 842 return EOK; 843 error: 844 if (str != NULL) 845 free(str); 846 return rc; 847 } 848 849 /** Fill rectangle with text character. 850 * 851 * @param resource UI resource 852 * @param rect Rectangle 853 * @param color Color 854 * @param gchar Character to fill with 855 * @return EOK on success or an error code 856 */ 857 errno_t ui_paint_text_rect(ui_resource_t *resource, gfx_rect_t *rect, 858 gfx_color_t *color, const char *gchar) 859 { 860 gfx_coord2_t pos; 861 gfx_text_fmt_t fmt; 862 gfx_rect_t srect; 863 gfx_coord_t w, i; 864 char *buf; 865 size_t gcharsz; 866 errno_t rc; 867 868 gfx_rect_points_sort(rect, &srect); 869 870 gfx_text_fmt_init(&fmt); 871 fmt.font = resource->font; 872 fmt.color = color; 873 fmt.halign = gfx_halign_left; 874 fmt.valign = gfx_valign_top; 875 876 w = srect.p1.x - srect.p0.x; 877 if (w == 0) 878 return EOK; 879 880 gcharsz = str_size(gchar); 881 882 buf = malloc(w * gcharsz + 1); 883 if (buf == NULL) 884 return ENOMEM; 885 886 for (i = 0; i < w; i++) 887 str_cpy(buf + i * gcharsz, (w - i) * gcharsz + 1, gchar); 888 buf[w * gcharsz] = '\0'; 889 890 pos.x = srect.p0.x; 891 for (pos.y = srect.p0.y; pos.y < srect.p1.y; pos.y++) { 892 rc = gfx_puttext(&pos, &fmt, buf); 893 if (rc != EOK) 894 goto error; 895 } 896 897 free(buf); 898 return EOK; 899 error: 900 free(buf); 901 return rc; 902 } 903 904 /** Initialize UI text formatting structure. 905 * 906 * UI text formatting structure must always be initialized using this function 907 * first. 908 * 909 * @param fmt UI text formatting structure 910 */ 911 void ui_text_fmt_init(ui_text_fmt_t *fmt) 912 { 913 memset(fmt, 0, sizeof(ui_text_fmt_t)); 914 } 915 916 /** Compute UI text width. 917 * 918 * @param font Font 919 * @param str String 920 * @return Text width 921 */ 922 gfx_coord_t ui_text_width(gfx_font_t *font, const char *str) 923 { 924 gfx_coord_t w; 925 gfx_coord_t tw; 926 const char *sp; 927 928 /* Text including tildes */ 929 w = gfx_text_width(font, str); 930 tw = gfx_text_width(font, "~"); 931 932 /* Subtract width of singular tildes */ 933 sp = str; 934 while (*sp != '\0') { 935 if (*sp == '~' && sp[1] != '~') 936 w -= tw; 937 ++sp; 938 } 939 940 return w; 941 } 942 943 /** Paint text (with highlighting markup). 944 * 945 * Paint some text with highlighted sections enclosed with tilde characters 946 * ('~'). A literal tilde can be printed with "~~". Text can be highlighted 947 * with an underline or different color, based on display capabilities. 948 * 949 * @param pos Anchor position 950 * @param fmt Text formatting 951 * @param str String containing '~' markup 952 * 953 * @return EOK on success or an error code 954 */ 955 errno_t ui_paint_text(gfx_coord2_t *pos, ui_text_fmt_t *fmt, const char *str) 956 { 957 gfx_coord2_t tpos; 958 gfx_text_fmt_t tfmt; 959 char *buf; 960 char *endptr; 961 const char *sp; 962 errno_t rc; 963 964 /* Break down string into list of (non)highlighted parts */ 965 rc = ui_accel_process(str, &buf, &endptr); 966 if (rc != EOK) 967 return rc; 968 969 gfx_text_fmt_init(&tfmt); 970 tfmt.font = fmt->font; 971 tfmt.color = fmt->color; 972 tfmt.halign = fmt->halign; 973 tfmt.width = fmt->width; 974 tfmt.valign = fmt->valign; 975 tfmt.underline = false; 976 977 tpos = *pos; 978 sp = buf; 979 while (sp != endptr) { 980 /* Print the current string */ 981 rc = gfx_puttext(&tpos, &tfmt, sp); 982 if (rc != EOK) 983 goto error; 984 985 gfx_text_cont(&tpos, &tfmt, sp, &tpos, &tfmt); 986 tfmt.underline = !tfmt.underline; 987 tfmt.color = tfmt.underline ? fmt->hgl_color : fmt->color; 988 989 /* Skip to the next string */ 990 while (*sp != '\0') 991 ++sp; 992 ++sp; 993 } 994 995 free(buf); 996 return EOK; 997 error: 998 free(buf); 999 return rc; 1000 } 1001 326 1002 /** @} 327 1003 */
Note:
See TracChangeset
for help on using the changeset viewer.