NetBSD/dist/cdk/radio.c

899 lines
20 KiB
C

#include <cdk.h>
/*
* $Author: garbled $
* $Date: 2001/01/09 18:41:53 $
* $Revision: 1.3 $
*/
/*
* Declare file local prototypes.
*/
static void drawCDKRadioList (CDKRADIO *radio);
static void createCDKRadioItemList (CDKRADIO *radio,
char **list, int listSize);
DeclareCDKObjects(my_funcs,Radio);
/*
* This function creates the radio widget.
*/
CDKRADIO *newCDKRadio (CDKSCREEN *cdkscreen, int xplace, int yplace, int splace, int height, int width, char *title, char **list, int listSize, chtype choiceChar, int defItem, chtype highlight, boolean Box, boolean shadow)
{
/* Declare local variables. */
CDKRADIO *radio = newCDKObject(CDKRADIO, &my_funcs);
chtype *holder = 0;
int parentWidth = getmaxx(cdkscreen->window);
int parentHeight = getmaxy(cdkscreen->window);
int boxWidth = width;
int boxHeight = height;
int maxWidth = INT_MIN;
int xpos = xplace;
int ypos = yplace;
char **temp = 0;
int x, len, junk2;
if (splace == LEFT || splace == RIGHT)
{
radio->scrollbar = TRUE;
}
else
{
radio->scrollbar = FALSE;
}
/*
* If the height is a negative value, the height will
* be ROWS-height, otherwise, the height will be the
* given height.
*/
boxHeight = setWidgetDimension (parentHeight, height, 0);
/*
* If the width is a negative value, the width will
* be COLS-width, otherwise, the width will be the
* given width.
*/
boxWidth = setWidgetDimension (parentWidth, width, 5);
/* Translate the char * title to a chtype * */
if (title != 0)
{
temp = CDKsplitString (title, '\n');
radio->titleLines = CDKcountStrings (temp);
/* We need to determine the widest title line. */
for (x=0; x < radio->titleLines; x++)
{
holder = char2Chtype (temp[x], &len, &junk2);
maxWidth = MAXIMUM (maxWidth, len);
freeChtype (holder);
}
boxWidth = MAXIMUM (boxWidth, maxWidth + 2);
/* For each line in the title, convert from a char * to a chtype * */
for (x=0; x < radio->titleLines; x++)
{
radio->title[x] = char2Chtype (temp[x],
&radio->titleLen[x],
&radio->titlePos[x]);
radio->titlePos[x] = justifyString (boxWidth - 2,
radio->titleLen[x],
radio->titlePos[x]);
}
CDKfreeStrings(temp);
}
else
{
radio->titleLines = 0;
}
/* Set the box height. */
if (radio->titleLines > boxHeight)
{
if (listSize > 8)
{
boxHeight = radio->titleLines + 10;
}
else
{
boxHeight = radio->titleLines + listSize + 2;
}
}
radio->fieldWidth = boxWidth - 2 - radio->scrollbar;
radio->viewSize = boxHeight - 2 - radio->titleLines;
/*
* Make sure we didn't extend beyond the dimensions of the window.
*/
boxWidth = MINIMUM (boxWidth, parentWidth);
boxHeight = MINIMUM (boxHeight, parentHeight);
/* Rejustify the x and y positions if we need to. */
alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);
/* Make the radio window */
radio->win = newwin (boxHeight + !!shadow, boxWidth + !!shadow, ypos, xpos);
/* Is the window null??? */
if (radio->win == 0)
{
/* Clean up memory. */
for (x=0; x < radio->titleLines; x++)
{
freeChtype (radio->title[x]);
}
free (radio);
/* Return a null pointer. */
return (0);
}
keypad (radio->win, TRUE);
leaveok (radio->win, TRUE);
if (radio->titleLines > 0)
{
/* Make the title window. */
radio->titleWin = subwin (radio->win,
radio->titleLines, boxWidth - 2,
ypos + 1, xpos + 1);
}
/* Create the scrollbar window. */
if (splace == RIGHT)
{
radio->fieldWin = subwin (radio->win,
radio->viewSize, radio->fieldWidth,
ypos + radio->titleLines + 1,
xpos + 1);
radio->scrollbarWin = subwin (radio->win,
radio->viewSize, 1,
ypos + radio->titleLines + 1,
xpos + 1 + radio->fieldWidth);
}
else if (splace == LEFT)
{
radio->scrollbarWin = subwin (radio->win,
radio->viewSize, 1,
ypos + radio->titleLines + 1,
xpos + 1);
radio->fieldWin = subwin (radio->win,
radio->viewSize, radio->fieldWidth,
ypos + radio->titleLines + 1,
xpos + 2);
}
else
{
radio->fieldWin = subwin (radio->win,
radio->viewSize, radio->fieldWidth,
ypos + radio->titleLines + 1,
xpos + 1);
radio->scrollbarWin = 0;
}
/* Set the rest of the variables */
ScreenOf(radio) = cdkscreen;
radio->parent = cdkscreen->window;
radio->boxHeight = boxHeight;
radio->boxWidth = boxWidth;
radio->currentTop = 0;
radio->currentItem = 0;
radio->currentHigh = 0;
radio->leftChar = 0;
radio->selectedItem = defItem;
radio->highlight = highlight;
radio->choiceChar = choiceChar;
radio->leftBoxChar = (chtype)'[';
radio->rightBoxChar = (chtype)']';
radio->exitType = vNEVER_ACTIVATED;
ObjOf(radio)->box = Box;
radio->shadow = shadow;
radio->preProcessFunction = 0;
radio->preProcessData = 0;
radio->postProcessFunction = 0;
radio->postProcessData = 0;
radio->ULChar = ACS_ULCORNER;
radio->URChar = ACS_URCORNER;
radio->LLChar = ACS_LLCORNER;
radio->LRChar = ACS_LRCORNER;
radio->HChar = ACS_HLINE;
radio->VChar = ACS_VLINE;
radio->BoxAttrib = A_NORMAL;
/* Create the scrolling list item list and needed variables. */
createCDKRadioItemList (radio, list, listSize);
/* Clean the key bindings. */
cleanCDKObjectBindings (vRADIO, radio);
/* Register this baby. */
registerCDKObject (cdkscreen, vRADIO, radio);
/* Return the radio list */
return (radio);
}
/*
* This actually manages the radio widget.
*/
int activateCDKRadio (CDKRADIO *radio, chtype *actions)
{
/* Draw the radio list. */
drawCDKRadio (radio, ObjOf(radio)->box);
/* Check if actions is null. */
if (actions == 0)
{
/* Declare some local variables. */
chtype input;
int ret;
for (;;)
{
/* Get the input. */
wrefresh (radio->win);
input = wgetch (radio->win);
/* Inject the character into the widget. */
ret = injectCDKRadio (radio, input);
if (radio->exitType != vEARLY_EXIT)
{
return ret;
}
}
}
else
{
/* Declare some local variables. */
int length = chlen (actions);
int x, ret;
/* Inject each character one at a time. */
for (x=0; x < length; x++)
{
ret = injectCDKRadio (radio, actions[x]);
if (radio->exitType != vEARLY_EXIT)
{
return ret;
}
}
}
/* Set the exit type and return. */
radio->exitType = vEARLY_EXIT;
return -1;
}
/*
* This injects a single character into the widget.
*/
int injectCDKRadio (CDKRADIO *radio, chtype input)
{
/* Declare local variables. */
int ppReturn = 1;
/* Set the exit type. */
radio->exitType = vEARLY_EXIT;
/* Draw the radio list */
drawCDKRadioList (radio);
/* Check if there is a pre-process function to be called. */
if (radio->preProcessFunction != 0)
{
/* Call the pre-process function. */
ppReturn = ((PROCESSFN)(radio->preProcessFunction)) (vRADIO, radio, radio->preProcessData, input);
}
/* Should we continue? */
if (ppReturn != 0)
{
/* Check for a predefined key binding. */
if (checkCDKObjectBind (vRADIO, radio, input) != 0)
{
return -1;
}
else
{
switch (input)
{
case KEY_UP :
if (radio->currentItem > 0)
{
radio->currentItem--;
if (radio->currentHigh == 0)
{
radio->currentTop--;
}
else
{
radio->currentHigh--;
}
}
else
{
Beep();
}
break;
case KEY_DOWN :
if (radio->currentItem < radio->listSize - 1)
{
radio->currentItem++;
if (radio->currentHigh == radio->viewSize - 1)
{
radio->currentTop++;
}
else
{
radio->currentHigh++;
}
}
else
{
Beep();
}
break;
case KEY_LEFT :
if (radio->leftChar > 0)
{
radio->leftChar--;
}
else
{
Beep();
}
break;
case KEY_RIGHT :
if (radio->leftChar < radio->maxLeftChar)
{
radio->leftChar++;
}
else
{
Beep();
}
break;
case KEY_PPAGE :
case CONTROL('B') :
if (radio->currentItem > 0)
{
radio->currentTop =
MAXIMUM (radio->currentTop - radio->viewSize + 1,
0);
radio->currentItem =
MAXIMUM (radio->currentItem - radio->viewSize + 1,
0);
radio->currentHigh =
radio->currentItem - radio->currentTop;
}
else
{
Beep();
}
break;
case KEY_NPAGE :
case CONTROL('F') :
if (radio->currentItem < radio->listSize - 1)
{
radio->currentTop =
MINIMUM (radio->currentTop + radio->viewSize - 1,
radio->maxTopItem);
radio->currentItem =
MINIMUM (radio->currentItem + radio->viewSize - 1,
radio->listSize-1);
radio->currentHigh =
radio->currentItem - radio->currentTop;
}
else
{
Beep();
}
break;
case 'g' :
case '1' :
case KEY_HOME :
radio->currentTop = 0;
radio->currentItem = 0;
radio->currentHigh = 0;
break;
case 'G' :
case KEY_END :
radio->currentTop = radio->maxTopItem;
radio->currentItem = radio->listSize-1;
radio->currentHigh = radio->currentItem - radio->currentTop;
break;
case '|' :
radio->leftChar = 0;
break;
case '$' :
radio->leftChar = radio->maxLeftChar;
break;
case SPACE :
radio->selectedItem = radio->currentItem;
break;
case KEY_ESC :
radio->exitType = vESCAPE_HIT;
return -1;
case KEY_RETURN :
case KEY_TAB :
case KEY_ENTER :
case KEY_CR :
radio->exitType = vNORMAL;
return radio->selectedItem;
case CDK_REFRESH :
eraseCDKScreen (ScreenOf(radio));
refreshCDKScreen (ScreenOf(radio));
break;
default :
Beep();
break;
}
}
/* Should we call a post-process? */
if (radio->postProcessFunction != 0)
{
((PROCESSFN)(radio->postProcessFunction)) (vRADIO, radio, radio->postProcessData, input);
}
}
/* Draw the radio list */
drawCDKRadioList (radio);
/* Set the exit type and return. */
radio->exitType = vEARLY_EXIT;
return -1;
}
/*
* This moves the radio field to the given location.
*/
static void _moveCDKRadio (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag)
{
CDKRADIO *radio = (CDKRADIO *)object;
/*
* If this is a relative move, then we will adjust where we want
* to move to.
*/
if (relative)
{
xplace += getbegx(radio->win);
yplace += getbegy(radio->win);
}
/* Adjust the window if we need to. */
alignxy (WindowOf(radio), &xplace, &yplace, radio->boxWidth, radio->boxHeight);
/* Move the window to the new location. */
moveCursesWindow(radio->win, xplace, yplace);
/* Redraw the window, if they asked for it. */
if (refresh_flag)
{
drawCDKRadio (radio, ObjOf(radio)->box);
}
}
/*
* This function draws the radio widget.
*/
static void _drawCDKRadio (CDKOBJS *object, boolean Box GCC_UNUSED)
{
CDKRADIO *radio = (CDKRADIO *)object;
int x;
/* Box it if needed. */
if (Box)
{
attrbox (radio->win,
radio->ULChar, radio->URChar,
radio->LLChar, radio->LRChar,
radio->HChar, radio->VChar,
radio->BoxAttrib,
radio->shadow);
}
if (radio->titleLines > 0)
{
/* Draw in the title if there is one */
for (x=0; x < radio->titleLines; x++)
{
writeChtype (radio->titleWin,
radio->titlePos[x], x,
radio->title[x],
HORIZONTAL, 0,
radio->titleLen[x]);
}
wnoutrefresh (radio->titleWin);
}
/* Draw in the radio list. */
drawCDKRadioList (radio);
}
/*
* This redraws the radio list.
*/
static void drawCDKRadioList (CDKRADIO *radio)
{
/* Declare local variables. */
int screenPos, x, y;
chtype temp[3];
werase (radio->fieldWin);
/* Redraw the list */
for (x=0, y=radio->currentTop; x < radio->viewSize; x++, y++)
{
if (y >= radio->listSize)
{
break;
}
screenPos = radio->itemPos[y] - radio->leftChar;
/* Draw in the line. */
if (y == radio->currentItem)
{
if (screenPos >= 0)
{
writeChtypeAttrib (radio->fieldWin,
screenPos, x,
radio->item[y],
radio->highlight,
HORIZONTAL, 0,
radio->itemLen[y]);
}
else
{
writeChtypeAttrib (radio->fieldWin,
0, x,
radio->item[y],
radio->highlight,
HORIZONTAL, -screenPos,
radio->itemLen[y]);
}
}
else
{
if (screenPos >= 0)
{
writeChtype (radio->fieldWin,
screenPos, x,
radio->item[y],
HORIZONTAL, 0,
radio->itemLen[y]);
}
else
{
writeChtype (radio->fieldWin,
0, x,
radio->item[y],
HORIZONTAL, -screenPos,
radio->itemLen[y]);
}
}
screenPos = - radio->leftChar;
temp[0] = radio->leftBoxChar;
if (y == radio->selectedItem)
{
temp[1] = radio->choiceChar;
}
else
{
temp[1] = ' ';
}
temp[2] = radio->rightBoxChar;
writeChtype (radio->fieldWin,
0, x,
temp,
HORIZONTAL, -screenPos,
3);
}
if (radio->scrollbar)
{
int togglePos;
/* Determine where the toggle is supposed to be. */
if (radio->listSize >= radio->viewSize)
togglePos = floorCDK ((float)radio->viewSize * (float)radio->currentItem / (float)radio->listSize);
else
togglePos = floorCDK ((float)(radio->viewSize - radio->toggleSize) * (float)radio->currentItem / (float)(radio->listSize - 1));
/* Make sure the toggle button doesn't go out of bounds. */
togglePos = MINIMUM (togglePos, radio->viewSize - radio->toggleSize);
/* Draw the scrollbar. */
mvwvline (radio->scrollbarWin, 0, 0, ACS_CKBOARD, radio->viewSize);
mvwvline (radio->scrollbarWin, togglePos, 0, ' ' | A_REVERSE, radio->toggleSize);
wnoutrefresh (radio->scrollbarWin);
}
/* Refresh the window. */
wnoutrefresh (radio->fieldWin);
wnoutrefresh (radio->win);
}
/*
* These functions set the drawing characters of the widget.
*/
void setCDKRadioULChar (CDKRADIO *radio, chtype character)
{
radio->ULChar = character;
}
void setCDKRadioURChar (CDKRADIO *radio, chtype character)
{
radio->URChar = character;
}
void setCDKRadioLLChar (CDKRADIO *radio, chtype character)
{
radio->LLChar = character;
}
void setCDKRadioLRChar (CDKRADIO *radio, chtype character)
{
radio->LRChar = character;
}
void setCDKRadioVerticalChar (CDKRADIO *radio, chtype character)
{
radio->VChar = character;
}
void setCDKRadioHorizontalChar (CDKRADIO *radio, chtype character)
{
radio->HChar = character;
}
void setCDKRadioBoxAttribute (CDKRADIO *radio, chtype character)
{
radio->BoxAttrib = character;
}
/*
* This sets the background color of the widget.
*/
void setCDKRadioBackgroundColor (CDKRADIO *radio, char *color)
{
chtype *holder = 0;
int junk1, junk2;
/* Make sure the color isn't null. */
if (color == 0)
{
return;
}
/* Convert the value of the environment variable to a chtype. */
holder = char2Chtype (color, &junk1, &junk2);
/* Set the widgets background color. */
wbkgd (radio->win, holder[0]);
if (radio->scrollbar)
{
wbkgd (radio->scrollbarWin, holder[0]);
}
/* Clean up. */
freeChtype (holder);
}
/*
* This function destroys the radio widget.
*/
void destroyCDKRadio (CDKRADIO *radio)
{
/* Declare local variables. */
int x;
/* Erase the object. */
eraseCDKRadio (radio);
/* Clear up the char pointers. */
for (x=0; x < radio->titleLines; x++)
{
freeChtype (radio->title[x]);
}
for (x=0; x < radio->listSize; x++)
{
freeChtype (radio->item[x]);
}
/* Clean up the windows. */
deleteCursesWindow (radio->win);
/* Unregister this object. */
unregisterCDKObject (vRADIO, radio);
/* Finish cleaning up. */
free (radio);
}
/*
* This function erases the radio widget.
*/
static void _eraseCDKRadio (CDKOBJS *object)
{
CDKRADIO *radio = (CDKRADIO *)object;
eraseCursesWindow (radio->win);
}
/*
* This function creates massages the scrolling list information and
* sets up the needed variables for the scrolling list to work correctly.
*/
static void createCDKRadioItemList (CDKRADIO *radio, char **list, int listSize)
{
/* Declare local variables. */
int widestItem, x;
/* Is the view size larger than the list? */
radio->listSize = listSize;
radio->maxTopItem = MAXIMUM (0, listSize - radio->viewSize);
/* Determine the size of the scrollbar toggle and the step. */
if (listSize >= radio->viewSize)
radio->toggleSize = 1;
else
radio->toggleSize = floorCDK ((float)radio->viewSize / (float)listSize + 0.5);
/* Each item in the needs to be converted to chtype * */
widestItem = 0;
for (x=0; x < listSize; x++)
{
radio->item[x] = char2Chtype (list[x], &radio->itemLen[x], &radio->itemPos[x]);
radio->itemPos[x] = justifyString (radio->fieldWidth, radio->itemLen[x], radio->itemPos[x]) + 3;
widestItem = MAXIMUM (widestItem, radio->itemLen[x]);
}
/*
* Determine how many characters we can shift to the right
* before all the items have been scrolled off the screen.
*/
radio->maxLeftChar = MAXIMUM (0, widestItem - radio->fieldWidth + 3);
}
/*
* This set various attributes of the radio list.
*/
void setCDKRadio (CDKRADIO *radio, chtype highlight, chtype choiceChar, int Box)
{
setCDKRadioChoiceCharacter (radio, choiceChar);
setCDKRadioHighlight (radio, highlight);
setCDKRadioBox (radio, Box);
}
/*
* This sets the radio list items.
*/
void setCDKRadioItems (CDKRADIO *radio, char **list, int listSize)
{
/* Declare some wars. */
int x;
/* Clean out the old list. */
for (x=0; x < radio->listSize; x++)
{
freeChtype (radio->item[x]);
radio->itemLen[x] = 0;
radio->itemPos[x] = 0;
}
/* Set some vars. */
radio->currentTop = 0;
radio->currentItem = 0;
radio->currentHigh = 0;
radio->leftChar = 0;
radio->selectedItem = 0;
/* Set up the new list. */
createCDKRadioItemList (radio, list, listSize);
}
int getCDKRadioItems (CDKRADIO *radio, char *list[])
{
int x;
for (x=0; x < radio->listSize; x++)
{
list[x] = chtype2Char (radio->item[x]);
}
return radio->listSize;
}
/*
* This sets the highlight bar of the radio list.
*/
void setCDKRadioHighlight (CDKRADIO *radio, chtype highlight)
{
radio->highlight = highlight;
}
chtype getCDKRadioHighlight (CDKRADIO *radio)
{
return radio->highlight;
}
/*
* This sets the character to use when selecting an item in the list.
*/
void setCDKRadioChoiceCharacter (CDKRADIO *radio, chtype character)
{
radio->choiceChar = character;
}
chtype getCDKRadioChoiceCharacter (CDKRADIO *radio)
{
return radio->choiceChar;
}
/*
* This sets the character to use to draw the left side of the
* choice box on the list.
*/
void setCDKRadioLeftBrace (CDKRADIO *radio, chtype character)
{
radio->leftBoxChar = character;
}
chtype getCDKRadioLeftBrace (CDKRADIO *radio)
{
return radio->leftBoxChar;
}
/*
* This sets the character to use to draw the right side of the
* choice box on the list.
*/
void setCDKRadioRightBrace (CDKRADIO *radio, chtype character)
{
radio->rightBoxChar = character;
}
chtype getCDKRadioRightBrace (CDKRADIO *radio)
{
return radio->rightBoxChar;
}
/*
* This sets the box attribute of the widget.
*/
void setCDKRadioBox (CDKRADIO *radio, boolean Box)
{
ObjOf(radio)->box = Box;
}
boolean getCDKRadioBox (CDKRADIO *radio)
{
return ObjOf(radio)->box;
}
/*
* This function sets the pre-process function.
*/
void setCDKRadioPreProcess (CDKRADIO *radio, PROCESSFN callback, void *data)
{
radio->preProcessFunction = callback;
radio->preProcessData = data;
}
/*
* This function sets the post-process function.
*/
void setCDKRadioPostProcess (CDKRADIO *radio, PROCESSFN callback, void *data)
{
radio->postProcessFunction = callback;
radio->postProcessData = data;
}