Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ui/src/paint.c

    r81ec7e1 r1eaead4  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2023 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3939#include <gfx/render.h>
    4040#include <gfx/text.h>
     41#include <ui/accel.h>
    4142#include <ui/paint.h>
    4243#include <stdlib.h>
     
    359360}
    360361
    361 /** Paint a text box.
     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 */
     369errno_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 */
     396errno_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 */
     423errno_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 */
     450errno_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 */
     479errno_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 */
     539errno_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 */
     568errno_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 */
     613errno_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.
    362637 *
    363638 * @param resource UI resource
    364639 * @param rect Rectangle inside which to paint the box
    365640 * @param style Box style
     641 * @param boxc Box characters
    366642 * @param color Color
    367643 * @return EOK on success or an error code
    368644 */
    369 errno_t ui_paint_text_box(ui_resource_t *resource, gfx_rect_t *rect,
    370     ui_box_style_t style, gfx_color_t *color)
     645errno_t ui_paint_text_box_custom(ui_resource_t *resource, gfx_rect_t *rect,
     646    ui_box_chars_t *boxc, gfx_color_t *color)
    371647{
    372648        errno_t rc;
     
    380656        gfx_coord_t y;
    381657        char *str = NULL;
    382         ui_box_chars_t *boxc = NULL;
    383658
    384659        gfx_rect_points_sort(rect, &srect);
     
    388663        if (dim.x < 2 || dim.y < 2)
    389664                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;
     734error:
     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 */
     750errno_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;
    390754
    391755        switch (style) {
     
    401765                return EINVAL;
    402766
    403         gfx_text_fmt_init(&fmt);
    404         fmt.color = color;
    405 
    406         bufsz = str_size(boxc->c[0][0]) +
    407             str_size(boxc->c[0][1]) * (dim.x - 2) +
    408             str_size(boxc->c[0][2]) + 1;
    409 
    410         str = malloc(bufsz);
    411         if (str == NULL)
    412                 return ENOMEM;
    413 
    414         /* Top edge and corners */
    415 
    416         str_cpy(str, bufsz, boxc->c[0][0]);
    417         off = str_size(boxc->c[0][0]);
    418 
    419         for (i = 1; i < dim.x - 1; i++) {
    420                 str_cpy(str + off, bufsz - off, boxc->c[0][1]);
    421                 off += str_size(boxc->c[0][1]);
    422         }
    423 
    424         str_cpy(str + off, bufsz - off, boxc->c[0][2]);
    425         off += str_size(boxc->c[0][2]);
    426         str[off] = '\0';
    427 
    428         pos = rect->p0;
    429         rc = gfx_puttext(resource->font, &pos, &fmt, str);
    430         if (rc != EOK)
    431                 goto error;
    432 
    433         /* Vertical edges */
    434         for (y = rect->p0.y + 1; y < rect->p1.y - 1; y++) {
    435                 pos.y = y;
    436 
    437                 pos.x = rect->p0.x;
    438                 rc = gfx_puttext(resource->font, &pos, &fmt,
    439                     boxc->c[1][0]);
    440                 if (rc != EOK)
    441                         goto error;
    442 
    443                 pos.x = rect->p1.x - 1;
    444                 rc = gfx_puttext(resource->font, &pos, &fmt,
    445                     boxc->c[1][2]);
    446                 if (rc != EOK)
    447                         goto error;
    448         }
    449 
    450         /* Bottom edge and corners */
    451 
    452         str_cpy(str, bufsz, boxc->c[2][0]);
    453         off = str_size(boxc->c[2][0]);
    454 
    455         for (i = 1; i < dim.x - 1; i++) {
    456                 str_cpy(str + off, bufsz - off, boxc->c[2][1]);
    457                 off += str_size(boxc->c[2][1]);
    458         }
    459 
    460         str_cpy(str + off, bufsz - off, boxc->c[2][2]);
    461         off += str_size(boxc->c[2][2]);
    462         str[off] = '\0';
    463 
    464         pos.x = rect->p0.x;
    465         pos.y = rect->p1.y - 1;
    466         rc = gfx_puttext(resource->font, &pos, &fmt, str);
    467         if (rc != EOK)
    468                 goto error;
    469 
    470         free(str);
    471         return EOK;
    472 error:
    473         if (str != NULL)
    474                 free(str);
    475         return rc;
     767        return ui_paint_text_box_custom(resource, rect, boxc, color);
    476768}
    477769
     
    519811
    520812        gfx_text_fmt_init(&fmt);
     813        fmt.font = resource->font;
    521814        fmt.color = color;
    522815
     
    542835
    543836        pos = rect->p0;
    544         rc = gfx_puttext(resource->font, &pos, &fmt, str);
     837        rc = gfx_puttext(&pos, &fmt, str);
    545838        if (rc != EOK)
    546839                goto error;
     
    554847}
    555848
     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 */
     857errno_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;
     899error:
     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 */
     911void 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 */
     922gfx_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 */
     955errno_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;
     997error:
     998        free(buf);
     999        return rc;
     1000}
     1001
    5561002/** @}
    5571003 */
Note: See TracChangeset for help on using the changeset viewer.