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