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 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 } 364