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