1 #include <curses.h>
2 #include <stddef.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <assert.h>
6 #include "mucurses.h"
7 #include "cursor.h"
8 
9 /** @file
10  *
11  * Soft label key functions
12  */
13 
14 #define MIN_SPACE_SIZE 2
15 
16 #define SLK_MAX_LABEL_LEN 8
17 
18 #define SLK_MAX_NUM_LABELS 12
19 
20 #define SLK_MAX_NUM_SPACES 2
21 
22 struct _softlabel {
23 	// label string
24 	char label[SLK_MAX_LABEL_LEN];
25 	/* Format of soft label
26 	   0: left justify
27 	   1: centre justify
28 	   2: right justify
29 	 */
30 	unsigned int fmt;
31 };
32 
33 struct _softlabelkeys {
34 	struct _softlabel fkeys[SLK_MAX_NUM_LABELS];
35 	attr_t attrs;
36 	/* Soft label layout format
37 	   0: 3-2-3
38 	   1: 4-4
39 	   2: 4-4-4
40 	   3: 4-4-4 with index line
41 	*/
42 	unsigned int fmt;
43 	unsigned int max_label_len;
44 	unsigned int maj_space_len;
45 	unsigned int num_labels;
46 	unsigned int num_spaces;
47 	unsigned int spaces[SLK_MAX_NUM_SPACES];
48 	struct cursor_pos saved_cursor;
49 	attr_t saved_attrs;
50 	short saved_pair;
51 };
52 
53 static struct _softlabelkeys *slks;
54 
55 /*
56   I either need to break the primitives here, or write a collection of
57   functions specifically for SLKs that directly access the screen
58   functions - since this technically isn't part of stdscr, I think
59   this should be ok...
60  */
61 
_enter_slk(void)62 static void _enter_slk ( void ) {
63 	_store_curs_pos ( stdscr, &slks->saved_cursor );
64 	wattr_get ( stdscr, &slks->saved_attrs, &slks->saved_pair, NULL );
65 	LINES++;
66 	wmove ( stdscr, LINES, 0 );
67 	wattrset ( stdscr, slks->attrs );
68 }
69 
_leave_slk(void)70 static void _leave_slk ( void ) {
71 	LINES--;
72 	wattr_set ( stdscr, slks->saved_attrs, slks->saved_pair, NULL );
73 	_restore_curs_pos ( stdscr, &slks->saved_cursor );
74 }
75 
_print_label(struct _softlabel sl)76 static void _print_label ( struct _softlabel sl ) {
77 	int space_ch;
78 	char str[SLK_MAX_LABEL_LEN + 1];
79 
80 	assert ( slks->max_label_len <= SLK_MAX_LABEL_LEN );
81 	space_ch = ' ';
82 
83 	// protect against gaps in the soft label keys array
84 	if ( sl.label == NULL ) {
85 		memset( str, space_ch, (size_t)(slks->max_label_len) );
86 	} else {
87 		/* we need to pad the label with varying amounts of leading
88 		   pad depending on the format of the label */
89 		if ( sl.fmt == 1 ) {
90 			memset( str, space_ch,
91 				(size_t)(slks->max_label_len
92 					 - strlen(sl.label)) / 2 );
93 		}
94 		if ( sl.fmt == 2 ) {
95 			memset( str, space_ch,
96 				(size_t)(slks->max_label_len
97 					 - strlen(sl.label)) );
98 		}
99 		strcat(str,sl.label);
100 
101 		// post-padding
102 		memset(str+strlen(str), space_ch,
103 		       (size_t)(slks->max_label_len - strlen(str)) );
104 	}
105 
106 	// print the formatted label
107 	_wputstr ( stdscr, str, NOWRAP, slks->max_label_len );
108 }
109 
110 /**
111  * Return the attribute used for the soft function keys
112  *
113  * @ret attrs	the current attributes of the soft function keys
114  */
slk_attr(void)115 attr_t slk_attr ( void ) {
116 	return ( slks == NULL ? 0 : slks->attrs );
117 }
118 
119 /**
120  * Turn off soft function key attributes
121  *
122  * @v attrs	attribute bit mask
123  * @ret rc	return status code
124  */
slk_attroff(const chtype attrs)125 int slk_attroff ( const chtype attrs ) {
126 	if ( slks == NULL )
127 		return ERR;
128 	slks->attrs &= ~( attrs & A_ATTRIBUTES );
129 	return OK;
130 }
131 
132 /**
133  * Turn on soft function key attributes
134  *
135  * @v attrs	attribute bit mask
136  * @ret rc	return status code
137  */
slk_attron(const chtype attrs)138 int slk_attron ( const chtype attrs ) {
139 	if ( slks == NULL )
140 		return ERR;
141 	slks->attrs |= ( attrs & A_ATTRIBUTES );
142 	return OK;
143 }
144 
145 /**
146  * Set soft function key attributes
147  *
148  * @v attrs	attribute bit mask
149  * @ret rc	return status code
150  */
slk_attrset(const chtype attrs)151 int slk_attrset ( const chtype attrs ) {
152 	if ( slks == NULL )
153 		return ERR;
154 	slks->attrs = ( attrs & A_ATTRIBUTES );
155 	return OK;
156 }
157 
158 /**
159  * Turn off soft function key attributes
160  *
161  * @v attrs	attribute bit mask
162  * @v *opts	undefined (for future implementation)
163  * @ret rc	return status code
164  */
slk_attr_off(const attr_t attrs,void * opts __unused)165 int slk_attr_off ( const attr_t attrs, void *opts __unused ) {
166 	return slk_attroff( attrs );
167 }
168 
169 /**
170  * Turn on soft function key attributes
171  *
172  * @v attrs	attribute bit mask
173  * @v *opts	undefined (for future implementation)
174  * @ret rc	return status code
175  */
slk_attr_on(attr_t attrs,void * opts __unused)176 int slk_attr_on ( attr_t attrs, void *opts __unused ) {
177 	return slk_attron( attrs );
178 }
179 
180 /**
181  * Set soft function key attributes
182  *
183  * @v attrs			attribute bit mask
184  * @v colour_pair_number	colour pair integer
185  * @v *opts			undefined (for future implementation)
186  * @ret rc			return status code
187  */
slk_attr_set(const attr_t attrs,short colour_pair_number,void * opts __unused)188 int slk_attr_set ( const attr_t attrs, short colour_pair_number,
189 		   void *opts __unused ) {
190 	if ( slks == NULL )
191 		return ERR;
192 
193 	if ( ( unsigned short )colour_pair_number > COLORS )
194 		return ERR;
195 
196 	slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT ) |
197 		( attrs & A_ATTRIBUTES );
198 	return OK;
199 }
200 
201 /**
202  * Clear the soft function key labels from the screen
203  *
204  * @ret rc	return status code
205  */
slk_clear(void)206 int slk_clear ( void ) {
207 	if ( slks == NULL )
208 		return ERR;
209 
210 	_enter_slk();
211 	wclrtoeol ( stdscr );
212 	_leave_slk();
213 
214 	return OK;
215 }
216 
217 /**
218  * Set soft label colour pair
219  */
slk_colour(short colour_pair_number)220 int slk_colour ( short colour_pair_number ) {
221 	if ( slks == NULL )
222 		return ERR;
223 	if ( ( unsigned short )colour_pair_number > COLORS )
224 		return ERR;
225 
226 	slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT )
227 		| ( slks->attrs & A_ATTRIBUTES );
228 
229 	return OK;
230 }
231 
232 /**
233  * Initialise the soft function keys
234  *
235  * @v fmt	format of keys
236  * @ret rc	return status code
237  */
slk_init(int fmt)238 int slk_init ( int fmt ) {
239 	unsigned short nmaj, nmin, nblocks, available_width;
240 
241 	if ( (unsigned)fmt > 3 ) {
242 		return ERR;
243 	}
244 
245 	/* There seems to be no API call to free this data structure... */
246 	if ( ! slks )
247 		slks = calloc(1,sizeof(*slks));
248 	if ( ! slks )
249 		return ERR;
250 
251 	slks->attrs = A_DEFAULT;
252 	slks->fmt = fmt;
253 	switch(fmt) {
254 	case 0:
255 		nblocks = 8; nmaj = 2; nmin = 5;
256 		slks->spaces[0] = 2; slks->spaces[1] = 4;
257 		break;
258 	case 1:
259 		nblocks = 8; nmaj = 1; nmin = 6;
260 		slks->spaces[0] = 3;
261 		break;
262 	case 2:
263 		// same allocations as format 3
264 	case 3:
265 		nblocks = 12; nmaj = 2; nmin = 9;
266 		slks->spaces[0] = 3; slks->spaces[1] = 7;
267 		break;
268 	default:
269 		nblocks = 0; nmaj = 0; nmin = 0;
270 		break;
271 	}
272 
273 	// determine maximum label length and major space size
274 	available_width = COLS - ( ( MIN_SPACE_SIZE * nmaj ) + nmin );
275 	slks->max_label_len = available_width / nblocks;
276 	slks->maj_space_len = MIN_SPACE_SIZE +
277 		( available_width % nblocks ) / nmaj;
278 	slks->num_spaces = nmaj;
279 	slks->num_labels = nblocks;
280 
281 	// strip a line from the screen
282 	LINES -= 1;
283 
284 	return OK;
285 }
286 
287 /**
288  * Return the label for the specified soft key
289  *
290  * @v labnum	soft key identifier
291  * @ret label	return label
292  */
slk_label(int labnum)293 char* slk_label ( int labnum ) {
294 	if ( slks == NULL )
295 		return NULL;
296 
297 	return slks->fkeys[labnum].label;
298 }
299 
300 /**
301  * Restore soft function key labels to the screen
302  *
303  * @ret rc	return status code
304  */
slk_restore(void)305 int slk_restore ( void ) {
306 	unsigned int i, j, pos_x,
307 		*next_space, *last_space;
308 	chtype space_ch;
309 
310 	if ( slks == NULL )
311 		return ERR;
312 
313 	pos_x = 0;
314 
315 	_enter_slk();
316 
317 	space_ch = (chtype)' ' | slks->attrs;
318 	next_space = &(slks->spaces[0]);
319 	last_space = &(slks->spaces[slks->num_spaces-1]);
320 
321 	for ( i = 0; i < slks->num_labels ; i++ ) {
322 		_print_label( slks->fkeys[i] );
323 		pos_x += slks->max_label_len;
324 
325 		if ( i == *next_space ) {
326 			for ( j = 0; j < slks->maj_space_len; j++, pos_x++ )
327 				_wputch ( stdscr, space_ch, NOWRAP );
328 			if ( next_space < last_space )
329 				next_space++;
330 		} else {
331 			if ( pos_x < COLS )
332 				_wputch ( stdscr, space_ch, NOWRAP );
333 			pos_x++;
334 		}
335 	}
336 
337 	_leave_slk();
338 
339 	return OK;
340 }
341 
342 /**
343  * Configure specified soft key
344  *
345  * @v labnum	soft label position to configure
346  * @v *label	string to use as soft key label
347  * @v fmt	justification format of label
348  * @ret rc	return status code
349  */
slk_set(int labnum,const char * label,int fmt)350 int slk_set ( int labnum, const char *label, int fmt ) {
351 	if ( slks == NULL )
352 		return ERR;
353 	if ( (unsigned short)labnum >= slks->num_labels )
354 		return ERR;
355 	if ( (unsigned short)fmt >= 3 )
356 		return ERR;
357 
358 	strncpy(slks->fkeys[labnum].label, label,
359 		sizeof(slks->fkeys[labnum].label));
360 	slks->fkeys[labnum].fmt = fmt;
361 
362 	return OK;
363 }
364