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