1 /* $NetBSD: slk.c,v 1.16 2021/09/06 07:45:48 rin Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Roy Marples. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: slk.c,v 1.16 2021/09/06 07:45:48 rin Exp $"); 35 #endif /* not lint */ 36 37 #include <ctype.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #ifdef HAVE_WCHAR 41 #include <wctype.h> 42 #endif 43 44 #include "curses.h" 45 #include "curses_private.h" 46 47 /* Terminals with real soft labels have NOT been tested. 48 * If you have such a device, please let us know so this comment 49 * can be adjusted. */ 50 51 /* POSIX says that each label can be up to 8 columns. 52 * However, our implementation can allow labels to expand beyond that. */ 53 //#define SLK_SIZE_DYNAMIC 54 #ifdef SLK_SIZE_DYNAMIC 55 #define SLK_SIZE MAX_SLK_LABEL 56 #else 57 #define SLK_SIZE MAX_SLK_COLS 58 #endif 59 60 static int slk_fmt = SLK_FMT_INVAL; /* fmt of slk_init */ 61 62 /* Safe variants of public functions. */ 63 static int __slk_attroff(SCREEN *, const chtype); 64 static int __slk_attron(SCREEN *, const chtype); 65 static int __slk_attrset(SCREEN *, const chtype); 66 #ifdef HAVE_WCHAR 67 static int __slk_attr_off(SCREEN *, const attr_t, void *); 68 static int __slk_attr_on(SCREEN *, const attr_t, void *); 69 static int __slk_attr_set(SCREEN *, const attr_t, short, void *opt); 70 static int __slk_color(SCREEN *, short); 71 #endif 72 73 static int __slk_clear(SCREEN *); 74 static char *__slk_label(SCREEN *, int); 75 static int __slk_restore(SCREEN *); 76 static int __slk_set(SCREEN *, int, const char *, int); 77 static int __slk_touch(SCREEN *); 78 #ifdef HAVE_WCHAR 79 static int __slk_wset(SCREEN *, int, const wchar_t *, int); 80 #endif 81 82 /* Internal engine parts. */ 83 static int __slk_ripoffline(WINDOW *, int); 84 static int __slk_set_finalise(SCREEN *, int); 85 static int __slk_draw(SCREEN *, int); 86 static int __slk_redraw(SCREEN *); 87 88 /* 89 * slk_init -- 90 * Init Soft Label Keys. 91 */ 92 int 93 slk_init(int fmt) 94 { 95 96 switch(fmt) { 97 case SLK_FMT_3_2_3: 98 case SLK_FMT_4_4: 99 break; 100 default: 101 return ERR; 102 } 103 104 slk_fmt = fmt; 105 /* Even if the terminal supports soft label keys directly, 106 * we need to reserve a line. */ 107 return ripoffline(-1, __slk_ripoffline); 108 } 109 110 /* 111 * slk_attron -- 112 * Test and set attributes on ripped off slk window. 113 */ 114 int 115 slk_attron(const chtype attr) 116 { 117 118 return __slk_attron(_cursesi_screen, attr); 119 } 120 121 #ifdef HAVE_WCHAR 122 /* 123 * slk_attr_on -- 124 * Test and set wide attributes on ripped off slk window. 125 */ 126 int 127 slk_attr_on(const attr_t attr, void *opt) 128 { 129 130 return __slk_attr_on(_cursesi_screen, attr, opt); 131 } 132 #endif /* HAVE_WCHAR */ 133 134 /* 135 * slk_attroff -- 136 * Test and unset attributes on ripped off slk window. 137 */ 138 int 139 slk_attroff(const chtype attr) 140 { 141 142 return __slk_attroff(_cursesi_screen, attr); 143 } 144 145 #ifdef HAVE_WCHAR 146 /* 147 * slk_attr_off -- 148 * Test and unset wide attributes on ripped off slk window. 149 */ 150 int 151 slk_attr_off(const attr_t attr, void *opt) 152 { 153 154 return __slk_attr_off(_cursesi_screen, attr, opt); 155 } 156 #endif /* HAVE_WCHAR */ 157 158 /* 159 * slk_attrset -- 160 * Set attributes and color pair on ripped off slk window. 161 */ 162 int 163 slk_attrset(const chtype attr) 164 { 165 166 return __slk_attrset(_cursesi_screen, attr); 167 } 168 169 #ifdef HAVE_WCHAR 170 /* 171 * slk_attr_set -- 172 * Set wide attributes and color pair on ripped off slk window. 173 */ 174 int 175 slk_attr_set(const attr_t attr, short pair, void *opt) 176 { 177 178 return __slk_attr_set(_cursesi_screen, attr, pair, opt); 179 } 180 #endif /* HAVE_WCHAR */ 181 182 /* 183 * slk_clear -- 184 * Clear slk from the current screen. 185 */ 186 int 187 slk_clear(void) 188 { 189 190 return __slk_clear(_cursesi_screen); 191 } 192 193 #ifdef HAVE_WCHAR 194 /* 195 * slk_color -- 196 * Set color pair on ripped off slk window. 197 */ 198 int 199 slk_color(short pair) 200 { 201 202 return __slk_color(_cursesi_screen, pair); 203 } 204 #endif /* HAVE_WCHAR */ 205 206 /* 207 * slk_label -- 208 * Return a pointer to the saved label for key labnum. 209 */ 210 char * 211 slk_label(int labnum) 212 { 213 214 return __slk_label(_cursesi_screen, labnum); 215 } 216 217 /* 218 * slk_wnoutrefresh -- 219 * Add the contents of the ripped off slk window to the virtual window. 220 */ 221 int 222 slk_noutrefresh(void) 223 { 224 225 return __slk_noutrefresh(_cursesi_screen); 226 } 227 228 /* 229 * slk_refresh -- 230 * Force a refresh for the ripped off slk window. 231 */ 232 int 233 slk_refresh(void) 234 { 235 236 if (slk_noutrefresh() == ERR) 237 return ERR; 238 return doupdate(); 239 } 240 241 /* 242 * slk_restore -- 243 * Retore slk to the screen after a slk_clear. 244 */ 245 int 246 slk_restore(void) 247 { 248 249 return __slk_restore(_cursesi_screen); 250 } 251 252 /* 253 * slk_set -- 254 * Sets the text of the label specified by labnum 255 * and how it is displayed. 256 */ 257 int 258 slk_set(int labnum, const char *label, int justify) 259 { 260 261 return __slk_set(_cursesi_screen, labnum, label, justify); 262 } 263 264 /* 265 * slk_touch -- 266 * Sets the ripped off slk window as modified. 267 */ 268 int 269 slk_touch(void) 270 { 271 272 return __slk_touch(_cursesi_screen); 273 } 274 275 #ifdef HAVE_WCHAR 276 /* 277 * slk_wset -- 278 * Sets the wide text of the label specified by labnum 279 * and how it is displayed. 280 */ 281 int 282 slk_wset(int labnum, const wchar_t *label, int justify) 283 { 284 285 return __slk_wset(_cursesi_screen, labnum, label, justify); 286 } 287 #endif /* HAVE_WCHAR */ 288 289 /* 290 * __slk_attron -- 291 * Test and set attributes on ripped off slk window. 292 */ 293 static int 294 __slk_attron(SCREEN *screen, const chtype attr) 295 { 296 297 if (screen == NULL || screen->slk_window == NULL) 298 return ERR; 299 return wattron(screen->slk_window, attr); 300 } 301 302 #ifdef HAVE_WCHAR 303 /* 304 * __slk_attr_on -- 305 * Test and set wide attributes on ripped off slk window. 306 */ 307 static int 308 __slk_attr_on(SCREEN *screen, const attr_t attr, void *opt) 309 { 310 311 if (screen == NULL || screen->slk_window == NULL) 312 return ERR; 313 return wattr_on(screen->slk_window, attr, opt); 314 } 315 #endif /* HAVE_WCHAR */ 316 317 /* 318 * __slk_attroff -- 319 * Test and unset attributes on ripped off slk window. 320 */ 321 static int 322 __slk_attroff(SCREEN *screen, const chtype attr) 323 { 324 325 if (screen == NULL || screen->slk_window == NULL) 326 return ERR; 327 return wattroff(screen->slk_window, attr); 328 } 329 330 #ifdef HAVE_WCHAR 331 /* 332 * __slk_attr_off -- 333 * Test and unset wide attributes on ripped off slk window. 334 */ 335 static int 336 __slk_attr_off(SCREEN *screen, const attr_t attr, void *opt) 337 { 338 339 if (screen == NULL || screen->slk_window == NULL) 340 return ERR; 341 return wattr_off(screen->slk_window, attr, opt); 342 } 343 #endif /* HAVE_WCHAR */ 344 345 /* 346 * __slk_attrset -- 347 * Set attributes and color pair on ripped off slk window. 348 */ 349 static int 350 __slk_attrset(SCREEN *screen, const chtype attr) 351 { 352 353 if (screen == NULL || screen->slk_window == NULL) 354 return ERR; 355 return wattrset(screen->slk_window, attr); 356 } 357 358 #ifdef HAVE_WCHAR 359 /* 360 * __slk_attr_set -- 361 * Set wide attributes and color pair on ripped off slk window. 362 */ 363 static int 364 __slk_attr_set(SCREEN *screen, const attr_t attr, short pair, void *opt) 365 { 366 367 if (screen == NULL || screen->slk_window == NULL) 368 return ERR; 369 return wattr_set(screen->slk_window, attr, pair, opt); 370 } 371 #endif /* HAVE_WCHAR */ 372 373 /* 374 * __slk_clear -- 375 * Clear slk from the current screen. 376 */ 377 static int 378 __slk_clear(SCREEN *screen) 379 { 380 381 if (screen == NULL) 382 return ERR; 383 screen->slk_hidden = true; 384 if (screen->is_term_slk) { 385 if (t_label_off(screen->term) == NULL) 386 return ERR; 387 return ti_putp(screen->term, 388 ti_tiparm(screen->term, t_label_off(screen->term))); 389 } 390 if (screen->slk_window == NULL) 391 return ERR; 392 werase(screen->slk_window); 393 return wrefresh(screen->slk_window); 394 } 395 396 #ifdef HAVE_WCHAR 397 /* 398 * __slk_color -- 399 * Set color pair on ripped off slk window. 400 */ 401 static int 402 __slk_color(SCREEN *screen, short pair) 403 { 404 405 if (screen == NULL || screen->slk_window == NULL) 406 return ERR; 407 return wcolor_set(screen->slk_window, pair, NULL); 408 } 409 #endif /* HAVE_WCHAR */ 410 411 /* 412 * __slk_label -- 413 * Return a pointer to the saved label for key labnum. 414 */ 415 static char * 416 __slk_label(SCREEN *screen, int labnum) 417 { 418 419 if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels) 420 return NULL; 421 return screen->slk_labels[--labnum].text; 422 } 423 424 /* 425 * __slk_wnoutrefresh -- 426 * Add the contents of the ripped off slk window to the virtual window. 427 */ 428 int 429 __slk_noutrefresh(SCREEN *screen) 430 { 431 432 if (screen == NULL || screen->slk_window == NULL) 433 return ERR; 434 return wnoutrefresh(screen->slk_window); 435 } 436 437 /* 438 * __slk_restore -- 439 * Retore slk to the screen after a slk_clear. 440 */ 441 static int 442 __slk_restore(SCREEN *screen) 443 { 444 445 if (screen == NULL) 446 return ERR; 447 screen->slk_hidden = false; 448 if (screen->is_term_slk) { 449 if (t_label_on(screen->term) == NULL) 450 return ERR; 451 return ti_putp(screen->term, 452 ti_tiparm(screen->term, t_label_on(screen->term))); 453 } 454 if (screen->slk_window == NULL) 455 return ERR; 456 if (__slk_redraw(screen) == ERR) 457 return ERR; 458 return wrefresh(screen->slk_window); 459 } 460 461 /* 462 * __slk_set -- 463 * Sets the text of the label specified by labnum 464 * and how it is displayed. 465 */ 466 static int 467 __slk_set(SCREEN *screen, int labnum, const char *label, int justify) 468 { 469 struct __slk_label *l; 470 const char *end; 471 size_t len; 472 char *text; 473 #ifdef HAVE_WCHAR 474 wchar_t wc; 475 size_t wc_len; 476 #endif 477 478 /* Check args. */ 479 if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels) 480 return ERR; 481 switch(justify) { 482 case SLK_JUSTIFY_LEFT: 483 case SLK_JUSTIFY_CENTER: 484 case SLK_JUSTIFY_RIGHT: 485 break; 486 default: 487 return ERR; 488 } 489 if (label == NULL) 490 label = ""; 491 492 /* Skip leading whitespace. */ 493 while(isspace((unsigned char)*label)) 494 label++; 495 /* Grab end. */ 496 end = label; 497 498 #ifdef HAVE_WCHAR 499 size_t endlen = strlen(end); 500 while (*end != '\0') { 501 wc_len = mbrtowc(&wc, end, endlen, &screen->sp); 502 if ((ssize_t)wc_len < 0) 503 return ERR; 504 if (!iswprint((wint_t)wc)) 505 break; 506 end += wc_len; 507 endlen -= wc_len; 508 } 509 #else 510 while(isprint((unsigned char)*end)) 511 end++; 512 #endif 513 len = end - label; 514 515 /* Take a backup, in-case we can grow the label. */ 516 if ((text = strndup(label, len)) == NULL) 517 return ERR; 518 519 /* All checks out, assign. */ 520 l = &screen->slk_labels[--labnum]; /* internal zero based index */ 521 l->text = text; 522 l->justify = justify; 523 524 __slk_set_finalise(screen, labnum); 525 return OK; 526 } 527 528 /* 529 * __slk_touch -- 530 * Sets the ripped off slk window as modified. 531 */ 532 static int 533 __slk_touch(SCREEN *screen) 534 { 535 536 if (screen == NULL || screen->slk_window == NULL) 537 return ERR; 538 return touchwin(screen->slk_window); 539 } 540 541 542 #ifdef HAVE_WCHAR 543 /* 544 * __slk_wset -- 545 * Sets the wide text of the label specified by labnum 546 * and how it is displayed. 547 */ 548 static int 549 __slk_wset(SCREEN *screen, int labnum, const wchar_t *label, int justify) 550 { 551 const wchar_t *olabel; 552 size_t len; 553 char *str; 554 int result = ERR; 555 556 if (screen == NULL) 557 return ERR; 558 __CTRACE(__CTRACE_INPUT, "__slk_wset: entry\n"); 559 olabel = label; 560 if ((len = wcsrtombs(NULL, &olabel, 0, &screen->sp)) == -1) { 561 __CTRACE(__CTRACE_INPUT, 562 "__slk_wset: conversion failed on char 0x%hx\n", 563 (uint16_t)*olabel); 564 return ERR; 565 } 566 567 __CTRACE(__CTRACE_INPUT, "__slk_wset: wcsrtombs %zu\n", len); 568 len++; /* We need to store the NULL character. */ 569 if ((str = malloc(len)) == NULL) 570 return ERR; 571 olabel = label; 572 if (wcsrtombs(str, &olabel, len, &screen->sp) == -1) 573 goto out; 574 result = __slk_set(screen, labnum, str, justify); 575 out: 576 free(str); 577 __CTRACE(__CTRACE_INPUT, "__slk_wset: return %s\n", 578 result == OK ? "OK" : "ERR"); 579 return result; 580 } 581 #endif /* HAVE_WCHAR */ 582 583 584 /* 585 * __slk_init -- 586 * Allocate structures. 587 */ 588 int 589 __slk_init(SCREEN *screen) 590 { 591 592 __slk_free(screen); /* safety */ 593 594 screen->slk_format = slk_fmt; 595 if (slk_fmt == SLK_FMT_INVAL) 596 return OK; 597 slk_fmt = SLK_FMT_INVAL; 598 599 switch(screen->slk_format) { 600 case SLK_FMT_3_2_3: 601 case SLK_FMT_4_4: 602 screen->slk_nlabels = 8; 603 break; 604 default: /* impossible */ 605 return ERR; 606 } 607 608 screen->slk_labels = calloc(screen->slk_nlabels, 609 sizeof(*screen->slk_labels)); 610 if (screen->slk_labels == NULL) 611 return ERR; 612 613 screen->is_term_slk = 614 t_plab_norm(screen->term) != NULL && 615 t_num_labels(screen->term) > 0; 616 if (screen->is_term_slk) { 617 __unripoffline(__slk_ripoffline); 618 screen->slk_nlabels = t_num_labels(screen->term); 619 screen->slk_label_len = t_label_width(screen->term); 620 /* XXX label_height, label_format? */ 621 } 622 623 return OK; 624 } 625 626 /* 627 * __slk_free -- 628 * Free allocates resources. 629 */ 630 void 631 __slk_free(SCREEN *screen) 632 { 633 int i; 634 635 if (screen->slk_window != NULL) 636 delwin(screen->slk_window); 637 for (i = 0; i < screen->slk_nlabels; i++) 638 free(screen->slk_labels[i].text); 639 free(screen->slk_labels); 640 } 641 642 /* 643 * __slk_ripoffline -- 644 * ripoffline callback to accept a WINDOW to create our keys. 645 */ 646 static int 647 __slk_ripoffline(WINDOW *window, int cols) 648 { 649 650 if (window == NULL) 651 return ERR; 652 window->screen->slk_window = window; 653 wattron(window, 654 (t_no_color_video(window->screen->term) & 1) == 0 655 ? A_STANDOUT : A_REVERSE); 656 __slk_resize(window->screen, cols); 657 return OK; 658 } 659 660 /* 661 * __slk_resize -- 662 * Size and position the labels in the ripped off slk window. 663 */ 664 int 665 __slk_resize(SCREEN *screen, int cols) 666 { 667 int x = 0; 668 struct __slk_label *l; 669 670 if (screen == NULL) 671 return ERR; 672 if (screen->is_term_slk || screen->slk_nlabels == 0) 673 return OK; 674 675 screen->slk_label_len = (cols / screen->slk_nlabels) - 1; 676 if (screen->slk_label_len > SLK_SIZE) 677 screen->slk_label_len = SLK_SIZE; 678 679 l = screen->slk_labels; 680 681 switch(screen->slk_format) { 682 case SLK_FMT_3_2_3: 683 /* Left 3 */ 684 (l++)->x = x; 685 (l++)->x = (x += screen->slk_label_len + 1); 686 (l++)->x = (x += screen->slk_label_len + 1); 687 688 /* Middle 2 */ 689 x = cols / 2; 690 (l++)->x = x -(screen->slk_label_len + 1); 691 (l++)->x = x + 1; 692 693 /* Right 3 */ 694 x = (cols - ((screen->slk_label_len + 1) * 3)) + 1; 695 (l++)->x = x; 696 (l++)->x = (x += screen->slk_label_len + 1); 697 (l++)->x = (x += screen->slk_label_len + 1); 698 break; 699 700 case SLK_FMT_4_4: 701 { 702 int i, half; 703 704 half = screen->slk_nlabels / 2; 705 for (i = 0; i < screen->slk_nlabels; i++) { 706 (l++)->x = x; 707 x += screen->slk_label_len; 708 /* Split labels in half */ 709 if (i == half - 1) 710 x = cols - (screen->slk_label_len * half) + 1; 711 } 712 break; 713 } 714 } 715 716 /* Write text to the labels. */ 717 for (x = 0; x < screen->slk_nlabels; x++) 718 __slk_set_finalise(screen, x); 719 720 return __slk_redraw(screen); 721 } 722 723 /* 724 * __slk_set_finalise -- 725 * Does the grunt work of positioning and sizing the text in the label. 726 */ 727 static int 728 __slk_set_finalise(SCREEN *screen, int labnum) 729 { 730 struct __slk_label *l; 731 size_t spc, len, width, x; 732 char *p; 733 734 l = &screen->slk_labels[labnum]; 735 spc = screen->slk_label_len; 736 737 #ifdef HAVE_WCHAR 738 len = 0; 739 width = 0; 740 if (l->text != NULL) { 741 size_t plen; 742 743 p = l->text; 744 plen = strlen(l->text); 745 while (*p != '\0') { 746 size_t mblen; 747 wchar_t wc; 748 int w; 749 750 mblen = mbrtowc(&wc, p, plen, &screen->sp); 751 if ((ssize_t)mblen < 0) 752 return ERR; 753 w = wcwidth(wc); 754 if (width + w > spc) 755 break; 756 width += w; 757 len += mblen; 758 p += mblen; 759 plen -= mblen; 760 } 761 } 762 #else 763 len = l->text == NULL ? 0 : strlen(l->text); 764 if (len > spc) 765 len = spc; 766 width = len; 767 #endif 768 769 switch(l->justify) { 770 case SLK_JUSTIFY_LEFT: 771 x = 0; 772 break; 773 case SLK_JUSTIFY_CENTER: 774 x = (spc - width) / 2; 775 if (x + width > spc) 776 x--; 777 break; 778 case SLK_JUSTIFY_RIGHT: 779 x = spc - width; 780 break; 781 default: 782 return ERR; /* impossible */ 783 } 784 785 p = l->label; 786 if (x != 0) { 787 memset(p, ' ', x); 788 p += x; 789 spc -= x; 790 } 791 if (len != 0) { 792 memcpy(p, l->text, len); 793 p += len; 794 spc -= width; 795 } 796 if (spc != 0) { 797 memset(p, ' ', spc); 798 p += spc; 799 } 800 *p = '\0'; /* Terminate for plab_norm. */ 801 802 return __slk_draw(screen, labnum); 803 } 804 805 /* 806 * __slk_draw -- 807 * Draws the specified key. 808 */ 809 static int 810 __slk_draw(SCREEN *screen, int labnum) 811 { 812 const struct __slk_label *l; 813 int retval, inc, lcnt, tx; 814 char ts[MB_LEN_MAX]; 815 #ifdef HAVE_WCHAR 816 cchar_t cc; 817 wchar_t wc[2]; 818 #endif 819 820 if (screen->slk_hidden) 821 return OK; 822 823 retval = OK; /* quiet gcc... */ 824 825 l = &screen->slk_labels[labnum]; 826 if (screen->is_term_slk) 827 return ti_putp(screen->term, 828 ti_tiparm(screen->term, 829 t_plab_norm(screen->term), labnum + 1, l->label)); 830 else if (screen->slk_window != NULL) { 831 if ((labnum != screen->slk_nlabels - 1) || 832 (screen->slk_window->flags & __SCROLLOK) || 833 ((l->x + screen->slk_label_len) < screen->slk_window->maxx)) { 834 retval = mvwaddnstr(screen->slk_window, 0, l->x, 835 l->label, screen->slk_label_len); 836 } else { 837 lcnt = 0; 838 tx = 0; 839 while (lcnt < screen->slk_label_len) { 840 inc = wctomb(ts, l->label[lcnt]); 841 if (inc < 0) { 842 /* conversion failed, skip? */ 843 lcnt++; 844 continue; 845 } 846 847 __CTRACE(__CTRACE_INPUT, 848 "__slk_draw: last label, (%d,%d) char[%d] 0x%x\n", 849 l->x + tx, 0, lcnt, l->label[lcnt]); 850 __CTRACE(__CTRACE_INPUT, "__slk_draw: label len %d, wcwidth %d\n", 851 screen->slk_label_len, wcwidth(l->label[lcnt])); 852 #ifdef HAVE_WCHAR 853 wc[0] = l->label[lcnt]; 854 wc[1] = L'\0'; 855 if (setcchar(&cc, wc, 856 screen->slk_window->wattr, 0, 857 NULL) == ERR) 858 return ERR; 859 #endif 860 861 if (l->x + wcwidth(l->label[lcnt] + tx) >= 862 screen->slk_label_len) { 863 /* last character that will fit 864 * so insert it to avoid scroll 865 */ 866 #ifdef HAVE_WCHAR 867 retval = mvwins_wch(screen->slk_window, 868 0, l->x + tx, &cc); 869 #else 870 retval = mvwinsch(screen->slk_window, 871 0, l->x + tx, l->label[lcnt]); 872 #endif 873 } else { 874 #ifdef HAVE_WCHAR 875 retval = mvwadd_wch(screen->slk_window, 876 0, l->x + tx, &cc); 877 #else 878 retval = mvwaddch(screen->slk_window, 879 0, l->x + tx, l->label[lcnt]); 880 #endif 881 } 882 tx += wcwidth(l->label[lcnt]); 883 lcnt += inc; 884 } 885 } 886 887 return retval; 888 } else 889 return ERR; 890 } 891 892 /* 893 * __slk_draw -- 894 * Draws all the keys. 895 */ 896 static int 897 __slk_redraw(SCREEN *screen) 898 { 899 int i, result = OK; 900 901 for (i = 0; i < screen->slk_nlabels; i++) { 902 if (__slk_draw(screen, i) == ERR) 903 result = ERR; 904 } 905 return result; 906 } 907