1/****************************************************************************
2 * Copyright 2020 Thomas E. Dickey                                          *
3 * Copyright 1998-2010,2011 Free Software Foundation, Inc.                  *
4 *                                                                          *
5 * Permission is hereby granted, free of charge, to any person obtaining a  *
6 * copy of this software and associated documentation files (the            *
7 * "Software"), to deal in the Software without restriction, including      *
8 * without limitation the rights to use, copy, modify, merge, publish,      *
9 * distribute, distribute with modifications, sublicense, and/or sell       *
10 * copies of the Software, and to permit persons to whom the Software is    *
11 * furnished to do so, subject to the following conditions:                 *
12 *                                                                          *
13 * The above copyright notice and this permission notice shall be included  *
14 * in all copies or substantial portions of the Software.                   *
15 *                                                                          *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23 *                                                                          *
24 * Except as contained in this notice, the name(s) of the above copyright   *
25 * holders shall not be used in advertising or otherwise to promote the     *
26 * sale, use or other dealings in this Software without prior written       *
27 * authorization.                                                           *
28 ****************************************************************************/
29
30/****************************************************************************
31 *  Authors:                                                                *
32 *          Gerhard Fuernkranz                      1993 (original)         *
33 *          Zeyd M. Ben-Halim                       1992,1995 (sic)         *
34 *          Eric S. Raymond                                                 *
35 *          Juergen Pfeifer                         1996-on                 *
36 *          Thomas E. Dickey                                                *
37 ****************************************************************************/
38
39/*
40 *	lib_slk.c
41 *	Soft key routines.
42 */
43
44#include <curses.priv.h>
45#include <ctype.h>
46
47#ifndef CUR
48#define CUR SP_TERMTYPE
49#endif
50
51MODULE_ID("$Id: lib_slk.c,v 1.49 2020/02/02 23:34:34 tom Exp $")
52
53#ifdef USE_TERM_DRIVER
54#define NumLabels    InfoOf(SP_PARM).numlabels
55#define NoColorVideo InfoOf(SP_PARM).nocolorvideo
56#define LabelWidth   InfoOf(SP_PARM).labelwidth
57#define LabelHeight  InfoOf(SP_PARM).labelheight
58#else
59#define NumLabels    num_labels
60#define NoColorVideo no_color_video
61#define LabelWidth   label_width
62#define LabelHeight  label_height
63#endif
64
65/*
66 * Free any memory related to soft labels, return an error.
67 */
68static int
69slk_failed(NCURSES_SP_DCL0)
70{
71    if ((0 != SP_PARM) && SP_PARM->_slk) {
72	FreeIfNeeded(SP_PARM->_slk->ent);
73	free(SP_PARM->_slk);
74	SP_PARM->_slk = (SLK *) 0;
75    }
76    return ERR;
77}
78
79NCURSES_EXPORT(int)
80_nc_format_slks(NCURSES_SP_DCLx int cols)
81{
82    int gap, i, x;
83    int max_length;
84
85    if (!SP_PARM || !SP_PARM->_slk)
86	return ERR;
87
88    max_length = SP_PARM->_slk->maxlen;
89    if (SP_PARM->slk_format >= 3) {	/* PC style */
90	gap = (cols - 3 * (3 + 4 * max_length)) / 2;
91
92	if (gap < 1)
93	    gap = 1;
94
95	for (i = x = 0; i < SP_PARM->_slk->maxlab; i++) {
96	    SP_PARM->_slk->ent[i].ent_x = x;
97	    x += max_length;
98	    x += (i == 3 || i == 7) ? gap : 1;
99	}
100    } else {
101	if (SP_PARM->slk_format == 2) {		/* 4-4 */
102	    gap = cols - (int) (SP_PARM->_slk->maxlab * max_length) - 6;
103
104	    if (gap < 1)
105		gap = 1;
106	    for (i = x = 0; i < SP_PARM->_slk->maxlab; i++) {
107		SP_PARM->_slk->ent[i].ent_x = x;
108		x += max_length;
109		x += (i == 3) ? gap : 1;
110	    }
111	} else {
112	    if (SP_PARM->slk_format == 1) {	/* 1 -> 3-2-3 */
113		gap = (cols - (SP_PARM->_slk->maxlab * max_length) - 5)
114		    / 2;
115
116		if (gap < 1)
117		    gap = 1;
118		for (i = x = 0; i < SP_PARM->_slk->maxlab; i++) {
119		    SP_PARM->_slk->ent[i].ent_x = x;
120		    x += max_length;
121		    x += (i == 2 || i == 4) ? gap : 1;
122		}
123	    } else {
124		return slk_failed(NCURSES_SP_ARG);
125	    }
126	}
127    }
128    SP_PARM->_slk->dirty = TRUE;
129
130    return OK;
131}
132
133/*
134 * Initialize soft labels.
135 * Called from newterm()
136 */
137NCURSES_EXPORT(int)
138_nc_slk_initialize(WINDOW *stwin, int cols)
139{
140    int i;
141    int res = OK;
142    size_t max_length;
143    SCREEN *sp;
144    int numlab;
145
146    T((T_CALLED("_nc_slk_initialize()")));
147
148    assert(stwin);
149
150    sp = _nc_screen_of(stwin);
151    if (0 == sp)
152	returnCode(ERR);
153
154    assert(TerminalOf(SP_PARM));
155
156    numlab = NumLabels;
157
158    if (SP_PARM->_slk) {	/* we did this already, so simply return */
159	returnCode(OK);
160    } else if ((SP_PARM->_slk = typeCalloc(SLK, 1)) == 0)
161	returnCode(ERR);
162
163    if (!SP_PARM->slk_format)
164	SP_PARM->slk_format = _nc_globals.slk_format;
165
166    /*
167     * If we use colors, vidputs() will suppress video attributes that conflict
168     * with colors.  In that case, we're still guaranteed that "reverse" would
169     * work.
170     */
171    if ((NoColorVideo & 1) == 0)
172	SetAttr(SP_PARM->_slk->attr, A_STANDOUT);
173    else
174	SetAttr(SP_PARM->_slk->attr, A_REVERSE);
175
176    SP_PARM->_slk->maxlab = (short) ((numlab > 0)
177				     ? numlab
178				     : MAX_SKEY(SP_PARM->slk_format));
179    SP_PARM->_slk->maxlen = (short) ((numlab > 0)
180				     ? LabelWidth * LabelHeight
181				     : MAX_SKEY_LEN(SP_PARM->slk_format));
182    SP_PARM->_slk->labcnt = (short) ((SP_PARM->_slk->maxlab < MAX_SKEY(SP_PARM->slk_format))
183				     ? MAX_SKEY(SP_PARM->slk_format)
184				     : SP_PARM->_slk->maxlab);
185
186    if (SP_PARM->_slk->maxlen <= 0
187	|| SP_PARM->_slk->labcnt <= 0
188	|| (SP_PARM->_slk->ent = typeCalloc(slk_ent,
189					    (size_t) SP_PARM->_slk->labcnt))
190	== NULL)
191	returnCode(slk_failed(NCURSES_SP_ARG));
192
193    max_length = (size_t) SP_PARM->_slk->maxlen;
194    for (i = 0; i < SP_PARM->_slk->labcnt; i++) {
195	size_t used = max_length + 1;
196
197	SP_PARM->_slk->ent[i].ent_text = (char *) _nc_doalloc(0, used);
198	if (SP_PARM->_slk->ent[i].ent_text == 0)
199	    returnCode(slk_failed(NCURSES_SP_ARG));
200	memset(SP_PARM->_slk->ent[i].ent_text, 0, used);
201
202	SP_PARM->_slk->ent[i].form_text = (char *) _nc_doalloc(0, used);
203	if (SP_PARM->_slk->ent[i].form_text == 0)
204	    returnCode(slk_failed(NCURSES_SP_ARG));
205
206	if (used > 1) {
207	    memset(SP_PARM->_slk->ent[i].form_text, ' ', used - 1);
208	}
209	SP_PARM->_slk->ent[i].form_text[used - 1] = '\0';
210
211	SP_PARM->_slk->ent[i].visible = (char) (i < SP_PARM->_slk->maxlab);
212    }
213
214    res = _nc_format_slks(NCURSES_SP_ARGx cols);
215
216    if ((SP_PARM->_slk->win = stwin) == NULL) {
217	returnCode(slk_failed(NCURSES_SP_ARG));
218    }
219
220    /* We now reset the format so that the next newterm has again
221     * per default no SLK keys and may call slk_init again to
222     * define a new layout. (juergen 03-Mar-1999)
223     */
224    _nc_globals.slk_format = 0;
225    returnCode(res);
226}
227
228/*
229 * Restore the soft labels on the screen.
230 */
231NCURSES_EXPORT(int)
232NCURSES_SP_NAME(slk_restore) (NCURSES_SP_DCL0)
233{
234    T((T_CALLED("slk_restore(%p)"), (void *) SP_PARM));
235
236    if (0 == SP_PARM)
237	returnCode(ERR);
238    if (SP_PARM->_slk == NULL)
239	returnCode(ERR);
240    SP_PARM->_slk->hidden = FALSE;
241    SP_PARM->_slk->dirty = TRUE;
242
243    returnCode(NCURSES_SP_NAME(slk_refresh) (NCURSES_SP_ARG));
244}
245
246#if NCURSES_SP_FUNCS
247NCURSES_EXPORT(int)
248slk_restore(void)
249{
250    return NCURSES_SP_NAME(slk_restore) (CURRENT_SCREEN);
251}
252#endif
253