#include <curses.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "mucurses.h"
#include "cursor.h"
/** @file
*
* Soft label key functions
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define MIN_SPACE_SIZE 2
#define SLK_MAX_LABEL_LEN 8
#define SLK_MAX_NUM_LABELS 12
#define SLK_MAX_NUM_SPACES 2
struct _softlabel {
// label string
char label[SLK_MAX_LABEL_LEN];
/* Format of soft label
0: left justify
1: centre justify
2: right justify
*/
unsigned int fmt;
};
struct _softlabelkeys {
struct _softlabel fkeys[SLK_MAX_NUM_LABELS];
attr_t attrs;
/* Soft label layout format
0: 3-2-3
1: 4-4
2: 4-4-4
3: 4-4-4 with index line
*/
unsigned int fmt;
unsigned int max_label_len;
unsigned int maj_space_len;
unsigned int num_labels;
unsigned int num_spaces;
unsigned int spaces[SLK_MAX_NUM_SPACES];
struct cursor_pos saved_cursor;
attr_t saved_attrs;
short saved_pair;
};
static struct _softlabelkeys *slks;
/*
I either need to break the primitives here, or write a collection of
functions specifically for SLKs that directly access the screen
functions - since this technically isn't part of stdscr, I think
this should be ok...
*/
static void _enter_slk ( void ) {
_store_curs_pos ( stdscr, &slks->saved_cursor );
wattr_get ( stdscr, &slks->saved_attrs, &slks->saved_pair, NULL );
LINES++;
wmove ( stdscr, LINES, 0 );
wattrset ( stdscr, slks->attrs );
}
static void _leave_slk ( void ) {
LINES--;
wattr_set ( stdscr, slks->saved_attrs, slks->saved_pair, NULL );
_restore_curs_pos ( stdscr, &slks->saved_cursor );
}
static void _print_label ( struct _softlabel sl ) {
int space_ch;
char str[SLK_MAX_LABEL_LEN + 1];
assert ( slks->max_label_len <= SLK_MAX_LABEL_LEN );
space_ch = ' ';
memset ( str, 0, sizeof ( str ) );
// protect against gaps in the soft label keys array
if ( ! sl.label[0] ) {
memset( str, space_ch, (size_t)(slks->max_label_len) );
} else {
/* we need to pad the label with varying amounts of leading
pad depending on the format of the label */
if ( sl.fmt == 1 ) {
memset( str, space_ch,
(size_t)(slks->max_label_len
- strlen(sl.label)) / 2 );
}
if ( sl.fmt == 2 ) {
memset( str, space_ch,
(size_t)(slks->max_label_len
- strlen(sl.label)) );
}
strcat(str,sl.label);
// post-padding
memset(str+strlen(str), space_ch,
(size_t)(slks->max_label_len - strlen(str)) );
}
// print the formatted label
_wputstr ( stdscr, str, NOWRAP, slks->max_label_len );
}
/**
* Return the attribute used for the soft function keys
*
* @ret attrs the current attributes of the soft function keys
*/
attr_t slk_attr ( void ) {
return ( slks == NULL ? 0 : slks->attrs );
}
/**
* Turn off soft function key attributes
*
* @v attrs attribute bit mask
* @ret rc return status code
*/
int slk_attroff ( const chtype attrs ) {
if ( slks == NULL )
return ERR;
slks->attrs &= ~( attrs & A_ATTRIBUTES );
return OK;
}
/**
* Turn on soft function key attributes
*
* @v attrs attribute bit mask
* @ret rc return status code
*/
int slk_attron ( const chtype attrs ) {
if ( slks == NULL )
return ERR;
slks->attrs |= ( attrs & A_ATTRIBUTES );
return OK;
}
/**
* Set soft function key attributes
*
* @v attrs attribute bit mask
* @ret rc return status code
*/
int slk_attrset ( const chtype attrs ) {
if ( slks == NULL )
return ERR;
slks->attrs = ( attrs & A_ATTRIBUTES );
return OK;
}
/**
* Turn off soft function key attributes
*
* @v attrs attribute bit mask
* @v *opts undefined (for future implementation)
* @ret rc return status code
*/
int slk_attr_off ( const attr_t attrs, void *opts __unused ) {
return slk_attroff( attrs );
}
/**
* Turn on soft function key attributes
*
* @v attrs attribute bit mask
* @v *opts undefined (for future implementation)
* @ret rc return status code
*/
int slk_attr_on ( attr_t attrs, void *opts __unused ) {
return slk_attron( attrs );
}
/**
* Set soft function key attributes
*
* @v attrs attribute bit mask
* @v colour_pair_number colour pair integer
* @v *opts undefined (for future implementation)
* @ret rc return status code
*/
int slk_attr_set ( const attr_t attrs, short colour_pair_number,
void *opts __unused ) {
if ( slks == NULL )
return ERR;
if ( ( unsigned short )colour_pair_number > COLORS )
return ERR;
slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT ) |
( attrs & A_ATTRIBUTES );
return OK;
}
/**
* Clear the soft function key labels from the screen
*
* @ret rc return status code
*/
int slk_clear ( void ) {
if ( slks == NULL )
return ERR;
_enter_slk();
wclrtoeol ( stdscr );
_leave_slk();
return OK;
}
/**
* Set soft label colour pair
*/
int slk_colour ( short colour_pair_number ) {
if ( slks == NULL )
return ERR;
if ( ( unsigned short )colour_pair_number > COLORS )
return ERR;
slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT )
| ( slks->attrs & A_ATTRIBUTES );
return OK;
}
/**
* Initialise the soft function keys
*
* @v fmt format of keys
* @ret rc return status code
*/
int slk_init ( int fmt ) {
unsigned short nmaj, nmin, nblocks, available_width;
if ( (unsigned)fmt > 3 ) {
return ERR;
}
/* There seems to be no API call to free this data structure... */
if ( ! slks )
slks = calloc(1,sizeof(*slks));
if ( ! slks )
return ERR;
slks->attrs = A_DEFAULT;
slks->fmt = fmt;
switch(fmt) {
case 0:
nblocks = 8; nmaj = 2; nmin = 5;
slks->spaces[0] = 2; slks->spaces[1] = 4;
break;
case 1:
nblocks = 8; nmaj = 1; nmin = 6;
slks->spaces[0] = 3;
break;
case 2:
// same allocations as format 3
case 3:
nblocks = 12; nmaj = 2; nmin = 9;
slks->spaces[0] = 3; slks->spaces[1] = 7;
break;
default:
return ERR;
}
// determine maximum label length and major space size
available_width = COLS - ( ( MIN_SPACE_SIZE * nmaj ) + nmin );
slks->max_label_len = available_width / nblocks;
slks->maj_space_len = MIN_SPACE_SIZE +
( available_width % nblocks ) / nmaj;
slks->num_spaces = nmaj;
slks->num_labels = nblocks;
// strip a line from the screen
LINES -= 1;
return OK;
}
/**
* Return the label for the specified soft key
*
* @v labnum soft key identifier
* @ret label return label
*/
char* slk_label ( int labnum ) {
if ( slks == NULL )
return NULL;
return slks->fkeys[labnum].label;
}
/**
* Restore soft function key labels to the screen
*
* @ret rc return status code
*/
int slk_restore ( void ) {
unsigned int i, j, pos_x,
*next_space, *last_space;
chtype space_ch;
if ( slks == NULL )
return ERR;
pos_x = 0;
_enter_slk();
space_ch = (chtype)' ' | slks->attrs;
next_space = &(slks->spaces[0]);
last_space = &(slks->spaces[slks->num_spaces-1]);
for ( i = 0; i < slks->num_labels ; i++ ) {
_print_label( slks->fkeys[i] );
pos_x += slks->max_label_len;
if ( i == *next_space ) {
for ( j = 0; j < slks->maj_space_len; j++, pos_x++ )
_wputch ( stdscr, space_ch, NOWRAP );
if ( next_space < last_space )
next_space++;
} else {
if ( pos_x < COLS )
_wputch ( stdscr, space_ch, NOWRAP );
pos_x++;
}
}
_leave_slk();
return OK;
}
/**
* Configure specified soft key
*
* @v labnum soft label position to configure
* @v *label string to use as soft key label
* @v fmt justification format of label
* @ret rc return status code
*/
int slk_set ( int labnum, const char *label, int fmt ) {
if ( slks == NULL )
return ERR;
if ( (unsigned short)labnum >= slks->num_labels )
return ERR;
if ( (unsigned short)fmt >= 3 )
return ERR;
strncpy(slks->fkeys[labnum].label, label,
(sizeof(slks->fkeys[labnum].label) - 1));
slks->fkeys[labnum].fmt = fmt;
return OK;
}