#include #include /* * $Author: tom $ * $Date: 2016/11/20 19:24:26 $ * $Revision: 1.161 $ */ /* * Declare file local prototypes. */ static void drawCDKScrollList (CDKSCROLL *scrollp, boolean Box); static int createCDKScrollItemList (CDKSCROLL *scrollp, boolean numbers, CDK_CSTRING2 list, int listSize); static void fixCursorPosition (CDKSCROLL *widget); static void setViewSize (CDKSCROLL *scrollp, int listSize); static int maxViewSize (CDKSCROLL *scrollp); #define NUMBER_FMT "%4d. %s" #define NUMBER_LEN(s) (8 + strlen (s)) /* Determine how many characters we can shift to the right */ /* before all the items have been scrolled off the screen. */ #define AvailableWidth(w) ((w)->boxWidth - 2 * BorderOf (w)) #define updateViewWidth(w, widest) \ (w)->maxLeftChar = (((w)->boxWidth > widest) \ ? 0 \ : (widest - AvailableWidth (w))) #define WidestItem(w) ((w)->maxLeftChar + AvailableWidth (w)) #define SCREENPOS(w,n) (w)->itemPos[n] - (w)->leftChar /* + scrollbarAdj + BorderOf(w) */ DeclareCDKObjects (SCROLL, Scroll, setCdk, Int); /* * This function creates a new scrolling list widget. */ CDKSCROLL *newCDKScroll (CDKSCREEN *cdkscreen, int xplace, int yplace, int splace, int height, int width, const char *title, CDK_CSTRING2 list, int listSize, boolean numbers, chtype highlight, boolean Box, boolean shadow) { /* *INDENT-EQLS* */ CDKSCROLL *scrollp = 0; int parentWidth = getmaxx (cdkscreen->window); int parentHeight = getmaxy (cdkscreen->window); int boxWidth; int boxHeight; int xpos = xplace; int ypos = yplace; int scrollAdjust = 0; int x; /* *INDENT-OFF* */ static const struct { int from; int to; } bindings[] = { { CDK_BACKCHAR, KEY_PPAGE }, { CDK_FORCHAR, KEY_NPAGE }, { 'g', KEY_HOME }, { '1', KEY_HOME }, { 'G', KEY_END }, { '<', KEY_HOME }, { '>', KEY_END }, }; /* *INDENT-ON* */ if ((scrollp = newCDKObject (CDKSCROLL, &my_funcs)) == 0) { destroyCDKObject (scrollp); return (0); } setCDKScrollBox (scrollp, Box); /* * 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); boxWidth = setCdkTitle (ObjOf (scrollp), title, boxWidth); /* Set the box height. */ if (TitleLinesOf (scrollp) > boxHeight) { boxHeight = (TitleLinesOf (scrollp) + MINIMUM (listSize, 8) + 2 * BorderOf (scrollp)); } /* Adjust the box width if there is a scrollp bar. */ if ((splace == LEFT) || (splace == RIGHT)) { scrollp->scrollbar = TRUE; boxWidth += 1; } else { scrollp->scrollbar = FALSE; } /* * Make sure we didn't extend beyond the dimensions of the window. */ scrollp->boxWidth = (boxWidth > parentWidth ? (parentWidth - scrollAdjust) : boxWidth); scrollp->boxHeight = (boxHeight > parentHeight ? parentHeight : boxHeight); setViewSize (scrollp, listSize); /* Rejustify the x and y positions if we need to. */ alignxy (cdkscreen->window, &xpos, &ypos, scrollp->boxWidth, scrollp->boxHeight); /* Make the scrolling window */ scrollp->win = newwin (scrollp->boxHeight, scrollp->boxWidth, ypos, xpos); /* Is the scrolling window null?? */ if (scrollp->win == 0) { destroyCDKObject (scrollp); return (0); } /* Turn the keypad on for the window. */ keypad (scrollp->win, TRUE); /* Create the scrollbar window. */ if (splace == RIGHT) { scrollp->scrollbarWin = subwin (scrollp->win, maxViewSize (scrollp), 1, SCREEN_YPOS (scrollp, ypos), xpos + scrollp->boxWidth - BorderOf (scrollp) - 1); } else if (splace == LEFT) { scrollp->scrollbarWin = subwin (scrollp->win, maxViewSize (scrollp), 1, SCREEN_YPOS (scrollp, ypos), SCREEN_XPOS (scrollp, xpos)); } else { scrollp->scrollbarWin = 0; } /* create the list window */ scrollp->listWin = subwin (scrollp->win, maxViewSize (scrollp), scrollp->boxWidth - 2 * BorderOf (scrollp) - scrollAdjust, SCREEN_YPOS (scrollp, ypos), SCREEN_XPOS (scrollp, xpos) + (splace == LEFT ? 1 : 0)); /* *INDENT-EQLS* Set the rest of the variables */ ScreenOf (scrollp) = cdkscreen; scrollp->parent = cdkscreen->window; scrollp->shadowWin = 0; scrollp->scrollbarPlacement = splace; scrollp->maxLeftChar = 0; scrollp->leftChar = 0; scrollp->highlight = highlight; initExitType (scrollp); ObjOf (scrollp)->acceptsFocus = TRUE; ObjOf (scrollp)->inputWindow = scrollp->win; scrollp->shadow = shadow; setCDKScrollPosition (scrollp, 0); /* Create the scrolling list item list and needed variables. */ if (createCDKScrollItemList (scrollp, numbers, list, listSize) <= 0) { destroyCDKObject (scrollp); return (0); } /* Do we need to create a shadow? */ if (shadow) { scrollp->shadowWin = newwin (scrollp->boxHeight, boxWidth, ypos + 1, xpos + 1); } /* Setup the key bindings. */ for (x = 0; x < (int)SIZEOF (bindings); ++x) bindCDKObject (vSCROLL, scrollp, (chtype)bindings[x].from, getcCDKBind, (void *)(long)bindings[x].to); registerCDKObject (cdkscreen, vSCROLL, scrollp); /* Return the scrolling list */ return scrollp; } /* * Put the cursor on the currently-selected item's row. */ static void fixCursorPosition (CDKSCROLL *widget) { scroller_FixCursorPosition ((CDKSCROLLER *)widget); } /* * This actually does all the 'real' work of managing the scrolling list. */ int activateCDKScroll (CDKSCROLL *scrollp, chtype *actions) { /* Draw the scrolling list */ drawCDKScroll (scrollp, ObjOf (scrollp)->box); if (actions == 0) { chtype input; boolean functionKey; for (;;) { int ret; fixCursorPosition (scrollp); input = (chtype)getchCDKObject (ObjOf (scrollp), &functionKey); /* Inject the character into the widget. */ ret = injectCDKScroll (scrollp, input); if (scrollp->exitType != vEARLY_EXIT) { return ret; } } } else { int length = chlen (actions); int i = 0; /* Inject each character one at a time. */ for (i = 0; i < length; i++) { int ret = injectCDKScroll (scrollp, actions[i]); if (scrollp->exitType != vEARLY_EXIT) return ret; } } /* Set the exit type for the widget and return. */ setExitType (scrollp, 0); return -1; } /* * This injects a single character into the widget. */ static int _injectCDKScroll (CDKOBJS *object, chtype input) { CDKSCROLL *myself = (CDKSCROLL *)object; CDKSCROLLER *widget = (CDKSCROLLER *)object; int ppReturn = 1; int ret = unknownInt; bool complete = FALSE; /* Set the exit type for the widget. */ setExitType (widget, 0); /* Draw the scrolling list */ drawCDKScrollList (myself, ObjOf (widget)->box); /* Check if there is a pre-process function to be called. */ if (PreProcessFuncOf (widget) != 0) { /* Call the pre-process function. */ ppReturn = PreProcessFuncOf (widget) (vSCROLL, widget, PreProcessDataOf (widget), input); } /* Should we continue? */ if (ppReturn != 0) { /* Check for a predefined key binding. */ if (checkCDKObjectBind (vSCROLL, widget, input) != 0) { checkEarlyExit (widget); complete = TRUE; } else { switch (input) { case KEY_UP: scroller_KEY_UP (widget); break; case KEY_DOWN: scroller_KEY_DOWN (widget); break; case KEY_RIGHT: scroller_KEY_RIGHT (widget); break; case KEY_LEFT: scroller_KEY_LEFT (widget); break; case KEY_PPAGE: scroller_KEY_PPAGE (widget); break; case KEY_NPAGE: scroller_KEY_NPAGE (widget); break; case KEY_HOME: scroller_KEY_HOME (widget); break; case KEY_END: scroller_KEY_END (widget); break; case '$': widget->leftChar = widget->maxLeftChar; break; case '|': widget->leftChar = 0; break; case KEY_ESC: setExitType (widget, input); complete = TRUE; break; case KEY_ERROR: setExitType (widget, input); complete = TRUE; break; case CDK_REFRESH: eraseCDKScreen (ScreenOf (widget)); refreshCDKScreen (ScreenOf (widget)); break; case KEY_TAB: case KEY_ENTER: setExitType (widget, input); ret = widget->currentItem; complete = TRUE; break; default: break; } } /* Should we call a post-process? */ if (!complete && (PostProcessFuncOf (widget) != 0)) { PostProcessFuncOf (widget) (vSCROLL, widget, PostProcessDataOf (widget), input); } } if (!complete) { drawCDKScrollList (myself, ObjOf (widget)->box); setExitType (widget, 0); } fixCursorPosition (myself); ResultOf (widget).valueInt = ret; return (ret != unknownInt); } /* * This allows the user to accelerate to a position in the scrolling list. */ void setCDKScrollPosition (CDKSCROLL *scrollp, int item) { scroller_SetPosition ((CDKSCROLLER *)scrollp, item); } /* obsolete (because the name is inconsistent) */ int getCDKScrollCurrent (CDKSCROLL *scrollp) { return scrollp->currentItem; } void setCDKScrollCurrent (CDKSCROLL *scrollp, int item) { scroller_SetPosition ((CDKSCROLLER *)scrollp, item); } /* * Get/Set the current item number of the scroller. */ int getCDKScrollCurrentItem (CDKSCROLL *widget) { return widget->currentItem; } void setCDKScrollCurrentItem (CDKSCROLL *widget, int item) { scroller_SetPosition ((CDKSCROLLER *)widget, item); } /* * Get/Set the top line of the scroller. */ int getCDKScrollCurrentTop (CDKSCROLL *widget) { return widget->currentTop; } void setCDKScrollCurrentTop (CDKSCROLL *widget, int item) { if (item < 0) item = 0; else if (item > widget->maxTopItem) item = widget->maxTopItem; widget->currentTop = item; scroller_SetPosition ((CDKSCROLLER *)widget, item); } /* * This moves the scroll field to the given location. */ static void _moveCDKScroll (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag) { /* *INDENT-EQLS* */ CDKSCROLL *scrollp = (CDKSCROLL *)object; int currentX = getbegx (scrollp->win); int currentY = getbegy (scrollp->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 (scrollp->win) + xplace; ypos = getbegy (scrollp->win) + yplace; } /* Adjust the window if we need to. */ alignxy (WindowOf (scrollp), &xpos, &ypos, scrollp->boxWidth, scrollp->boxHeight); /* Get the difference. */ xdiff = currentX - xpos; ydiff = currentY - ypos; /* Move the window to the new location. */ moveCursesWindow (scrollp->win, -xdiff, -ydiff); moveCursesWindow (scrollp->listWin, -xdiff, -ydiff); moveCursesWindow (scrollp->shadowWin, -xdiff, -ydiff); moveCursesWindow (scrollp->scrollbarWin, -xdiff, -ydiff); /* Touch the windows so they 'move'. */ refreshCDKWindow (WindowOf (scrollp)); /* Redraw the window, if they asked for it. */ if (refresh_flag) { drawCDKScroll (scrollp, ObjOf (scrollp)->box); } } /* * This function draws the scrolling list widget. */ static void _drawCDKScroll (CDKOBJS *object, boolean Box) { CDKSCROLL *scrollp = (CDKSCROLL *)object; /* Draw in the shadow if we need to. */ if (scrollp->shadowWin != 0) drawShadow (scrollp->shadowWin); drawCdkTitle (scrollp->win, object); /* Draw in the scolling list items. */ drawCDKScrollList (scrollp, Box); } static void drawCDKScrollCurrent (CDKSCROLL *s) { /* Rehighlight the current menu item. */ int screenPos = s->itemPos[s->currentItem] - s->leftChar; chtype highlight = HasFocusObj (s) ? s->highlight : A_NORMAL; writeChtypeAttrib (s->listWin, (screenPos >= 0) ? screenPos : 0, s->currentHigh, s->item[s->currentItem], highlight, HORIZONTAL, (screenPos >= 0) ? 0 : (1 - screenPos), s->itemLen[s->currentItem]); } static int maxViewSize (CDKSCROLL *scrollp) { return scroller_MaxViewSize ((CDKSCROLLER *)scrollp); } /* * Set variables that depend upon the list-size. */ static void setViewSize (CDKSCROLL *scrollp, int listSize) { scroller_SetViewSize ((CDKSCROLLER *)scrollp, listSize); } #undef SCREEN_YPOS /* because listWin is separate */ #define SCREEN_YPOS(w,n) (n) /* * This redraws the scrolling list. */ static void drawCDKScrollList (CDKSCROLL *scrollp, boolean Box) { /* If the list is empty, don't draw anything. */ if (scrollp->listSize > 0) { int j; /* Redraw the list */ for (j = 0; j < scrollp->viewSize; j++) { int k; int xpos = SCREEN_YPOS (scrollp, 0); int ypos = SCREEN_YPOS (scrollp, j); writeBlanks (scrollp->listWin, xpos, ypos, HORIZONTAL, 0, scrollp->boxWidth - 2 * BorderOf (scrollp)); k = j + scrollp->currentTop; /* Draw the elements in the scroll list. */ if (k < scrollp->listSize) { int screenPos = SCREENPOS (scrollp, k); /* Write in the correct line. */ writeChtype (scrollp->listWin, (screenPos >= 0) ? screenPos : 1, ypos, scrollp->item[k], HORIZONTAL, (screenPos >= 0) ? 0 : (1 - screenPos), scrollp->itemLen[k]); } } drawCDKScrollCurrent (scrollp); /* Determine where the toggle is supposed to be. */ if (scrollp->scrollbarWin != 0) { scrollp->togglePos = floorCDK (scrollp->currentItem * (double)scrollp->step); /* Make sure the toggle button doesn't go out of bounds. */ if (scrollp->togglePos >= getmaxy (scrollp->scrollbarWin)) scrollp->togglePos = getmaxy (scrollp->scrollbarWin) - 1; /* Draw the scrollbar. */ (void)mvwvline (scrollp->scrollbarWin, 0, 0, ACS_CKBOARD, getmaxy (scrollp->scrollbarWin)); (void)mvwvline (scrollp->scrollbarWin, scrollp->togglePos, 0, ' ' | A_REVERSE, scrollp->toggleSize); } } /* Box it if needed. */ if (Box) { drawObjBox (scrollp->win, ObjOf (scrollp)); } else { touchwin (scrollp->win); } wrefresh (scrollp->win); } /* * This sets the background attribute of the widget. */ static void _setBKattrScroll (CDKOBJS *object, chtype attrib) { if (object != 0) { CDKSCROLL *widget = (CDKSCROLL *)object; wbkgd (widget->win, attrib); wbkgd (widget->listWin, attrib); if (widget->scrollbarWin != 0) { wbkgd (widget->scrollbarWin, attrib); } } } /* * This function destroys */ static void _destroyCDKScroll (CDKOBJS *object) { if (object != 0) { CDKSCROLL *scrollp = (CDKSCROLL *)object; cleanCdkTitle (object); CDKfreeChtypes (scrollp->item); freeChecked (scrollp->itemPos); freeChecked (scrollp->itemLen); /* Clean up the windows. */ deleteCursesWindow (scrollp->scrollbarWin); deleteCursesWindow (scrollp->shadowWin); deleteCursesWindow (scrollp->listWin); deleteCursesWindow (scrollp->win); /* Clean the key bindings. */ cleanCDKObjectBindings (vSCROLL, scrollp); /* Unregister this object. */ unregisterCDKObject (vSCROLL, scrollp); } } /* * This function erases the scrolling list from the screen. */ static void _eraseCDKScroll (CDKOBJS *object) { if (validCDKObject (object)) { CDKSCROLL *scrollp = (CDKSCROLL *)object; eraseCursesWindow (scrollp->win); eraseCursesWindow (scrollp->shadowWin); } } static boolean allocListArrays (CDKSCROLL *scrollp, int oldSize, int newSize) { /* *INDENT-EQLS* */ boolean result; int nchunk = ((newSize + 1) | 31) + 1; chtype **newList = typeCallocN (chtype *, nchunk); int *newLen = typeCallocN (int, nchunk); int *newPos = typeCallocN (int, nchunk); if (newList != 0 && newLen != 0 && newPos != 0) { int n; for (n = 0; n < oldSize; ++n) { newList[n] = scrollp->item[n]; newLen[n] = scrollp->itemLen[n]; newPos[n] = scrollp->itemPos[n]; } freeChecked (scrollp->item); freeChecked (scrollp->itemPos); freeChecked (scrollp->itemLen); scrollp->item = newList; scrollp->itemLen = newLen; scrollp->itemPos = newPos; result = TRUE; } else { freeChecked (newList); freeChecked (newLen); freeChecked (newPos); result = FALSE; } return result; } static boolean allocListItem (CDKSCROLL *scrollp, int which, char **work, size_t * used, int number, const char *value) { if (number > 0) { size_t need = NUMBER_LEN (value); if (need > *used) { *used = ((need + 2) * 2); if (*work == 0) { if ((*work = (char *)malloc (*used)) == 0) return FALSE; } else { if ((*work = (char *)realloc (*work, *used)) == 0) return FALSE; } } sprintf (*work, NUMBER_FMT, number, value); value = *work; } if ((scrollp->item[which] = char2Chtype (value, &(scrollp->itemLen[which]), &(scrollp->itemPos[which]))) == 0) return FALSE; scrollp->itemPos[which] = justifyString (scrollp->boxWidth, scrollp->itemLen[which], scrollp->itemPos[which]); return TRUE; } /* * This function creates the scrolling list information and sets up the needed * variables for the scrolling list to work correctly. */ static int createCDKScrollItemList (CDKSCROLL *scrollp, boolean numbers, CDK_CSTRING2 list, int listSize) { int status = 0; if (listSize > 0) { /* *INDENT-EQLS* */ size_t have = 0; char *temp = 0; if (allocListArrays (scrollp, 0, listSize)) { int widestItem = 0; int x = 0; /* Create the items in the scrolling list. */ status = 1; for (x = 0; x < listSize; x++) { if (!allocListItem (scrollp, x, &temp, &have, numbers ? (x + 1) : 0, list[x])) { status = 0; break; } widestItem = MAXIMUM (scrollp->itemLen[x], widestItem); } freeChecked (temp); if (status) { updateViewWidth (scrollp, widestItem); /* Keep the boolean flag 'numbers' */ scrollp->numbers = numbers; } } } else { status = 1; /* null list is ok - for a while */ } return status; } /* * This sets certain attributes of the scrolling list. */ void setCDKScroll (CDKSCROLL *scrollp, CDK_CSTRING2 list, int listSize, boolean numbers, chtype highlight, boolean Box) { setCDKScrollItems (scrollp, list, listSize, numbers); setCDKScrollHighlight (scrollp, highlight); setCDKScrollBox (scrollp, Box); } /* * This sets the scrolling list items. */ void setCDKScrollItems (CDKSCROLL *scrollp, CDK_CSTRING2 list, int listSize, boolean numbers) { int x = 0; if (createCDKScrollItemList (scrollp, numbers, list, listSize) <= 0) return; /* Clean up the display. */ for (x = 0; x < scrollp->viewSize; x++) { writeBlanks (scrollp->win, 1, SCREEN_YPOS (scrollp, x), HORIZONTAL, 0, scrollp->boxWidth - 2); } setViewSize (scrollp, listSize); setCDKScrollPosition (scrollp, 0); scrollp->leftChar = 0; } int getCDKScrollItems (CDKSCROLL *scrollp, char **list) { if (list != 0) { int x; for (x = 0; x < scrollp->listSize; x++) { list[x] = chtype2Char (scrollp->item[x]); } } return scrollp->listSize; } /* * This sets the highlight of the scrolling list. */ void setCDKScrollHighlight (CDKSCROLL *scrollp, chtype highlight) { scrollp->highlight = highlight; } chtype getCDKScrollHighlight (CDKSCROLL *scrollp, chtype highlight GCC_UNUSED) { return scrollp->highlight; } /* * This sets the box attribute of the scrolling list. */ void setCDKScrollBox (CDKSCROLL *scrollp, boolean Box) { ObjOf (scrollp)->box = Box; ObjOf (scrollp)->borderSize = Box ? 1 : 0; } boolean getCDKScrollBox (CDKSCROLL *scrollp) { return ObjOf (scrollp)->box; } /* * Resequence the numbers after a insertion/deletion. */ static void resequence (CDKSCROLL *scrollp) { if (scrollp->numbers) { int j, k; for (j = 0; j < scrollp->listSize; ++j) { char source[80]; chtype *target = scrollp->item[j]; sprintf (source, NUMBER_FMT, j + 1, ""); for (k = 0; source[k] != 0; ++k) { /* handle deletions that change the length of number */ if (source[k] == '.' && CharOf (target[k]) != '.') { int k2 = k; while ((target[k2] = target[k2 + 1]) != 0) ++k2; scrollp->itemLen[j] -= 1; } target[k] &= A_ATTRIBUTES; target[k] |= (chtype)(unsigned char)source[k]; } } } } static boolean insertListItem (CDKSCROLL *scrollp, int item) { int x; for (x = scrollp->listSize; x > item; --x) { scrollp->item[x] = scrollp->item[x - 1]; scrollp->itemLen[x] = scrollp->itemLen[x - 1]; scrollp->itemPos[x] = scrollp->itemPos[x - 1]; } return TRUE; } /* * This adds a single item to a scrolling list, at the end of the list. */ void addCDKScrollItem (CDKSCROLL *scrollp, const char *item) { int itemNumber = scrollp->listSize; int widestItem = WidestItem (scrollp); char *temp = 0; size_t have = 0; if (allocListArrays (scrollp, scrollp->listSize, scrollp->listSize + 1) && allocListItem (scrollp, itemNumber, &temp, &have, scrollp->numbers ? (itemNumber + 1) : 0, item)) { /* Determine the size of the widest item. */ widestItem = MAXIMUM (scrollp->itemLen[itemNumber], widestItem); updateViewWidth (scrollp, widestItem); setViewSize (scrollp, scrollp->listSize + 1); } freeChecked (temp); } /* * This adds a single item to a scrolling list, before the current item. */ void insertCDKScrollItem (CDKSCROLL *scrollp, const char *item) { int widestItem = WidestItem (scrollp); char *temp = 0; size_t have = 0; if (allocListArrays (scrollp, scrollp->listSize, scrollp->listSize + 1) && insertListItem (scrollp, scrollp->currentItem) && allocListItem (scrollp, scrollp->currentItem, &temp, &have, scrollp->numbers ? (scrollp->currentItem + 1) : 0, item)) { /* Determine the size of the widest item. */ widestItem = MAXIMUM (scrollp->itemLen[scrollp->currentItem], widestItem); updateViewWidth (scrollp, widestItem); setViewSize (scrollp, scrollp->listSize + 1); resequence (scrollp); } freeChecked (temp); } /* * This removes a single item from a scrolling list. */ void deleteCDKScrollItem (CDKSCROLL *scrollp, int position) { if (position >= 0 && position < scrollp->listSize) { int x; freeChtype (scrollp->item[position]); /* Adjust the list. */ for (x = position; x < scrollp->listSize; x++) { scrollp->item[x] = scrollp->item[x + 1]; scrollp->itemLen[x] = scrollp->itemLen[x + 1]; scrollp->itemPos[x] = scrollp->itemPos[x + 1]; } setViewSize (scrollp, scrollp->listSize - 1); if (scrollp->listSize > 0) resequence (scrollp); if (scrollp->listSize < maxViewSize (scrollp)) werase (scrollp->win); /* force the next redraw to be complete */ /* do this to update the view size, etc. */ setCDKScrollPosition (scrollp, scrollp->currentItem); } } static void _focusCDKScroll (CDKOBJS *object) { CDKSCROLL *scrollp = (CDKSCROLL *)object; drawCDKScrollCurrent (scrollp); wrefresh (scrollp->listWin); } static void _unfocusCDKScroll (CDKOBJS *object) { CDKSCROLL *scrollp = (CDKSCROLL *)object; drawCDKScrollCurrent (scrollp); wrefresh (scrollp->listWin); } dummyRefreshData (Scroll) dummySaveData (Scroll)