Ignore:
File:
1 edited

Legend:

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

    r1eaead4 r214aefb  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838#include <gfx/context.h>
    3939#include <gfx/render.h>
    40 #include <gfx/text.h>
    41 #include <ui/accel.h>
    4240#include <ui/paint.h>
    43 #include <stdlib.h>
    44 #include <str.h>
    4541#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 };
    7842
    7943/** Paint bevel.
     
    8549 * @param thickness Bevel thickness in pixels
    8650 * @param inside Place to store rectangle of the interior or @c NULL
    87  * @return EOK on success or an error code
     51 * @reutrn EOK on success or an error code
    8852 */
    8953errno_t ui_paint_bevel(gfx_context_t *gc, gfx_rect_t *rect,
     
    143107        }
    144108
    145         if (inside != NULL)
    146                 ui_paint_get_bevel_inside(gc, rect, thickness, inside);
     109        if (inside != NULL) {
     110                inside->p0.x = rect->p0.x + thickness;
     111                inside->p0.y = rect->p0.y + thickness;
     112                inside->p1.x = rect->p1.x - thickness;
     113                inside->p1.y = rect->p1.y - thickness;
     114        }
    147115
    148116        return EOK;
    149117error:
    150118        return rc;
    151 }
    152 
    153 /** Get bevel interior rectangle.
    154  *
    155  * Get the bevel interior rectangle without painting it.
    156  *
    157  * @param gc Graphic context
    158  * @param rect Rectangle to paint into
    159  * @param thickness Bevel thickness in pixels
    160  * @param inside Place to store rectangle of the interior
    161  */
    162 void ui_paint_get_bevel_inside(gfx_context_t *gc, gfx_rect_t *rect,
    163     gfx_coord_t thickness, gfx_rect_t *inside)
    164 {
    165         inside->p0.x = rect->p0.x + thickness;
    166         inside->p0.y = rect->p0.y + thickness;
    167         inside->p1.x = rect->p1.x - thickness;
    168         inside->p1.y = rect->p1.y - thickness;
    169119}
    170120
     
    197147error:
    198148        return rc;
    199 }
    200 
    201 /** Get inset frame interior rectangle.
    202  *
    203  * This allows one to get the interior rectangle without actually painting
    204  * the inset frame.
    205  *
    206  * @param resource UI resource
    207  * @param rect Rectangle to paint onto
    208  * @param inside Place to store inside rectangle or @c NULL
    209  */
    210 void ui_paint_get_inset_frame_inside(ui_resource_t *resource, gfx_rect_t *rect,
    211     gfx_rect_t *inside)
    212 {
    213         ui_paint_get_bevel_inside(resource->gc, rect, 2, inside);
    214149}
    215150
     
    360295}
    361296
    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 
    1002297/** @}
    1003298 */
Note: See TracChangeset for help on using the changeset viewer.