slk.c revision 1.12 1 /* $NetBSD: slk.c,v 1.12 2021/08/15 11:44:39 christos 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.12 2021/08/15 11:44:39 christos 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 #ifdef DEBUG
559 __CTRACE(__CTRACE_INPUT, "__slk_wset: entry\n");
560 #endif
561 olabel = label;
562 if ((len = wcsrtombs(NULL, &olabel, 0, &screen->sp)) == -1) {
563 #ifdef DEBUG
564 __CTRACE(__CTRACE_INPUT, "__slk_wset: conversion failed on char 0x%x\n",
565 (uint16_t) *olabel);
566 #endif
567 return ERR;
568 }
569
570 #ifdef DEBUG
571 __CTRACE(__CTRACE_INPUT, "__slk_wset: wcsrtombs %zu\n", len);
572 #endif
573 len++; /* We need to store the NULL character. */
574 if ((str = malloc(len)) == NULL)
575 return ERR;
576 olabel = label;
577 if (wcsrtombs(str, &olabel, len, &screen->sp) == -1)
578 goto out;
579 result = __slk_set(screen, labnum, str, justify);
580 out:
581 free(str);
582 #ifdef DEBUG
583 __CTRACE(__CTRACE_INPUT, "__slk_wset: return %s\n",
584 (result == OK)?"OK":"ERR");
585 #endif
586 return result;
587 }
588 #endif /* HAVE_WCHAR */
589
590
591 /*
592 * __slk_init --
593 * Allocate structures.
594 */
595 int
596 __slk_init(SCREEN *screen)
597 {
598
599 __slk_free(screen); /* safety */
600
601 screen->slk_format = slk_fmt;
602 if (slk_fmt == SLK_FMT_INVAL)
603 return OK;
604 slk_fmt = SLK_FMT_INVAL;
605
606 switch(screen->slk_format) {
607 case SLK_FMT_3_2_3:
608 case SLK_FMT_4_4:
609 screen->slk_nlabels = 8;
610 break;
611 default: /* impossible */
612 return ERR;
613 }
614
615 screen->slk_labels = calloc(screen->slk_nlabels,
616 sizeof(*screen->slk_labels));
617 if (screen->slk_labels == NULL)
618 return ERR;
619
620 screen->is_term_slk =
621 t_plab_norm(screen->term) != NULL &&
622 t_num_labels(screen->term) > 0;
623 if (screen->is_term_slk) {
624 __unripoffline(__slk_ripoffline);
625 screen->slk_nlabels = t_num_labels(screen->term);
626 screen->slk_label_len = t_label_width(screen->term);
627 /* XXX label_height, label_format? */
628 }
629
630 return OK;
631 }
632
633 /*
634 * __slk_free --
635 * Free allocates resources.
636 */
637 void
638 __slk_free(SCREEN *screen)
639 {
640 int i;
641
642 if (screen->slk_window != NULL)
643 delwin(screen->slk_window);
644 for (i = 0; i < screen->slk_nlabels; i++)
645 free(screen->slk_labels[i].text);
646 free(screen->slk_labels);
647 }
648
649 /*
650 * __slk_ripoffline --
651 * ripoffline callback to accept a WINDOW to create our keys.
652 */
653 static int
654 __slk_ripoffline(WINDOW *window, int cols)
655 {
656
657 if (window == NULL)
658 return ERR;
659 window->screen->slk_window = window;
660 wattron(window,
661 (t_no_color_video(window->screen->term) & 1) == 0
662 ? A_STANDOUT : A_REVERSE);
663 __slk_resize(window->screen, cols);
664 return OK;
665 }
666
667 /*
668 * __slk_resize --
669 * Size and position the labels in the ripped off slk window.
670 */
671 int
672 __slk_resize(SCREEN *screen, int cols)
673 {
674 int x = 0;
675 struct __slk_label *l;
676
677 if (screen == NULL)
678 return ERR;
679 if (screen->is_term_slk || screen->slk_nlabels == 0)
680 return OK;
681
682 screen->slk_label_len = (cols / screen->slk_nlabels) - 1;
683 if (screen->slk_label_len > SLK_SIZE)
684 screen->slk_label_len = SLK_SIZE;
685
686 l = screen->slk_labels;
687
688 switch(screen->slk_format) {
689 case SLK_FMT_3_2_3:
690 /* Left 3 */
691 (l++)->x = x;
692 (l++)->x = (x += screen->slk_label_len + 1);
693 (l++)->x = (x += screen->slk_label_len + 1);
694
695 /* Middle 2 */
696 x = cols / 2;
697 (l++)->x = x -(screen->slk_label_len + 1);
698 (l++)->x = x + 1;
699
700 /* Right 3 */
701 x = (cols - ((screen->slk_label_len + 1) * 3)) + 1;
702 (l++)->x = x;
703 (l++)->x = (x += screen->slk_label_len + 1);
704 (l++)->x = (x += screen->slk_label_len + 1);
705 break;
706
707 case SLK_FMT_4_4:
708 {
709 int i, half;
710
711 half = screen->slk_nlabels / 2;
712 for (i = 0; i < screen->slk_nlabels; i++) {
713 (l++)->x = x;
714 x += screen->slk_label_len;
715 /* Split labels in half */
716 if (i == half - 1)
717 x = cols - (screen->slk_label_len * half) + 1;
718 }
719 break;
720 }
721 }
722
723 /* Write text to the labels. */
724 for (x = 0; x < screen->slk_nlabels; x++)
725 __slk_set_finalise(screen, x);
726
727 return __slk_redraw(screen);
728 }
729
730 /*
731 * __slk_set_finalise --
732 * Does the grunt work of positioning and sizing the text in the label.
733 */
734 static int
735 __slk_set_finalise(SCREEN *screen, int labnum)
736 {
737 struct __slk_label *l;
738 size_t spc, len, width, x;
739 char *p;
740
741 l = &screen->slk_labels[labnum];
742 spc = screen->slk_label_len;
743
744 #ifdef HAVE_WCHAR
745 len = 0;
746 width = 0;
747 if (l->text != NULL) {
748 size_t plen;
749
750 p = l->text;
751 plen = strlen(l->text);
752 while (*p != '\0') {
753 size_t mblen;
754 wchar_t wc;
755 int w;
756
757 mblen = mbrtowc(&wc, p, plen, &screen->sp);
758 if ((ssize_t)mblen < 0)
759 return ERR;
760 w = wcwidth(wc);
761 if (width + w > spc)
762 break;
763 width += w;
764 len += mblen;
765 p += mblen;
766 plen -= mblen;
767 }
768 }
769 #else
770 len = l->text == NULL ? 0 : strlen(l->text);
771 if (len > spc)
772 len = spc;
773 width = len;
774 #endif
775
776 switch(l->justify) {
777 case SLK_JUSTIFY_LEFT:
778 x = 0;
779 break;
780 case SLK_JUSTIFY_CENTER:
781 x = (spc - width) / 2;
782 if (x + width > spc)
783 x--;
784 break;
785 case SLK_JUSTIFY_RIGHT:
786 x = spc - width;
787 break;
788 default:
789 return ERR; /* impossible */
790 }
791
792 p = l->label;
793 if (x != 0) {
794 memset(p, ' ', x);
795 p += x;
796 spc -= x;
797 }
798 if (len != 0) {
799 memcpy(p, l->text, len);
800 p += len;
801 spc -= width;
802 }
803 if (spc != 0) {
804 memset(p, ' ', spc);
805 p += spc;
806 }
807 *p = '\0'; /* Terminate for plab_norm. */
808
809 return __slk_draw(screen, labnum);
810 }
811
812 /*
813 * __slk_draw --
814 * Draws the specified key.
815 */
816 static int
817 __slk_draw(SCREEN *screen, int labnum)
818 {
819 const struct __slk_label *l;
820 int retval, inc, lcnt, tx;
821 char ts[MB_LEN_MAX];
822 #ifdef HAVE_WCHAR
823 cchar_t cc;
824 wchar_t wc[2];
825 #endif
826
827 if (screen->slk_hidden)
828 return OK;
829
830 retval = OK; /* quiet gcc... */
831
832 l = &screen->slk_labels[labnum];
833 if (screen->is_term_slk)
834 return ti_putp(screen->term,
835 ti_tiparm(screen->term,
836 t_plab_norm(screen->term), labnum + 1, l->label));
837 else if (screen->slk_window != NULL) {
838 if ((labnum != screen->slk_nlabels - 1) ||
839 (screen->slk_window->flags & __SCROLLOK) ||
840 ((l->x + screen->slk_label_len) < screen->slk_window->maxx)) {
841 retval = mvwaddnstr(screen->slk_window, 0, l->x,
842 l->label, screen->slk_label_len);
843 } else {
844 lcnt = 0;
845 tx = 0;
846 while (lcnt < screen->slk_label_len) {
847 inc = wctomb(ts, l->label[lcnt]);
848 if (inc < 0) {
849 /* conversion failed, skip? */
850 lcnt++;
851 continue;
852 }
853
854 #ifdef DEBUG
855 __CTRACE(__CTRACE_INPUT, "__slk_draw: last label, (%d,%d) char[%d] 0x%x\n",
856 l->x + tx, 0, lcnt, l->label[lcnt]);
857 __CTRACE(__CTRACE_INPUT, "__slk_draw: label len %d, wcwidth %d\n",
858 screen->slk_label_len, wcwidth(l->label[lcnt]));
859 #endif
860 #ifdef HAVE_WCHAR
861 wc[0] = l->label[lcnt];
862 wc[1] = L'\0';
863 if (setcchar(&cc, wc,
864 screen->slk_window->wattr, 0,
865 NULL) == ERR)
866 return ERR;
867 #endif
868
869 if (l->x + wcwidth(l->label[lcnt] + tx) >=
870 screen->slk_label_len) {
871 /* last character that will fit
872 * so insert it to avoid scroll
873 */
874 #ifdef HAVE_WCHAR
875 retval = mvwins_wch(screen->slk_window,
876 0, l->x + tx, &cc);
877 #else
878 retval = mvwinsch(screen->slk_window,
879 0, l->x + tx, l->label[lcnt]);
880 #endif
881 } else {
882 #ifdef HAVE_WCHAR
883 retval = mvwadd_wch(screen->slk_window,
884 0, l->x + tx, &cc);
885 #else
886 retval = mvwaddch(screen->slk_window,
887 0, l->x + tx, l->label[lcnt]);
888 #endif
889 }
890 tx += wcwidth(l->label[lcnt]);
891 lcnt += inc;
892 }
893 }
894
895 return retval;
896 } else
897 return ERR;
898 }
899
900 /*
901 * __slk_draw --
902 * Draws all the keys.
903 */
904 static int
905 __slk_redraw(SCREEN *screen)
906 {
907 int i, result = OK;
908
909 for (i = 0; i < screen->slk_nlabels; i++) {
910 if (__slk_draw(screen, i) == ERR)
911 result = ERR;
912 }
913 return result;
914 }
915