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
62 static int slk_fmt = SLK_FMT_INVAL; /* fmt of slk_init */
63
64 /* Safe variants of public functions. */
65 static int __slk_attroff(SCREEN *, const chtype);
66 static int __slk_attron(SCREEN *, const chtype);
67 static int __slk_attrset(SCREEN *, const chtype);
68 #ifdef HAVE_WCHAR
69 static int __slk_attr_off(SCREEN *, const attr_t, void *);
70 static int __slk_attr_on(SCREEN *, const attr_t, void *);
71 static int __slk_attr_set(SCREEN *, const attr_t, short, void *opt);
72 static int __slk_color(SCREEN *, short);
73 #endif
74
75 static int __slk_clear(SCREEN *);
76 static char *__slk_label(SCREEN *, int);
77 static int __slk_restore(SCREEN *);
78 static int __slk_set(SCREEN *, int, const char *, int);
79 static int __slk_touch(SCREEN *);
80 #ifdef HAVE_WCHAR
81 static int __slk_wset(SCREEN *, int, const wchar_t *, int);
82 #endif
83
84 /* Internal engine parts. */
85 static int __slk_ripoffline(WINDOW *, int);
86 static int __slk_set_finalise(SCREEN *, int);
87 static int __slk_draw(SCREEN *, int);
88 static int __slk_redraw(SCREEN *);
89
90 /*
91 * slk_init --
92 * Init Soft Label Keys.
93 */
94 int
slk_init(int fmt)95 slk_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 */
116 int
slk_attron(const chtype attr)117 slk_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 */
128 int
slk_attr_on(const attr_t attr,void * opt)129 slk_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 */
140 int
slk_attroff(const chtype attr)141 slk_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 */
152 int
slk_attr_off(const attr_t attr,void * opt)153 slk_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 */
164 int
slk_attrset(const chtype attr)165 slk_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 */
176 int
slk_attr_set(const attr_t attr,short pair,void * opt)177 slk_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 */
188 int
slk_clear(void)189 slk_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 */
200 int
slk_color(short pair)201 slk_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 */
212 char *
slk_label(int labnum)213 slk_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 */
223 int
slk_noutrefresh(void)224 slk_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 */
234 int
slk_refresh(void)235 slk_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 */
247 int
slk_restore(void)248 slk_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 */
259 int
slk_set(int labnum,const char * label,int justify)260 slk_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 */
270 int
slk_touch(void)271 slk_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 */
283 int
slk_wset(int labnum,const wchar_t * label,int justify)284 slk_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 */
295 static int
__slk_attron(SCREEN * screen,const chtype attr)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 */
309 static int
__slk_attr_on(SCREEN * screen,const attr_t attr,void * opt)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 */
323 static int
__slk_attroff(SCREEN * screen,const chtype attr)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 */
337 static int
__slk_attr_off(SCREEN * screen,const attr_t attr,void * opt)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 */
351 static int
__slk_attrset(SCREEN * screen,const chtype attr)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 */
365 static int
__slk_attr_set(SCREEN * screen,const attr_t attr,short pair,void * opt)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 */
379 static int
__slk_clear(SCREEN * screen)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 */
403 static int
__slk_color(SCREEN * screen,short pair)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 */
417 static char *
__slk_label(SCREEN * screen,int labnum)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 */
430 int
__slk_noutrefresh(SCREEN * screen)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 */
443 static int
__slk_restore(SCREEN * screen)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 */
468 static int
__slk_set(SCREEN * screen,int labnum,const char * label,int justify)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 */
534 static int
__slk_touch(SCREEN * screen)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 */
550 static int
__slk_wset(SCREEN * screen,int labnum,const wchar_t * label,int justify)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);
577 out:
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 */
590 int
__slk_init(SCREEN * screen)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 */
632 void
__slk_free(SCREEN * screen)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 */
648 static int
__slk_ripoffline(WINDOW * window,int cols)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 */
666 int
__slk_resize(SCREEN * screen,int cols)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 */
729 static int
__slk_set_finalise(SCREEN * screen,int labnum)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 */
811 static int
__slk_draw(SCREEN * screen,int labnum)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 */
901 static int
__slk_redraw(SCREEN * screen)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