NetBSD/dist/cdk/dialog.c
garbled 12a0ea436c Fix a problem in these widgets where they uncondititonally set the
exitType to either vEARLY_EXIT, or vESCAPE_HIT when returning from a bound
function.  This had the unfortunate effect that when you hit F2 to refresh
the screen in sushi, it would exit out immediately after refreshing the
screen.

This modification allows the programmer to still create an exit-causing
bound function, by simply setting the exitType in the function, as was likely
intended by the author.  Many thanks to Charles Hannum for helping me figure
this out.

This should fix problems noted by itojun on tech-userlevel with the function
keys.
2001-01-09 18:41:53 +00:00

551 lines
13 KiB
C

#include <cdk.h>
/*
* $Author: garbled $
* $Date: 2001/01/09 18:41:53 $
* $Revision: 1.3 $
*/
DeclareCDKObjects(my_funcs,Dialog);
/*
* This function creates a dialog widget.
*/
CDKDIALOG *newCDKDialog (CDKSCREEN *cdkscreen, int xplace, int yplace, char **mesg, int rows, char **buttonLabel, int buttonCount, chtype buttonHighlight, boolean separator, boolean Box, boolean shadow)
{
/* Declare local variables. */
CDKDIALOG *dialog = newCDKObject(CDKDIALOG, &my_funcs);
int boxWidth = MIN_DIALOG_WIDTH;
int boxHeight = rows + 2;
int xpos = xplace;
int ypos = yplace;
int maxmessagewidth = 0;
int buttonWidth, buttonPos;
int x, junk2;
/* Translate the char * message to a chtype * */
for (x=0; x < rows; x++)
{
dialog->info[x] = char2Chtype (mesg[x], &dialog->infoLen[x], &dialog->infoPos[x]);
maxmessagewidth = MAXIMUM (maxmessagewidth, dialog->infoLen[x]);
}
/* Translate the button label char * to a chtype * */
buttonWidth = 0;
for (x=0; x < buttonCount; x++)
{
dialog->buttonLabel[x] = char2Chtype (buttonLabel[x], &dialog->buttonLen[x], &junk2);
buttonWidth += dialog->buttonLen[x] + 1;
}
buttonWidth--;
/* Determine the final dimensions of the box. */
boxWidth = MAXIMUM (boxWidth, maxmessagewidth + 2);
boxWidth = MAXIMUM (boxWidth, buttonWidth + 2);
if (buttonCount > 0)
{
boxHeight += separator + 1;
}
/* Now we have to readjust the x and y positions. */
alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);
/* Make the dialog window. */
dialog->win = newwin (boxHeight + !!shadow, boxWidth + !!shadow, ypos, xpos);
/* If we couldn't create the window, we should return a null value. */
if (dialog->win == 0)
{
/* Couldn't create the window. Clean up used memory. */
for (x=0; x < dialog->messageRows ; x++)
{
freeChtype (dialog->info[x]);
}
for (x=0; x < dialog->buttonCount; x++)
{
freeChtype (dialog->buttonLabel[x]);
}
/* Remove the memory used by the dialog pointer. */
free (dialog);
/* Return a null dialog box. */
return (0);
}
keypad (dialog->win, TRUE);
leaveok (dialog->win, TRUE);
/* Make the info window. */
dialog->infoWin = subwin (dialog->win,
rows, boxWidth - 2,
ypos + 1, xpos + 1);
/* Make the button window. */
if (buttonCount > 0)
{
dialog->buttonWin = subwin (dialog->win,
1, boxWidth - 2,
ypos + rows + 2, xpos + 1);
}
/* Set up the dialog box attributes. */
ScreenOf(dialog) = cdkscreen;
dialog->parent = cdkscreen->window;
dialog->buttonCount = buttonCount;
dialog->buttonHighlight = buttonHighlight;
dialog->currentButton = 0;
dialog->messageRows = rows;
dialog->boxHeight = boxHeight;
dialog->boxWidth = boxWidth;
dialog->separator = separator;
dialog->exitType = vNEVER_ACTIVATED;
ObjOf(dialog)->box = Box;
dialog->shadow = shadow;
dialog->ULChar = ACS_ULCORNER;
dialog->URChar = ACS_URCORNER;
dialog->LLChar = ACS_LLCORNER;
dialog->LRChar = ACS_LRCORNER;
dialog->HChar = ACS_HLINE;
dialog->VChar = ACS_VLINE;
dialog->BoxAttrib = A_NORMAL;
dialog->preProcessFunction = 0;
dialog->preProcessData = 0;
dialog->postProcessFunction = 0;
dialog->postProcessData = 0;
/* Find the button positions. */
buttonPos = (boxWidth - 2 - buttonWidth) / 2;
for (x=0; x < buttonCount; x++)
{
dialog->buttonPos[x] = buttonPos;
buttonPos += dialog->buttonLen[x] + 1;
}
/* Create the string alignments. */
for (x=0; x < rows; x++)
{
dialog->infoPos[x] = justifyString (boxWidth - 2, dialog->infoLen[x], dialog->infoPos[x]);
}
/* Empty the key bindings. */
cleanCDKObjectBindings (vDIALOG, dialog);
/* Register this baby. */
registerCDKObject (cdkscreen, vDIALOG, dialog);
/* Return the dialog box pointer. */
return (dialog);
}
/*
* This lets the user select the button.
*/
int activateCDKDialog (CDKDIALOG *dialog, chtype *actions)
{
/* Declare local variables. */
chtype input = 0;
int ret;
/* Draw the dialog box. */
drawCDKDialog (dialog, ObjOf(dialog)->box);
/* Check if actions is null. */
if (actions == 0)
{
for (;;)
{
/* Get the input. */
wrefresh (dialog->win);
input = wgetch (dialog->win);
/* Inject the character into the widget. */
ret = injectCDKDialog (dialog, input);
if (dialog->exitType != vEARLY_EXIT)
{
return ret;
}
}
}
else
{
int length = chlen (actions);
int x = 0;
/* Inject each character one at a time. */
for (x=0; x < length; x++)
{
ret = injectCDKDialog (dialog, actions[x]);
if (dialog->exitType != vEARLY_EXIT)
{
return ret;
}
}
}
/* Set the exit type and exit. */
dialog->exitType = vEARLY_EXIT;
return -1;
}
/*
* This injects a single character into the dialog widget.
*/
int injectCDKDialog (CDKDIALOG *dialog, chtype input)
{
int firstButton = 0;
int lastButton = dialog->buttonCount - 1;
int ppReturn = 1;
/* Set the exit type. */
dialog->exitType = vEARLY_EXIT;
/* Check if there is a pre-process function to be called. */
if (dialog->preProcessFunction != 0)
{
ppReturn = ((PROCESSFN)(dialog->preProcessFunction)) (vDIALOG, dialog, dialog->preProcessData, input);
}
/* Should we continue? */
if (ppReturn != 0)
{
/* Check for a key binding. */
if (checkCDKObjectBind (vDIALOG, dialog, input) != 0)
{
return -1;
}
else
{
switch (input)
{
case KEY_LEFT : case CDK_PREV :
if (dialog->currentButton == firstButton)
{
dialog->currentButton = lastButton;;
}
else
{
dialog->currentButton--;
}
break;
case KEY_RIGHT : case CDK_NEXT : case KEY_TAB : case ' ' :
if (dialog->currentButton == lastButton)
{
dialog->currentButton = firstButton;
}
else
{
dialog->currentButton++;
}
break;
case KEY_UP : case KEY_DOWN :
Beep();
break;
case KEY_ESC :
dialog->exitType = vESCAPE_HIT;
return -1;
case KEY_RETURN : case KEY_ENTER : case KEY_CR :
dialog->exitType = vNORMAL;
return dialog->currentButton;
case CDK_REFRESH :
eraseCDKScreen (ScreenOf(dialog));
refreshCDKScreen (ScreenOf(dialog));
break;
default :
Beep();
break;
}
}
/* Should we call a post-process? */
if (dialog->postProcessFunction != 0)
{
((PROCESSFN)(dialog->postProcessFunction)) (vDIALOG, dialog, dialog->postProcessData, input);
}
}
/* Redraw the buttons. */
drawCDKDialogButtons (dialog);
/* Exit the dialog box. */
dialog->exitType = vEARLY_EXIT;
return -1;
}
/*
* This moves the dialog field to the given location.
*/
static void _moveCDKDialog (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag)
{
CDKDIALOG *dialog = (CDKDIALOG *)object;
/*
* If this is a relative move, then we will adjust where we want
* to move to.
*/
if (relative)
{
xplace += getbegx(dialog->win);
yplace += getbegy(dialog->win);
}
/* Adjust the window if we need to. */
alignxy (WindowOf(dialog), &xplace, &yplace, dialog->boxWidth, dialog->boxHeight);
/* Move the window to the new location. */
moveCursesWindow(dialog->win, xplace, yplace);
/* Redraw the window, if they asked for it. */
if (refresh_flag)
{
drawCDKDialog (dialog, ObjOf(dialog)->box);
}
}
/*
* This function draws the dialog widget.
*/
static void _drawCDKDialog (CDKOBJS *object, boolean Box)
{
CDKDIALOG *dialog = (CDKDIALOG *)object;
int x = 0;
/* Box the widget if they asked. */
if (Box)
{
attrbox (dialog->win,
dialog->ULChar, dialog->URChar,
dialog->LLChar, dialog->LRChar,
dialog->HChar, dialog->VChar,
dialog->BoxAttrib,
dialog->shadow);
}
/* Draw in the message. */
for (x=0; x < dialog->messageRows; x++)
{
writeChtype (dialog->infoWin,
dialog->infoPos[x], x,
dialog->info[x],
HORIZONTAL, 0,
dialog->infoLen[x]);
}
wnoutrefresh (dialog->infoWin);
/* Draw in the buttons. */
drawCDKDialogButtons (dialog);
}
/*
* This function destroys the dialog widget.
*/
void destroyCDKDialog (CDKDIALOG *dialog)
{
/* Declare local variables. */
int x;
/* Erase the object. */
eraseCDKDialog (dialog);
/* Clean up the char pointers. */
for (x=0; x < dialog->messageRows; x++)
{
freeChtype (dialog->info[x]);
}
for (x=0; x < dialog->buttonCount; x++)
{
freeChtype (dialog->buttonLabel[x]);
}
/* Clean up the windows. */
deleteCursesWindow (dialog->win);
/* Unregister this object. */
unregisterCDKObject (vDIALOG, dialog);
/* Finish cleaning up. */
free (dialog);
}
/*
* This function erases the dialog widget from the screen.
*/
static void _eraseCDKDialog (CDKOBJS *object)
{
CDKDIALOG *dialog = (CDKDIALOG *)object;
eraseCursesWindow (dialog->win);
}
/*
* This sets attributes of the dialog box.
*/
void setCDKDialog (CDKDIALOG *dialog, chtype buttonHighlight, boolean separator, boolean Box)
{
setCDKDialogHighlight (dialog, buttonHighlight);
setCDKDialogSeparator (dialog, separator);
setCDKDialogBox (dialog, Box);
}
/*
* This sets the highlight attribute for the buttons.
*/
void setCDKDialogHighlight (CDKDIALOG *dialog, chtype buttonHighlight)
{
dialog->buttonHighlight = buttonHighlight;
}
chtype getCDKDialogHighlight (CDKDIALOG *dialog)
{
return dialog->buttonHighlight;
}
/*
* This sets whether or not the dialog box will have a separator line.
*/
void setCDKDialogSeparator (CDKDIALOG *dialog, boolean separator)
{
dialog->separator = separator;
}
boolean getCDKDialogSeparator (CDKDIALOG *dialog)
{
return dialog->separator;
}
/*
* This sets the box attribute of the widget.
*/
void setCDKDialogBox (CDKDIALOG *dialog, boolean Box)
{
ObjOf(dialog)->box = Box;
}
boolean getCDKDialogBox (CDKDIALOG *dialog)
{
return ObjOf(dialog)->box;
}
/*
* These functions set the drawing characters of the widget.
*/
void setCDKDialogULChar (CDKDIALOG *dialog, chtype character)
{
dialog->ULChar = character;
}
void setCDKDialogURChar (CDKDIALOG *dialog, chtype character)
{
dialog->URChar = character;
}
void setCDKDialogLLChar (CDKDIALOG *dialog, chtype character)
{
dialog->LLChar = character;
}
void setCDKDialogLRChar (CDKDIALOG *dialog, chtype character)
{
dialog->LRChar = character;
}
void setCDKDialogVerticalChar (CDKDIALOG *dialog, chtype character)
{
dialog->VChar = character;
}
void setCDKDialogHorizontalChar (CDKDIALOG *dialog, chtype character)
{
dialog->HChar = character;
}
void setCDKDialogBoxAttribute (CDKDIALOG *dialog, chtype character)
{
dialog->BoxAttrib = character;
}
/*
* This sets the background color of the widget.
*/
void setCDKDialogBackgroundColor (CDKDIALOG *dialog, 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 (dialog->win, holder[0]);
/* Clean up. */
freeChtype (holder);
}
/*
* This draws the dialog buttons and the separation line.
*/
void drawCDKDialogButtons (CDKDIALOG *dialog)
{
/* Declare local variables. */
int x;
if (dialog->buttonCount > 0)
{
for (x=0; x < dialog->buttonCount; x++)
{
if (x == dialog->currentButton)
{
writeChtypeAttrib (dialog->buttonWin,
dialog->buttonPos[x], 0,
dialog->buttonLabel[x],
dialog->buttonHighlight,
HORIZONTAL, 0,
dialog->buttonLen[x]);
}
else
{
writeChtype (dialog->buttonWin,
dialog->buttonPos[x], 0,
dialog->buttonLabel[x],
HORIZONTAL, 0,
dialog->buttonLen[x]);
}
}
/* Draw the separation line. */
if (dialog->separator)
{
mvwaddch (dialog->win, dialog->boxHeight-3, 0, ACS_LTEE | dialog->BoxAttrib);
mvwhline (dialog->win, dialog->boxHeight-3, 1, ACS_HLINE | dialog->BoxAttrib, dialog->boxWidth-2);
mvwaddch (dialog->win, dialog->boxHeight-3, dialog->boxWidth-1, ACS_RTEE | dialog->BoxAttrib);
}
wnoutrefresh (dialog->buttonWin);
}
wnoutrefresh (dialog->win);
}
/*
* This function sets the pre-process function.
*/
void setCDKDialogPreProcess (CDKDIALOG *dialog, PROCESSFN callback, void *data)
{
dialog->preProcessFunction = callback;
dialog->preProcessData = data;
}
/*
* This function sets the post-process function.
*/
void setCDKDialogPostProcess (CDKDIALOG *dialog, PROCESSFN callback, void *data)
{
dialog->postProcessFunction = callback;
dialog->postProcessData = data;
}