564 lines
13 KiB
C
564 lines
13 KiB
C
#include <cdk_int.h>
|
|
|
|
/*
|
|
* $Author: tom $
|
|
* $Date: 2016/11/20 19:02:55 $
|
|
* $Revision: 1.102 $
|
|
*/
|
|
|
|
DeclareCDKObjects (DIALOG, Dialog, setCdk, Int);
|
|
|
|
/*
|
|
* This function creates a dialog widget.
|
|
*/
|
|
CDKDIALOG *newCDKDialog (CDKSCREEN *cdkscreen,
|
|
int xplace,
|
|
int yplace,
|
|
CDK_CSTRING2 mesg,
|
|
int rows,
|
|
CDK_CSTRING2 buttonLabel,
|
|
int buttonCount,
|
|
chtype highlight,
|
|
boolean separator,
|
|
boolean Box,
|
|
boolean shadow)
|
|
{
|
|
/* *INDENT-EQLS* */
|
|
CDKDIALOG *dialog = 0;
|
|
int boxHeight;
|
|
int boxWidth = MIN_DIALOG_WIDTH;
|
|
int maxmessagewidth = -1;
|
|
int buttonwidth = 0;
|
|
int xpos = xplace;
|
|
int ypos = yplace;
|
|
int temp = 0;
|
|
int buttonadj = 0;
|
|
int x = 0;
|
|
|
|
if (rows <= 0
|
|
|| buttonCount <= 0
|
|
|| (dialog = newCDKObject (CDKDIALOG, &my_funcs)) == 0
|
|
|| (dialog->info = typeCallocN (chtype *, rows + 1)) == 0
|
|
|| (dialog->infoLen = typeCallocN (int, rows + 1)) == 0
|
|
|| (dialog->infoPos = typeCallocN (int, rows + 1)) == 0
|
|
|| (dialog->buttonLabel = typeCallocN (chtype *, buttonCount + 1)) == 0
|
|
|| (dialog->buttonLen = typeCallocN (int, buttonCount + 1)) == 0
|
|
|| (dialog->buttonPos = typeCallocN (int, buttonCount + 1)) == 0)
|
|
{
|
|
destroyCDKObject (dialog);
|
|
return (0);
|
|
}
|
|
|
|
setCDKDialogBox (dialog, Box);
|
|
boxHeight = rows + 2 * BorderOf (dialog) + separator + 1;
|
|
|
|
/* 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 * */
|
|
for (x = 0; x < buttonCount; x++)
|
|
{
|
|
/* *INDENT-EQLS* */
|
|
dialog->buttonLabel[x] = char2Chtype (buttonLabel[x],
|
|
&dialog->buttonLen[x],
|
|
&temp);
|
|
buttonwidth += dialog->buttonLen[x] + 1;
|
|
}
|
|
buttonwidth--;
|
|
|
|
/* Determine the final dimensions of the box. */
|
|
boxWidth = MAXIMUM (boxWidth, maxmessagewidth);
|
|
boxWidth = MAXIMUM (boxWidth, buttonwidth);
|
|
boxWidth = boxWidth + 2 + 2 * BorderOf (dialog);
|
|
|
|
/* Now we have to readjust the x and y positions. */
|
|
alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);
|
|
|
|
/* *INDENT-EQLS* Set up the dialog box attributes. */
|
|
ScreenOf (dialog) = cdkscreen;
|
|
dialog->parent = cdkscreen->window;
|
|
dialog->win = newwin (boxHeight, boxWidth, ypos, xpos);
|
|
dialog->shadowWin = 0;
|
|
dialog->buttonCount = buttonCount;
|
|
dialog->currentButton = 0;
|
|
dialog->messageRows = rows;
|
|
dialog->boxHeight = boxHeight;
|
|
dialog->boxWidth = boxWidth;
|
|
dialog->highlight = highlight;
|
|
dialog->separator = separator;
|
|
initExitType (dialog);
|
|
ObjOf (dialog)->acceptsFocus = TRUE;
|
|
ObjOf (dialog)->inputWindow = dialog->win;
|
|
dialog->shadow = shadow;
|
|
|
|
/* If we couldn't create the window, we should return a null value. */
|
|
if (dialog->win == 0)
|
|
{
|
|
destroyCDKObject (dialog);
|
|
return (0);
|
|
}
|
|
keypad (dialog->win, TRUE);
|
|
|
|
/* Find the button positions. */
|
|
buttonadj = ((int)((boxWidth - buttonwidth) / 2));
|
|
for (x = 0; x < buttonCount; x++)
|
|
{
|
|
dialog->buttonPos[x] = buttonadj;
|
|
buttonadj = buttonadj + dialog->buttonLen[x] + BorderOf (dialog);
|
|
}
|
|
|
|
/* Create the string alignments. */
|
|
for (x = 0; x < rows; x++)
|
|
{
|
|
dialog->infoPos[x] = justifyString (boxWidth - 2 * BorderOf (dialog),
|
|
dialog->infoLen[x],
|
|
dialog->infoPos[x]);
|
|
}
|
|
|
|
/* Was there a shadow? */
|
|
if (shadow)
|
|
{
|
|
dialog->shadowWin = newwin (boxHeight, boxWidth, ypos + 1, xpos + 1);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
chtype input = 0;
|
|
boolean functionKey;
|
|
int ret;
|
|
|
|
/* Draw the dialog box. */
|
|
drawCDKDialog (dialog, ObjOf (dialog)->box);
|
|
|
|
/* Lets move to the first button. */
|
|
writeChtypeAttrib (dialog->win,
|
|
dialog->buttonPos[dialog->currentButton],
|
|
dialog->boxHeight - 1 - BorderOf (dialog),
|
|
dialog->buttonLabel[dialog->currentButton],
|
|
dialog->highlight,
|
|
HORIZONTAL,
|
|
0, dialog->buttonLen[dialog->currentButton]);
|
|
wrefresh (dialog->win);
|
|
|
|
if (actions == 0)
|
|
{
|
|
for (;;)
|
|
{
|
|
input = (chtype)getchCDKObject (ObjOf (dialog), &functionKey);
|
|
|
|
/* 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. */
|
|
setExitType (dialog, 0);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* This injects a single character into the dialog widget.
|
|
*/
|
|
static int _injectCDKDialog (CDKOBJS *object, chtype input)
|
|
{
|
|
/* *INDENT-EQLS* */
|
|
CDKDIALOG *widget = (CDKDIALOG *)object;
|
|
int lastButton = widget->buttonCount - 1;
|
|
int ppReturn = 1;
|
|
int ret = unknownInt;
|
|
bool complete = FALSE;
|
|
|
|
/* Set the exit type. */
|
|
setExitType (widget, 0);
|
|
|
|
/* Check if there is a pre-process function to be called. */
|
|
if (PreProcessFuncOf (widget) != 0)
|
|
{
|
|
ppReturn = PreProcessFuncOf (widget) (vDIALOG,
|
|
widget,
|
|
PreProcessDataOf (widget),
|
|
input);
|
|
}
|
|
|
|
/* Should we continue? */
|
|
if (ppReturn != 0)
|
|
{
|
|
/* Check for a key binding. */
|
|
if (checkCDKObjectBind (vDIALOG, widget, input) != 0)
|
|
{
|
|
checkEarlyExit (widget);
|
|
complete = TRUE;
|
|
}
|
|
else
|
|
{
|
|
int firstButton = 0;
|
|
|
|
switch (input)
|
|
{
|
|
case KEY_LEFT:
|
|
case KEY_BTAB:
|
|
case KEY_BACKSPACE:
|
|
if (widget->currentButton == firstButton)
|
|
{
|
|
widget->currentButton = lastButton;;
|
|
}
|
|
else
|
|
{
|
|
widget->currentButton--;
|
|
}
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
case KEY_TAB:
|
|
case SPACE:
|
|
if (widget->currentButton == lastButton)
|
|
{
|
|
widget->currentButton = firstButton;
|
|
}
|
|
else
|
|
{
|
|
widget->currentButton++;
|
|
}
|
|
break;
|
|
|
|
case KEY_UP:
|
|
case KEY_DOWN:
|
|
Beep ();
|
|
break;
|
|
|
|
case CDK_REFRESH:
|
|
eraseCDKScreen (ScreenOf (widget));
|
|
refreshCDKScreen (ScreenOf (widget));
|
|
break;
|
|
|
|
case KEY_ESC:
|
|
setExitType (widget, input);
|
|
complete = TRUE;
|
|
break;
|
|
|
|
case KEY_ERROR:
|
|
setExitType (widget, input);
|
|
complete = TRUE;
|
|
break;
|
|
|
|
case KEY_ENTER:
|
|
setExitType (widget, input);
|
|
ret = widget->currentButton;
|
|
complete = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Should we call a post-process? */
|
|
if (!complete && (PostProcessFuncOf (widget) != 0))
|
|
{
|
|
PostProcessFuncOf (widget) (vDIALOG,
|
|
widget,
|
|
PostProcessDataOf (widget),
|
|
input);
|
|
}
|
|
}
|
|
|
|
if (!complete)
|
|
{
|
|
drawCDKDialogButtons (widget);
|
|
wrefresh (widget->win);
|
|
setExitType (widget, 0);
|
|
}
|
|
|
|
ResultOf (widget).valueInt = ret;
|
|
return (ret != unknownInt);
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
/* *INDENT-EQLS* */
|
|
int currentX = getbegx (dialog->win);
|
|
int currentY = getbegy (dialog->win);
|
|
int xpos = xplace;
|
|
int ypos = yplace;
|
|
int xdiff = 0;
|
|
int ydiff = 0;
|
|
|
|
/*
|
|
* If this is a relative move, then we will adjust where we want
|
|
* to move to.
|
|
*/
|
|
if (relative)
|
|
{
|
|
xpos = getbegx (dialog->win) + xplace;
|
|
ypos = getbegy (dialog->win) + yplace;
|
|
}
|
|
|
|
/* Adjust the window if we need to. */
|
|
alignxy (WindowOf (dialog), &xpos, &ypos, dialog->boxWidth, dialog->boxHeight);
|
|
|
|
/* Get the difference. */
|
|
xdiff = currentX - xpos;
|
|
ydiff = currentY - ypos;
|
|
|
|
/* Move the window to the new location. */
|
|
moveCursesWindow (dialog->win, -xdiff, -ydiff);
|
|
moveCursesWindow (dialog->shadowWin, -xdiff, -ydiff);
|
|
|
|
/* Touch the windows so they 'move'. */
|
|
refreshCDKWindow (WindowOf (dialog));
|
|
|
|
/* 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;
|
|
|
|
/* Is there a shadow? */
|
|
if (dialog->shadowWin != 0)
|
|
{
|
|
drawShadow (dialog->shadowWin);
|
|
}
|
|
|
|
/* Box the widget if they asked. */
|
|
if (Box)
|
|
{
|
|
drawObjBox (dialog->win, ObjOf (dialog));
|
|
}
|
|
|
|
/* Draw in the message. */
|
|
for (x = 0; x < dialog->messageRows; x++)
|
|
{
|
|
writeChtype (dialog->win,
|
|
dialog->infoPos[x] + BorderOf (dialog), x + BorderOf (dialog),
|
|
dialog->info[x],
|
|
HORIZONTAL, 0,
|
|
dialog->infoLen[x]);
|
|
}
|
|
|
|
/* Draw in the buttons. */
|
|
drawCDKDialogButtons (dialog);
|
|
|
|
wrefresh (dialog->win);
|
|
}
|
|
|
|
/*
|
|
* This function destroys the dialog widget.
|
|
*/
|
|
static void _destroyCDKDialog (CDKOBJS *object)
|
|
{
|
|
if (object != 0)
|
|
{
|
|
CDKDIALOG *dialog = (CDKDIALOG *)object;
|
|
|
|
CDKfreeChtypes (dialog->info);
|
|
freeChecked (dialog->infoLen);
|
|
freeChecked (dialog->infoPos);
|
|
|
|
CDKfreeChtypes (dialog->buttonLabel);
|
|
freeChecked (dialog->buttonLen);
|
|
freeChecked (dialog->buttonPos);
|
|
|
|
/* Clean up the windows. */
|
|
deleteCursesWindow (dialog->win);
|
|
deleteCursesWindow (dialog->shadowWin);
|
|
|
|
/* Clean the key bindings. */
|
|
cleanCDKObjectBindings (vDIALOG, dialog);
|
|
|
|
/* Unregister this object. */
|
|
unregisterCDKObject (vDIALOG, dialog);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function erases the dialog widget from the screen.
|
|
*/
|
|
static void _eraseCDKDialog (CDKOBJS *object)
|
|
{
|
|
if (validCDKObject (object))
|
|
{
|
|
CDKDIALOG *dialog = (CDKDIALOG *)object;
|
|
|
|
eraseCursesWindow (dialog->win);
|
|
eraseCursesWindow (dialog->shadowWin);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This sets attributes of the dialog box.
|
|
*/
|
|
void setCDKDialog (CDKDIALOG *dialog, chtype highlight, boolean separator, boolean Box)
|
|
{
|
|
setCDKDialogHighlight (dialog, highlight);
|
|
setCDKDialogSeparator (dialog, separator);
|
|
setCDKDialogBox (dialog, Box);
|
|
}
|
|
|
|
/*
|
|
* This sets the highlight attribute for the buttons.
|
|
*/
|
|
void setCDKDialogHighlight (CDKDIALOG *dialog, chtype highlight)
|
|
{
|
|
dialog->highlight = highlight;
|
|
}
|
|
chtype getCDKDialogHighlight (CDKDIALOG *dialog)
|
|
{
|
|
return dialog->highlight;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
ObjOf (dialog)->borderSize = Box ? 1 : 0;
|
|
}
|
|
boolean getCDKDialogBox (CDKDIALOG *dialog)
|
|
{
|
|
return ObjOf (dialog)->box;
|
|
}
|
|
|
|
/*
|
|
* This sets the background attribute of the widget.
|
|
*/
|
|
static void _setBKattrDialog (CDKOBJS *object, chtype attrib)
|
|
{
|
|
if (object != 0)
|
|
{
|
|
CDKDIALOG *widget = (CDKDIALOG *)object;
|
|
|
|
wbkgd (widget->win, attrib);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This draws the dialog buttons and the separation line.
|
|
*/
|
|
void drawCDKDialogButtons (CDKDIALOG *dialog)
|
|
{
|
|
int x;
|
|
|
|
for (x = 0; x < dialog->buttonCount; x++)
|
|
{
|
|
writeChtype (dialog->win,
|
|
dialog->buttonPos[x],
|
|
dialog->boxHeight - 1 - BorderOf (dialog),
|
|
dialog->buttonLabel[x],
|
|
HORIZONTAL, 0,
|
|
dialog->buttonLen[x]);
|
|
}
|
|
|
|
/* Draw the separation line. */
|
|
if (dialog->separator)
|
|
{
|
|
chtype boxattr = BXAttrOf (dialog);
|
|
|
|
for (x = 1; x < dialog->boxWidth - 1; x++)
|
|
{
|
|
(void)mvwaddch (dialog->win,
|
|
dialog->boxHeight - 2 - BorderOf (dialog),
|
|
x,
|
|
ACS_HLINE | boxattr);
|
|
}
|
|
(void)mvwaddch (dialog->win,
|
|
dialog->boxHeight - 2 - BorderOf (dialog),
|
|
0,
|
|
ACS_LTEE | boxattr);
|
|
(void)mvwaddch (dialog->win,
|
|
dialog->boxHeight - 2 - BorderOf (dialog),
|
|
getmaxx (dialog->win) - 1,
|
|
ACS_RTEE | boxattr);
|
|
}
|
|
writeChtypeAttrib (dialog->win,
|
|
dialog->buttonPos[dialog->currentButton],
|
|
dialog->boxHeight - 1 - BorderOf (dialog),
|
|
dialog->buttonLabel[dialog->currentButton],
|
|
dialog->highlight,
|
|
HORIZONTAL, 0,
|
|
dialog->buttonLen[dialog->currentButton]);
|
|
|
|
}
|
|
|
|
static void _focusCDKDialog (CDKOBJS *object)
|
|
{
|
|
CDKDIALOG *widget = (CDKDIALOG *)object;
|
|
|
|
drawCDKDialog (widget, ObjOf (widget)->box);
|
|
}
|
|
|
|
static void _unfocusCDKDialog (CDKOBJS *object)
|
|
{
|
|
CDKDIALOG *widget = (CDKDIALOG *)object;
|
|
|
|
drawCDKDialog (widget, ObjOf (widget)->box);
|
|
}
|
|
|
|
dummyRefreshData (Dialog)
|
|
|
|
dummySaveData (Dialog)
|