Changes in uspace/lib/ui/src/paint.c [de9992c:1eaead4] in mainline
- File:
-
- 1 edited
-
uspace/lib/ui/src/paint.c (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/paint.c
rde9992c r1eaead4 1 1 /* 2 * Copyright (c) 202 0Jiri 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> 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 }; 41 78 42 79 /** Paint bevel. … … 48 85 * @param thickness Bevel thickness in pixels 49 86 * @param inside Place to store rectangle of the interior or @c NULL 50 * @re utrn EOK on success or an error code87 * @return EOK on success or an error code 51 88 */ 52 89 errno_t ui_paint_bevel(gfx_context_t *gc, gfx_rect_t *rect, … … 106 143 } 107 144 108 if (inside != NULL) { 109 inside->p0.x = rect->p0.x + thickness; 110 inside->p0.y = rect->p0.y + thickness; 111 inside->p1.x = rect->p1.x - thickness; 112 inside->p1.y = rect->p1.y - thickness; 113 } 145 if (inside != NULL) 146 ui_paint_get_bevel_inside(gc, rect, thickness, inside); 114 147 115 148 return EOK; … … 118 151 } 119 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; 169 } 170 171 /** Paint inset frame. 172 * 173 * @param resource UI resource 174 * @param rect Rectangle to paint onto 175 * @param inside Place to store inside rectangle or @c NULL 176 * @return EOK on success or an error code 177 */ 178 errno_t ui_paint_inset_frame(ui_resource_t *resource, gfx_rect_t *rect, 179 gfx_rect_t *inside) 180 { 181 gfx_rect_t frame; 182 errno_t rc; 183 184 rc = ui_paint_bevel(resource->gc, rect, 185 resource->wnd_shadow_color, resource->wnd_highlight_color, 186 1, &frame); 187 if (rc != EOK) 188 goto error; 189 190 rc = ui_paint_bevel(resource->gc, &frame, 191 resource->wnd_frame_sh_color, resource->wnd_frame_hi_color, 192 1, inside); 193 if (rc != EOK) 194 goto error; 195 196 return EOK; 197 error: 198 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); 214 } 215 216 /** Paint outset frame. 217 * 218 * @param resource UI resource 219 * @param rect Rectangle to paint onto 220 * @param inside Place to store inside rectangle or @c NULL 221 * @return EOK on success or an error code 222 */ 223 errno_t ui_paint_outset_frame(ui_resource_t *resource, gfx_rect_t *rect, 224 gfx_rect_t *inside) 225 { 226 gfx_rect_t frame; 227 errno_t rc; 228 229 rc = ui_paint_bevel(resource->gc, rect, 230 resource->wnd_frame_hi_color, resource->wnd_frame_sh_color, 231 1, &frame); 232 if (rc != EOK) 233 goto error; 234 235 rc = ui_paint_bevel(resource->gc, &frame, 236 resource->wnd_highlight_color, resource->wnd_shadow_color, 237 1, inside); 238 if (rc != EOK) 239 goto error; 240 241 return EOK; 242 error: 243 return rc; 244 } 245 246 /** Paint filled circle vertical scanline. 247 * 248 * @param gc Graphic context 249 * @param center Coordinates of the center of the circle 250 * @param x X-coordinate of the scanline 251 * @param y0 Lowest Y coordinate of the scanline (inclusive) 252 * @param y1 Highest Y coordinate of the scanline (inclusive) 253 * @param part Which part(s) of cicle to paint 254 * @return EOK on success or an error code 255 */ 256 static errno_t ui_paint_fcircle_line(gfx_context_t *gc, gfx_coord2_t *center, 257 gfx_coord_t x, gfx_coord_t y0, gfx_coord_t y1, ui_fcircle_part_t part) 258 { 259 gfx_rect_t rect; 260 gfx_rect_t trect; 261 262 rect.p0.x = x; 263 rect.p0.y = y0; 264 rect.p1.x = x + 1; 265 rect.p1.y = y1; 266 267 /* Clip to upper-left/lower-right half of circle, if required */ 268 269 if ((part & ui_fcircle_upleft) == 0) { 270 if (rect.p0.y < -rect.p1.x) 271 rect.p0.y = -rect.p1.x; 272 } 273 274 if ((part & ui_fcircle_lowright) == 0) { 275 if (rect.p1.y > -rect.p1.x) 276 rect.p1.y = -rect.p1.x; 277 } 278 279 /* If coordinates are reversed, there is nothing to do */ 280 if (rect.p1.y <= rect.p0.y) 281 return EOK; 282 283 gfx_rect_translate(center, &rect, &trect); 284 285 return gfx_fill_rect(gc, &trect); 286 } 287 288 /** Paint filled circle scanlines corresponding to octant point. 289 * 290 * Fills the four vertical scanlines lying between the eight reflections 291 * of a circle point. 292 * 293 * @param gc Graphic context 294 * @param center Coordinates of the center 295 * @param r Radius in pixels 296 * @param part Which part(s) of cicle to paint 297 * @return EOK on success or an error code 298 */ 299 static int ui_paint_fcircle_point(gfx_context_t *gc, gfx_coord2_t *center, 300 gfx_coord2_t *p, ui_fcircle_part_t part) 301 { 302 errno_t rc; 303 304 rc = ui_paint_fcircle_line(gc, center, +p->x, -p->y, p->y + 1, part); 305 if (rc != EOK) 306 return rc; 307 rc = ui_paint_fcircle_line(gc, center, -p->x, -p->y, p->y + 1, part); 308 if (rc != EOK) 309 return rc; 310 rc = ui_paint_fcircle_line(gc, center, +p->y, -p->x, p->x + 1, part); 311 if (rc != EOK) 312 return rc; 313 rc = ui_paint_fcircle_line(gc, center, -p->y, -p->x, p->x + 1, part); 314 if (rc != EOK) 315 return rc; 316 317 return EOK; 318 } 319 320 /** Paint a filled circle. 321 * 322 * @param gc Graphic context 323 * @param center Coordinates of the center 324 * @param r Radius in pixels 325 * @param part Which part(s) of cicle to paint 326 * @return EOK on success or an error code 327 */ 328 errno_t ui_paint_filled_circle(gfx_context_t *gc, gfx_coord2_t *center, 329 gfx_coord_t r, ui_fcircle_part_t part) 330 { 331 gfx_coord2_t p; 332 gfx_coord_t f; 333 errno_t rc; 334 335 /* Run through one octant using circle midpoint algorithm */ 336 337 p.x = r; 338 p.y = 0; 339 f = 1 - r; 340 341 rc = ui_paint_fcircle_point(gc, center, &p, part); 342 if (rc != EOK) 343 return rc; 344 345 while (p.x > p.y) { 346 if (f < 0) { 347 f = f + 2 * p.y + 3; 348 } else { 349 f = f + 2 * (p.y - p.x) + 5; 350 --p.x; 351 } 352 ++p.y; 353 354 rc = ui_paint_fcircle_point(gc, center, &p, part); 355 if (rc != EOK) 356 return rc; 357 } 358 359 return EOK; 360 } 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 120 1002 /** @} 121 1003 */
Note:
See TracChangeset
for help on using the changeset viewer.
