#include "cdk.h" /* * Declare file local prototypes. */ static void drawCDKRadioList (CDKRADIO *radio, boolean Box); 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) - 1; int parentHeight = getmaxy(cdkscreen->window) - 1; int boxWidth = width; int boxHeight = height; int maxWidth = INT_MIN; int xpos = xplace; int ypos = yplace; int widestItem = 0; int x = 0; char **temp = 0; int len, 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, 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, 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; } } /* Set the rest of the variables. */ radio->titleAdj = radio->titleLines + 1; radio->listSize = listSize; radio->viewSize = boxHeight - (2 + radio->titleLines); radio->lastItem = listSize - 1; radio->maxTopItem = listSize - radio->viewSize; /* Is the view size smaller then the window??? */ if (listSize < (boxHeight-1-radio->titleAdj)) { radio->viewSize = listSize; radio->listSize = listSize; radio->lastItem = listSize; radio->maxTopItem = -1; } /* Adjust the box width if there is a scroll bar. */ if (splace == LEFT || splace == RIGHT) { boxWidth++; radio->scrollbar = TRUE; } else { radio->scrollbar = FALSE; } /* * Make sure we didn't extend beyond the dimensions of the window. */ boxWidth = (boxWidth > parentWidth ? parentWidth : boxWidth); boxHeight = (boxHeight > parentHeight ? parentHeight : boxHeight); /* Determine the size of the scrollbar toggle and the step. */ radio->step = (float)(boxHeight-2) / (float)radio->listSize; radio->toggleSize = (radio->listSize > (boxHeight-2) ? 1 : ceilCDK(radio->step)); /* Each item in the needs to be converted to chtype * */ for (x=0; x < listSize; x++) { radio->item[x] = char2Chtype (list[x], &radio->itemLen[x], &radio->itemPos[x]); radio->itemPos[x] = justifyString (boxWidth, 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. */ if (boxWidth > widestItem) { radio->maxLeftChar = 0; } else { radio->maxLeftChar = widestItem-(boxWidth-2) + 3; } /* 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, boxWidth, ypos, xpos); /* Is the window null??? */ if (radio->win == 0) { /* Clean up memory. */ for (x=0; x < listSize; x++) { freeChtype (radio->item[x]); } for (x=0; x < radio->titleLines; x++) { freeChtype (radio->title[x]); } free (radio); /* Return a null pointer. */ return (0); } /* Turn on the keypad. */ keypad (radio->win, TRUE); /* Create the scrollbar window. */ if (splace == RIGHT) { radio->scrollbarWin = subwin (radio->win, boxHeight-radio->titleAdj-1, 1, ypos + radio->titleAdj, xpos + boxWidth-2); } else if (splace == LEFT) { radio->scrollbarWin = subwin (radio->win, boxHeight-radio->titleAdj-1, 1, ypos + radio->titleAdj, xpos + 1); } else { radio->scrollbarWin = 0; } /* Set the rest of the variables */ ScreenOf(radio) = cdkscreen; radio->parent = cdkscreen->window; radio->boxHeight = boxHeight; radio->boxWidth = boxWidth; radio->scrollbarPlacement = splace; radio->widestItem = widestItem; radio->currentTop = 0; radio->currentItem = 0; radio->currentHigh = 0; radio->leftChar = 0; radio->selectedItem = 0; radio->highlight = highlight; radio->choiceChar = choiceChar; radio->leftBoxChar = (chtype)'['; radio->rightBoxChar = (chtype)']'; radio->defItem = defItem; radio->exitType = vNEVER_ACTIVATED; ObjOf(radio)->box = Box; radio->shadow = shadow; radio->preProcessFunction = 0; radio->preProcessData = 0; radio->postProcessFunction = 0; radio->postProcessData = 0; radio->shadowWin = 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; /* Do we need to create the shadow??? */ if (shadow) { radio->shadowWin = newwin (boxHeight, boxWidth + 1, ypos + 1, xpos + 1); } /* 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. */ 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, ObjOf(radio)->box); /* Check if there is a pre-process function to be called. */ if (radio->preProcessFunction != 0) { /* Call the pre-process function. */ ppReturn = 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) { radio->exitType = vESCAPE_HIT; return -1; } else { switch (input) { case KEY_UP : if (radio->currentHigh == 0) { if (radio->currentTop != 0) { radio->currentTop--; radio->currentItem--; } else { Beep(); } } else { radio->currentItem--; radio->currentHigh--; } break; case KEY_DOWN : if (radio->currentHigh == radio->viewSize - 1) { /* We need to scroll down one line. */ if (radio->currentTop < radio->maxTopItem) { radio->currentTop++; radio->currentItem++; } else { Beep(); } } else { radio->currentItem++; radio->currentHigh++; } break; case KEY_RIGHT : if (radio->leftChar >= radio->maxLeftChar) { Beep(); } else { radio->leftChar ++; } break; case KEY_LEFT : if (radio->leftChar == 0) { Beep(); } else { radio->leftChar --; } break; case KEY_PPAGE : case CONTROL('B') : if (radio->currentTop > 0) { if (radio->currentTop >= (radio->viewSize -1)) { radio->currentTop -= (radio->viewSize - 1); radio->currentItem -= (radio->viewSize - 1); } else { radio->currentTop = 0; radio->currentItem = 0; radio->currentHigh = 0; } } else { Beep(); } break; case KEY_NPAGE : case CONTROL('F') : if (radio->currentTop < radio->maxTopItem) { if ((radio->currentTop + radio->viewSize - 1) <= radio->maxTopItem) { radio->currentTop += (radio->viewSize - 1); radio->currentItem += (radio->viewSize - 1); } else { radio->currentTop = radio->maxTopItem; radio->currentItem = radio->lastItem; radio->currentHigh = radio->viewSize-1; } } else { Beep(); } break; case 'g' : case '1' : radio->currentTop = 0; radio->currentItem = 0; radio->currentHigh = 0; break; case 'G' : radio->currentTop = radio->maxTopItem; radio->currentItem = radio->lastItem; radio->currentHigh = radio->viewSize-1; break; case '$' : radio->leftChar = radio->maxLeftChar; break; case '|' : radio->leftChar = 0; break; case SPACE : radio->selectedItem = radio->currentItem; break; case KEY_NEXT : case KEY_ESC : radio->exitType = vESCAPE_HIT; return -1; case KEY_RETURN : case KEY_TAB : case KEY_ENTER : radio->exitType = vNORMAL; return radio->selectedItem; case CDK_REFRESH : eraseCDKScreen (ScreenOf(radio)); refreshCDKScreen (ScreenOf(radio)); break; default : break; } } /* Should we call a post-process? */ if (radio->postProcessFunction != 0) { radio->postProcessFunction (vRADIO, radio, radio->postProcessData, input); } } /* Draw the radio list */ drawCDKRadioList (radio, ObjOf(radio)->box); /* 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; /* Declare local variables. */ int currentX = getbegx(radio->win); int currentY = getbegy(radio->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(radio->win) + xplace; ypos = getbegy(radio->win) + yplace; } /* Adjust the window if we need to. */ alignxy (WindowOf(radio), &xpos, &ypos, radio->boxWidth, radio->boxHeight); /* Get the difference. */ xdiff = currentX - xpos; ydiff = currentY - ypos; /* Move the window to the new location. */ moveCursesWindow(radio->win, -xdiff, -ydiff); /* If there is a scrollbar we have to move it too. */ if (radio->scrollbar) { moveCursesWindow(radio->scrollbarWin, -xdiff, -ydiff); } /* If there is a shadow box we have to move it too. */ if (radio->shadowWin != 0) { moveCursesWindow(radio->shadowWin, -xdiff, -ydiff); } /* Touch the windows so they 'move'. */ touchwin (WindowOf(radio)); wrefresh (WindowOf(radio)); /* 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; /* Do we need to draw in the shadow??? */ if (radio->shadowWin != 0) { drawShadow (radio->shadowWin); } /* Draw in the title if there is one */ if (radio->titleLines != 0) { for (x=0; x < radio->titleLines; x++) { writeChtype (radio->win, radio->titlePos[x], x + 1, radio->title[x], HORIZONTAL, 0, radio->titleLen[x]); } } /* Draw in the radio list. */ drawCDKRadioList (radio, ObjOf(radio)->box); } /* * This redraws the radio list. */ static void drawCDKRadioList (CDKRADIO *radio, boolean Box) { /* Declare local variables. */ int scrollbarAdj = 0; int screenPos = 0; char emptyString[1000]; int x; /* * If the scroll bar is on the left hand side, then adjust * everything over to the right one character. */ if (radio->scrollbarPlacement == LEFT) { scrollbarAdj = 1; } /* Create a string full of spaces. */ cleanChar (emptyString, radio->boxWidth-1, ' '); /* Redraw the list */ for (x=0; x < radio->viewSize; x++) { screenPos = radio->itemPos[x + radio->currentTop]-radio->leftChar + scrollbarAdj; /* Draw in the empty string. */ writeChar (radio->win, 1, radio->titleAdj + x, emptyString, HORIZONTAL, 0, (int)strlen(emptyString)); /* Draw in the line. */ if (screenPos >= 0) { writeChtype (radio->win, screenPos, x + radio->titleAdj, radio->item[x + radio->currentTop], HORIZONTAL, 0, radio->itemLen[x + radio->currentTop]); } else { writeChtype (radio->win, 1, x + radio->titleAdj, radio->item[x + radio->currentTop], HORIZONTAL, radio->leftChar - radio->itemPos[x + radio->currentTop] + 1, radio->itemLen[x + radio->currentTop]); } /* Draw in the selected choice... */ if (x + radio->currentTop == radio->selectedItem) { mvwaddch (radio->win, x + radio->titleAdj, 1 + scrollbarAdj, radio->leftBoxChar); mvwaddch (radio->win, x + radio->titleAdj, 2 + scrollbarAdj, radio->choiceChar); mvwaddch (radio->win, x + radio->titleAdj, 3 + scrollbarAdj, radio->rightBoxChar); } else { mvwaddch (radio->win, x + radio->titleAdj, 1 + scrollbarAdj, radio->leftBoxChar); mvwaddch (radio->win, x + radio->titleAdj, 2 + scrollbarAdj, ' '); mvwaddch (radio->win, x + radio->titleAdj, 3 + scrollbarAdj, radio->rightBoxChar); } } screenPos = radio->itemPos[radio->currentItem]-radio->leftChar + scrollbarAdj; /* Draw in the filler character for the scroll bar. */ if (radio->scrollbarWin != 0) { for (x=0; x < radio->boxHeight-1; x++) { mvwaddch (radio->scrollbarWin, x, 0, ACS_CKBOARD); } } /* Highlight the current item. */ if (screenPos >= 0) { writeChtypeAttrib (radio->win, screenPos, radio->currentHigh + radio->titleAdj, radio->item[radio->currentItem], radio->highlight, HORIZONTAL, 0, radio->itemLen[radio->currentItem]); } else { writeChtypeAttrib (radio->win, 1 + scrollbarAdj, radio->currentHigh + radio->titleAdj, radio->item[radio->currentItem], radio->highlight, HORIZONTAL, radio->leftChar - radio->itemPos[radio->currentTop] + 1, radio->itemLen[radio->currentItem]); } /* Draw in the selected choice... */ if (radio->currentItem == radio->selectedItem) { mvwaddch (radio->win, radio->currentHigh + radio->titleAdj, 1 + scrollbarAdj, radio->leftBoxChar); mvwaddch (radio->win, radio->currentHigh + radio->titleAdj, 2 + scrollbarAdj, radio->choiceChar); mvwaddch (radio->win, radio->currentHigh + radio->titleAdj, 3 + scrollbarAdj, radio->rightBoxChar); } else { mvwaddch (radio->win, radio->currentHigh + radio->titleAdj, 1 + scrollbarAdj, radio->leftBoxChar); mvwaddch (radio->win, radio->currentHigh + radio->titleAdj, 2 + scrollbarAdj, ' '); mvwaddch (radio->win, radio->currentHigh + radio->titleAdj, 3 + scrollbarAdj, radio->rightBoxChar); } /* Determine where the toggle is supposed to be. */ if (radio->scrollbar) { if (radio->listSize > radio->boxHeight-2) { radio->togglePos = floorCDK((float)radio->currentItem * (float)radio->step); } else { radio->togglePos = ceilCDK((float)radio->currentItem * (float)radio->step); } /* Make sure the toggle button doesn't go out of bounds. */ scrollbarAdj = (radio->togglePos + radio->toggleSize)-(radio->boxHeight-radio->titleAdj-1); if (scrollbarAdj > 0) { radio->togglePos -= scrollbarAdj; } /* Draw the scrollbar. */ for (x=radio->togglePos; x < radio->togglePos + radio->toggleSize; x++) { mvwaddch (radio->scrollbarWin, x, 0, ' ' | A_REVERSE); } touchwin (radio->scrollbarWin); wrefresh (radio->scrollbarWin); } /* Box it if needed. */ if (Box) { attrbox (radio->win, radio->ULChar, radio->URChar, radio->LLChar, radio->LRChar, radio->HChar, radio->VChar, radio->BoxAttrib); } /* Refresh the window. */ touchwin (radio->win); wrefresh (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->scrollbarWin != 0) { wbkgd (radio->scrollbarWin, holder[0]); } /* Clean up. */ freeChtype (holder); } /* * This function destroys the radio widget. */ void destroyCDKRadio (CDKRADIO *radio) { /* Declare local variables. */ int x = 0; /* 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->scrollbarWin); deleteCursesWindow (radio->shadowWin); 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); eraseCursesWindow (radio->shadowWin); } /* * This set various attributes of the radio list. */ void setCDKRadio (CDKRADIO *radio, chtype highlight, chtype choiceChar, int Box) { setCDKRadioHighlight (radio, highlight); setCDKRadioChoiceCharacter (radio, choiceChar); setCDKRadioBox (radio, Box); } /* * This sets the radio list items. */ void setCDKRadioItems (CDKRADIO *radio, char **list, int listSize) { /* Declare some wars. */ char emptyString[2000]; int widestItem = -1; int x = 0; /* Clean out the old list. */ for (x=0; x < radio->listSize; x++) { freeChtype (radio->item[x]); radio->itemLen[x] = 0; radio->itemPos[x] = 0; } /* Clean up the display. */ cleanChar (emptyString, radio->boxWidth-1, ' '); for (x=0; x < radio->viewSize ; x++) { writeChar (radio->win, 1, radio->titleAdj + x, emptyString, HORIZONTAL, 0, (int)strlen(emptyString)); } /* Readjust all of the variables ... */ radio->listSize = listSize; radio->viewSize = radio->boxHeight - (2 + radio->titleLines); radio->lastItem = listSize - 1; radio->maxTopItem = listSize - radio->viewSize; /* Is the view size smaller then the window? */ if (listSize < (radio->boxHeight-1-radio->titleAdj)) { radio->viewSize = listSize; radio->listSize = listSize; radio->lastItem = listSize; radio->maxTopItem = -1; } /* Set some vars. */ radio->currentTop = 0; radio->currentItem = 0; radio->currentHigh = 0; radio->leftChar = 0; radio->selectedItem = 0; /* Set the information for the radio bar. */ radio->step = (float)(radio->boxHeight-2) / (float)radio->listSize; radio->toggleSize = (radio->listSize > (radio->boxHeight-2) ? 1 : ceilCDK(radio->step)); /* Each item in the needs to be converted to chtype * */ for (x=0; x < listSize; x++) { radio->item[x] = char2Chtype (list[x], &radio->itemLen[x], &radio->itemPos[x]); radio->itemPos[x] = justifyString (radio->boxWidth, 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. */ if (radio->boxWidth > widestItem) { radio->maxLeftChar = 0; } else { radio->maxLeftChar = widestItem-(radio->boxWidth-2) + 3; } } 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; }