NetBSD/dist/cdk/alphalist.c

622 lines
17 KiB
C

#include <cdk.h>
/*
* $Author: christos $
* $Date: 2006/03/26 22:00:23 $
* $Revision: 1.2 $
*/
/*
* Declare file local prototypes.
*/
static BINDFN_PROTO(adjustAlphalistCB);
static BINDFN_PROTO(completeWordCB);
static int preProcessEntryField (EObjectType cdktype, void *object, void *clientData, chtype input);
DeclareCDKObjects(my_funcs,Alphalist);
/*
* This creates the alphalist widget.
*/
CDKALPHALIST *newCDKAlphalist (CDKSCREEN *cdkscreen, int xplace, int yplace, int height, int width, char *title, char *label, char *list[], int listSize, chtype fillerChar, chtype highlight, boolean Box, boolean shadow)
{
/* Set up some variables. */
CDKALPHALIST *alphalist = newCDKObject(CDKALPHALIST, &my_funcs);
chtype *chtypeLabel = 0;
int parentWidth = getmaxx(cdkscreen->window);
int parentHeight = getmaxy(cdkscreen->window);
int boxWidth = width;
int boxHeight = height;
int xpos = xplace;
int ypos = yplace;
int entryWidth = 0;
int labelLen = 0;
int x, junk2;
/*
* 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, 0);
/* Translate the label char *pointer to a chtype pointer. */
if (label != 0)
{
chtypeLabel = char2Chtype (label, &labelLen, &junk2);
freeChtype (chtypeLabel);
}
/* Rejustify the x and y positions if we need to. */
alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);
/* Make the file selector window. */
alphalist->win = newwin (boxHeight + !!shadow, boxWidth + !!shadow, ypos, xpos);
if (alphalist->win == 0)
{
free (alphalist);
return (0);
}
keypad (alphalist->win, TRUE);
/* Set some variables. */
ScreenOf(alphalist) = cdkscreen;
alphalist->parent = cdkscreen->window;
alphalist->highlight = highlight;
alphalist->fillerChar = fillerChar;
alphalist->boxHeight = boxHeight;
alphalist->boxWidth = boxWidth;
alphalist->exitType = vNEVER_ACTIVATED;
ObjOf(alphalist)->box = Box;
alphalist->shadow = shadow;
/* We need to sort the list before we use it. */
quickSort (list, 0, listSize-1);
/* Copy the list information. */
for (x=0; x < listSize; x++)
{
alphalist->list[x] = copyChar (list[x]);
}
alphalist->listSize = listSize;
/* Create the entry field. */
entryWidth = boxWidth - (labelLen + 2);
alphalist->entryField = newCDKEntry (cdkscreen,
getbegx(alphalist->win),
getbegy(alphalist->win),
title, label,
A_NORMAL, fillerChar,
vMIXED, entryWidth, 0, 512,
Box, FALSE);
setCDKEntryLLChar (alphalist->entryField, ACS_LTEE);
setCDKEntryLRChar (alphalist->entryField, ACS_RTEE);
/* Set the key bindings for the entry field. */
bindCDKObject (vENTRY, alphalist->entryField, KEY_UP, adjustAlphalistCB, alphalist);
bindCDKObject (vENTRY, alphalist->entryField, KEY_DOWN, adjustAlphalistCB, alphalist);
bindCDKObject (vENTRY, alphalist->entryField, KEY_NPAGE, adjustAlphalistCB, alphalist);
bindCDKObject (vENTRY, alphalist->entryField, CONTROL('F'), adjustAlphalistCB, alphalist);
bindCDKObject (vENTRY, alphalist->entryField, KEY_PPAGE, adjustAlphalistCB, alphalist);
bindCDKObject (vENTRY, alphalist->entryField, CONTROL('B'), adjustAlphalistCB, alphalist);
bindCDKObject (vENTRY, alphalist->entryField, KEY_TAB, completeWordCB, alphalist);
/* Set up the post-process function for the entry field. */
setCDKEntryPreProcess (alphalist->entryField, preProcessEntryField, alphalist);
/* Create the scrolling list. */
alphalist->scrollField = newCDKScroll (cdkscreen,
getbegx(alphalist->win),
getbegy(alphalist->win) + (alphalist->entryField)->titleLines + 2,
RIGHT,
boxHeight-((alphalist->entryField)->titleLines + 2),
boxWidth,
0, list, listSize,
NONUMBERS, A_REVERSE,
Box, FALSE);
setCDKScrollULChar (alphalist->scrollField, ACS_LTEE);
setCDKScrollURChar (alphalist->scrollField, ACS_RTEE);
/* Register this baby. */
registerCDKObject (cdkscreen, vALPHALIST, alphalist);
/* Return the file selector pointer. */
return (alphalist);
}
/*
* This erases the file selector from the screen.
*/
static void _eraseCDKAlphalist (CDKOBJS *obj)
{
CDKALPHALIST *alphalist = (CDKALPHALIST *)obj;
eraseCDKScroll (alphalist->scrollField);
eraseCDKEntry (alphalist->entryField);
eraseCursesWindow (alphalist->win);
}
/*
* This moves the alphalist field to the given location.
*/
static void _moveCDKAlphalist (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag)
{
CDKALPHALIST *alphalist = (CDKALPHALIST *)object;
/*
* If this is a relative move, then we will adjust where we want
* to move to.
*/
if (relative)
{
xplace += getbegx(alphalist->win);
yplace += getbegy(alphalist->win);
}
/* Adjust the window if we need to. */
alignxy (WindowOf(alphalist), &xplace, &yplace, alphalist->boxWidth, alphalist->boxHeight);
/* Move the window to the new location. */
moveCursesWindow(alphalist->win, xplace, yplace);
/* Move the sub-widgets. */
/* XXXX */
moveCDKEntry (alphalist->entryField, xplace, yplace, relative, FALSE);
moveCDKScroll (alphalist->scrollField, xplace, yplace, relative, FALSE);
/* Redraw the window, if they asked for it. */
if (refresh_flag)
{
drawCDKAlphalist (alphalist, ObjOf(alphalist)->box);
}
}
/*
* This draws the file selector widget.
*/
static void _drawCDKAlphalist (CDKOBJS *obj, boolean Box GCC_UNUSED)
{
CDKALPHALIST * alphalist = (CDKALPHALIST *)obj;
/* Draw in the entry field. */
drawCDKEntry (alphalist->entryField, ObjOf(alphalist->entryField)->box);
/* Draw in the scroll field. */
drawCDKScroll (alphalist->scrollField, ObjOf(alphalist->scrollField)->box);
}
/*
* This activates the file selector.
*/
char *activateCDKAlphalist (CDKALPHALIST *alphalist, chtype *actions)
{
char *ret = 0;
/* Draw the widget. */
drawCDKAlphalist (alphalist, ObjOf(alphalist)->box);
/* Activate the widget. */
ret = activateCDKEntry (alphalist->entryField, actions);
/* Copy the exit type from the entry field. */
alphalist->exitType = alphalist->entryField->exitType;
/* Determine the exit status. */
if (alphalist->exitType != vEARLY_EXIT)
{
return ret;
}
return 0;
}
/*
* This injects a single character into the alphalist.
*/
char *injectCDKAlphalist (CDKALPHALIST *alphalist, chtype input)
{
char *ret = 0;
/* Draw the widget. */
drawCDKAlphalist (alphalist, ObjOf(alphalist)->box);
/* Inject a character into the widget. */
ret = injectCDKEntry (alphalist->entryField, input);
/* Copy the exit type from the entry field. */
alphalist->exitType = alphalist->entryField->exitType;
/* Determine the exit status. */
if (alphalist->exitType != vEARLY_EXIT)
{
return ret;
}
return 0;
}
/*
* This sets multiple attributes of the widget.
*/
void setCDKAlphalist (CDKALPHALIST *alphalist, char *list[], int listSize, chtype fillerChar, chtype highlight, boolean Box)
{
setCDKAlphalistContents (alphalist, list, listSize);
setCDKAlphalistFillerChar (alphalist, fillerChar);
setCDKAlphalistHighlight (alphalist, highlight);
setCDKAlphalistBox (alphalist, Box);
}
/*
* This function sets the information inside the file selector.
*/
void setCDKAlphalistContents (CDKALPHALIST *alphalist, char *list[], int listSize)
{
/* Declare local variables. */
CDKSCROLL *scrollp = (CDKSCROLL *)alphalist->scrollField;
CDKENTRY *entry = (CDKENTRY *)alphalist->entryField;
int x;
freeCharList (alphalist->list, alphalist->listSize);
/* We need to sort the list before we use it. */
quickSort (list, 0, listSize-1);
/* Copy in the new information. */
alphalist->listSize = listSize;
for (x=0; x < listSize; x++)
{
alphalist->list[x] = copyChar (list[x]);
}
/* Set the information in the scrolling list. */
setCDKScroll (scrollp, list, listSize, NONUMBERS, scrollp->highlight, ObjOf(scrollp)->box);
/* Clean out the entry field. */
cleanCDKEntry (entry);
/* Redraw the alphalist. */
eraseCDKAlphalist (alphalist);
drawCDKAlphalist (alphalist, ObjOf(alphalist)->box);
}
/*
* This returns the contents of the alphalist.
*/
char **getCDKAlphalistContents (CDKALPHALIST *alphalist, int *size)
{
(*size) = alphalist->listSize;
return alphalist->list;
}
/*
* This sets the filler character of the entry field of the alphalist.
*/
void setCDKAlphalistFillerChar (CDKALPHALIST *alphalist, chtype fillerCharacter)
{
CDKENTRY *entry = (CDKENTRY *)alphalist->entryField;
alphalist->fillerChar = fillerCharacter;
setCDKEntryFillerChar (entry, fillerCharacter);
}
chtype getCDKAlphalistFillerChar (CDKALPHALIST *alphalist)
{
return alphalist->fillerChar;
}
/*
* This sets the highlight bar attributes.
*/
void setCDKAlphalistHighlight (CDKALPHALIST *alphalist, chtype highlight)
{
alphalist->highlight = highlight;
}
chtype getCDKAlphalistHighlight (CDKALPHALIST *alphalist)
{
return alphalist->highlight;
}
/*
* This sets whether or not the widget will be drawn with a box.
*/
void setCDKAlphalistBox (CDKALPHALIST *alphalist, boolean Box)
{
ObjOf(alphalist)->box = Box;
}
boolean getCDKAlphalistBox (CDKALPHALIST *alphalist)
{
return ObjOf(alphalist)->box;
}
/*
* These functions set the drawing characters of the widget.
*/
void setCDKAlphalistULChar (CDKALPHALIST *alphalist, chtype character)
{
setCDKEntryULChar (alphalist->entryField, character);
}
void setCDKAlphalistURChar (CDKALPHALIST *alphalist, chtype character)
{
setCDKEntryURChar (alphalist->entryField, character);
}
void setCDKAlphalistLLChar (CDKALPHALIST *alphalist, chtype character)
{
setCDKScrollLLChar (alphalist->scrollField, character);
}
void setCDKAlphalistLRChar (CDKALPHALIST *alphalist, chtype character)
{
setCDKScrollLRChar (alphalist->scrollField, character);
}
void setCDKAlphalistVerticalChar (CDKALPHALIST *alphalist, chtype character)
{
setCDKEntryVerticalChar (alphalist->entryField, character);
setCDKScrollVerticalChar (alphalist->scrollField, character);
}
void setCDKAlphalistHorizontalChar (CDKALPHALIST *alphalist, chtype character)
{
setCDKEntryHorizontalChar (alphalist->entryField, character);
setCDKScrollHorizontalChar (alphalist->scrollField, character);
}
void setCDKAlphalistBoxAttribute (CDKALPHALIST *alphalist, chtype character)
{
setCDKEntryBoxAttribute (alphalist->entryField, character);
setCDKScrollBoxAttribute (alphalist->scrollField, character);
}
/*
* This sets the background color of the widget.
*/
void setCDKAlphalistBackgroundColor (CDKALPHALIST *alphalist, char *color)
{
if (color != 0)
{
setCDKEntryBackgroundColor (alphalist->entryField, color);
setCDKScrollBackgroundColor (alphalist->scrollField, color);
}
}
/*
* This destroys the file selector.
*/
void destroyCDKAlphalist (CDKALPHALIST *alphalist)
{
/* Erase the file selector. */
eraseCDKAlphalist (alphalist);
freeCharList (alphalist->list, alphalist->listSize);
/* Destroy the other Cdk objects. */
destroyCDKEntry (alphalist->entryField);
destroyCDKScroll (alphalist->scrollField);
/* Free up the window pointers. */
deleteCursesWindow (alphalist->win);
/* Unregister the object. */
unregisterCDKObject (vALPHALIST, alphalist);
/* Free up the object pointer. */
free (alphalist);
}
/*
* This function sets the pre-process function.
*/
void setCDKAlphalistPreProcess (CDKALPHALIST *alphalist, PROCESSFN callback, void *data)
{
setCDKEntryPreProcess (alphalist->entryField, callback, data);
}
/*
* This function sets the post-process function.
*/
void setCDKAlphalistPostProcess (CDKALPHALIST *alphalist, PROCESSFN callback, void *data)
{
setCDKEntryPostProcess (alphalist->entryField, callback, data);
}
/*
* Start of callback functions.
*/
static void adjustAlphalistCB (EObjectType objectType GCC_UNUSED, void *object GCC_UNUSED, void *clientData, chtype key)
{
CDKALPHALIST *alphalist = (CDKALPHALIST *)clientData;
CDKSCROLL *scrollp = (CDKSCROLL*)alphalist->scrollField;
CDKENTRY *entry = (CDKENTRY*)alphalist->entryField;
char *current = 0;
/* Adjust the scrolling list. */
injectCDKScroll (alphalist->scrollField, (chtype)key);
/* Set the value in the entry field. */
current = chtype2Char (scrollp->item[scrollp->currentItem]);
setCDKEntryValue (entry, current);
drawCDKEntry (entry, ObjOf(entry)->box);
freeChar (current);
}
/*
* This is the heart-beat of the widget.
*/
static int preProcessEntryField (EObjectType cdktype GCC_UNUSED, void *object GCC_UNUSED, void *clientData, chtype input)
{
CDKALPHALIST *alphalist = (CDKALPHALIST *)clientData;
CDKSCROLL *scrollp = alphalist->scrollField;
CDKENTRY *entry = alphalist->entryField;
int infoLen = 0;
int Index;
char pattern[5000];
infoLen = (int)strlen (entry->info);
/* Check the input. */
if (isalnum (input) || ispunct (input) ||
input == DELETE || input == CONTROL('H') || input == KEY_DC)
{
/* Copy the information from the entry field. */
strcpy (pattern, entry->info);
/* Truncate/Concatenate to the information in the entry field. */
if (input == DELETE || input == CONTROL('H') || input == KEY_DC)
{
/* If we had only 1 item in the list; jump back to the top. */
if (infoLen <= 1)
{
setCDKScrollPosition (scrollp, 0);
drawCDKScroll (scrollp, ObjOf(scrollp)->box);
return 1;
}
pattern[infoLen - 1] = '\0';
}
else
{
pattern[infoLen] = (char)input;
pattern[infoLen + 1] = '\0';
}
/* Look for the pattern in the list. */
Index = searchList (alphalist->list, alphalist->listSize, pattern);
if (Index >= 0)
{
setCDKScrollPosition (scrollp, Index);
drawCDKScroll (scrollp, ObjOf(scrollp)->box);
}
else
{
Beep();
return 0;
}
}
return 1;
}
/*
* This tries to complete the word in the entry field.
*/
static void completeWordCB (EObjectType objectType GCC_UNUSED, void *object GCC_UNUSED, void *clientData, chtype key GCC_UNUSED)
{
CDKALPHALIST *alphalist = (CDKALPHALIST *)clientData;
CDKENTRY *entry = (CDKENTRY*)alphalist->entryField;
CDKSCROLL *scrollp = 0;
int currentIndex = 0;
int wordLength = 0;
int selected = -1;
int altCount = 0;
int height = 0;
int match = 0;
int Index = 0;
int ret = 0;
int x = 0;
char *altWords[MAX_LINES];
if (entry->info == 0)
{
Beep();
return;
}
wordLength = (int)strlen (entry->info);
/* If the word length is equal to zero, just leave. */
if (wordLength == 0)
{
Beep();
return;
}
/* Look for a unique word match. */
Index = searchList (alphalist->list, alphalist->listSize, entry->info);
/* If the index is less than zero, return we didn't find a match. */
if (Index < 0)
{
Beep();
return;
}
/* Did we find the last word in the list? */
if (Index == alphalist->listSize-1)
{
setCDKEntryValue (entry, alphalist->list[Index]);
drawCDKEntry (entry, ObjOf(entry)->box);
return;
}
/* Ok, we found a match, is the next item similar? */
ret = strncmp (alphalist->list[Index + 1], entry->info, wordLength);
if (ret == 0)
{
currentIndex = Index;
altCount = 0;
height = 0;
match = 0;
selected = -1;
/* Start looking for alternate words. */
while ((currentIndex < alphalist->listSize)
&& (strncmp (alphalist->list[currentIndex], entry->info, wordLength) == 0))
{
altWords[altCount] = copyChar (alphalist->list[currentIndex]);
currentIndex++;
altCount++;
}
/* Determine the height of the scrolling list. */
height = MINIMUM (altCount + 3, 11);
/* Create a scrolling list of close matches. */
scrollp = newCDKScroll (entry->obj.screen, CENTER, CENTER, RIGHT, height, -30,
"<C></B/5>Possible Matches.",
altWords, altCount, NUMBERS,
A_REVERSE, TRUE, FALSE);
/* Allow them to select a close match. */
match = activateCDKScroll (scrollp, 0);
selected = scrollp->currentItem;
/* Check how they exited the list. */
if (scrollp->exitType == vESCAPE_HIT)
{
/* Beep at the user. */
Beep();
/* Destroy the scrolling list. */
destroyCDKScroll (scrollp);
}
else
{
/* Destroy the scrolling list. */
destroyCDKScroll (scrollp);
/* Set the entry field to the selected value. */
setCDKEntryValue (entry, altWords[match]);
/* Move the highlight bar down to the selected value. */
for (x=0; x < selected; x++)
{
injectCDKScroll (alphalist->scrollField, KEY_DOWN);
}
}
/* Clean up. */
freeCharList (altWords, altCount);
/* Redraw the alphalist. */
drawCDKAlphalist (alphalist, ObjOf(alphalist)->box);
}
else
{
/* Set the entry field with the found item. */
setCDKEntryValue (entry, alphalist->list[Index]);
drawCDKEntry (entry, ObjOf(entry)->box);
}
}