Changes in uspace/lib/ui/src/paint.c [1eaead4:d63623f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/paint.c
r1eaead4 rd63623f 1 1 /* 2 * Copyright (c) 202 3Jiri Svoboda2 * Copyright (c) 2021 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>42 40 #include <ui/paint.h> 43 #include <stdlib.h>44 #include <str.h>45 41 #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 };78 42 79 43 /** Paint bevel. … … 360 324 } 361 325 362 /** Paint upward pointing triangle.363 *364 * @param gc Graphic context365 * @param pos Center position366 * @param n Length of triangle side367 * @return EOK on success or an error code368 */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 context392 * @param pos Center position393 * @param n Length of triangle side394 * @return EOK on success or an error code395 */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 context419 * @param pos Center position420 * @param n Length of triangle side421 * @return EOK on success or an error code422 */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 context446 * @param pos Center position447 * @param n Length of triangle side448 * @return EOK on success or an error code449 */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 context473 * @param pos Center position474 * @param n Length of each leg475 * @param w Pen width476 * @param h Pen height477 * @return EOK on success or an error code478 */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 resource534 * @param pos Center position535 * @param w Icon width536 * @param h Icon height537 * @return EOK on success or an error code538 */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 resource563 * @param pos Center position564 * @param w Icon width565 * @param h Icon height566 * @return EOK on success or an error code567 */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 resource606 * @param pos Center position607 * @param w Window icon width608 * @param h Window icon height609 * @param dw Horizontal distance between window icon centers610 * @param dh Vertical distance between window icon centers611 * @return EOK on success or an error code612 */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 resource639 * @param rect Rectangle inside which to paint the box640 * @param style Box style641 * @param boxc Box characters642 * @param color Color643 * @return EOK on success or an error code644 */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 resource745 * @param rect Rectangle inside which to paint the box746 * @param style Box style747 * @param color Color748 * @return EOK on success or an error code749 */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 resource773 * @param rect Rectangle inside which to paint the brace (height should774 * be 1).775 * @param style Box style776 * @param color Color777 * @return EOK on success or an error code778 */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 resource852 * @param rect Rectangle853 * @param color Color854 * @param gchar Character to fill with855 * @return EOK on success or an error code856 */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 function907 * first.908 *909 * @param fmt UI text formatting structure910 */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 Font919 * @param str String920 * @return Text width921 */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 characters946 * ('~'). A literal tilde can be printed with "~~". Text can be highlighted947 * with an underline or different color, based on display capabilities.948 *949 * @param pos Anchor position950 * @param fmt Text formatting951 * @param str String containing '~' markup952 *953 * @return EOK on success or an error code954 */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 1002 326 /** @} 1003 327 */
Note:
See TracChangeset
for help on using the changeset viewer.