Include stdlib.h rather than malloc.h
[people/meteger/gpxe.git] / src / hci / mucurses / slk.c
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 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
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
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
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }