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