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