📄 listbox.c
字号:
RY ryTop;
RY ryBottom;
WORD isz;
{
char sz[cchListTextMax];
char FAR * lgpsz;
WORD FAR * lmpiszoff;
REG RY ry;
#ifdef LISTBOX_HORIZ
WORD ccol; /* # of columns */
RX rxLeft; /* current left position */
#endif
/* lock down string buffer and indexes (handles may be NULL) */
lgpsz = LpvDeref(pwnd->hmemGpszLb);
lmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
BeginDraw();
#ifdef LISTBOX_HORIZ
/* Horizontal : fill in vertical list, then go to the right */
ccol = pwnd->citemWidthLb;
Assert(ccol != 0);
rxLeft = RxLeftItem(pwnd, 0);
while (ccol--)
{
WORD cch;
#endif /*LISTBOX_HORIZ*/
for (ry = ryTop; ry < ryBottom; ry++)
{
WORD off;
if (isz >= pwnd->cszLb)
{
#ifndef LISTBOX_HORIZ
break; /* gone too far */
#else
cch = 0;
goto BlankFillItem;
#endif /*LISTBOX_HORIZ*/
}
if (pwnd->hmemGpszLb != NULL &&
(off = lmpiszoff[isz]) != offEmpty)
{
/* valid cached string */
fstrcpy((char FAR *) sz, lgpsz+off);
}
else
{
/* not in cache */
GetOnDemand(pwnd, isz, &lmpiszoff, &lgpsz, sz);
}
#ifndef LISTBOX_HORIZ
TextOut(pwnd, rxListBoxMin, ry, sz, -1, pwnd->isaColor);
#else
/* display the string in proper column */
if ((cch = CchRealLenSz(sz)) > pwnd->drxItemLb)
cch = pwnd->drxItemLb;
TextOut(pwnd, rxLeft, ry, sz, cch, pwnd->isaColor);
BlankFillItem:
if (cch != pwnd->drxItemLb)
{
/* fill remaining part of line */
RRC rrc;
rrc.rxLeft = rxLeft + cch;
rrc.rxRight = rxLeft + pwnd->drxItemLb;
rrc.ryBottom = (rrc.ryTop = ry) + 1;
FillRrc(pwnd, &rrc, ' ', pwnd->isaColor);
}
#endif /*LISTBOX_HORIZ*/
/* invert the listbox selection */
if (isz == pwnd->iszCurLb && FSelected(pwnd))
{
/* selected */
RRC rrc;
#ifndef LISTBOX_HORIZ
/* entire width of listbox */
GetClientRrc(pwnd, &rrc);
#else
/* just this item with 1 before & after */
rrc.rxRight = (rrc.rxLeft = rxLeft - 1) +
pwnd->drxItemLb + 2;
#endif
rrc.ryBottom = (rrc.ryTop = ry) + 1;
FillRrc(pwnd, &rrc, '\0', DiMake(dmAttrOnly,
pwnd->isaHiliteColor));
}
isz++;
}
#ifdef LISTBOX_HORIZ
rxLeft += (BYTE) pwnd->drxItemLb + 1;
}/*end while(ccol--); */
#endif
EndDraw();
/* unlock string buffers and indexes */
/*GlobalUnlock(pwnd->hmemGpszLb);*/
/*GlobalUnlock(pwnd->hmemMpiszoffLb);*/
}
STATIC VOID
ScrollListBox(pwnd, dry, fKillOld)
/*
-- scroll vertical listbox by dry lines (may be negative)
-- if hit top show top, if hit bottom show bottom
*/
REG PWND pwnd;
short dry;
BOOL fKillOld; /* TRUE => kill old selection */
{
WORD iszTop;
RRC rrc;
WORD iszBottom;
short iszNewTop;
short iszNewBottom; /* note : use for signed compares */
WORD ryBottom;
#ifdef LISTBOX_HORIZ
if (pwnd->style & WS_HSCROLL)
{
// horizontal listbox
Assert(!fKillOld);
ScrollHorizListBox(pwnd, dry);
return;
}
#endif /*LISTBOX_HORIZ*/
iszTop = pwnd->iszTopLb;
/* optionally turn off old selection */
if (fKillOld)
HiliteListSel(pwnd, FALSE); /* turn off old */
GetClientRrc(pwnd, &rrc);
ryBottom = rrc.ryBottom;
iszBottom = iszTop + ryBottom - 1;
iszNewTop = iszTop + dry;
iszNewBottom = iszBottom + dry;
/* see if we should stop at top or bottom */
if (iszNewTop < 0)
{
iszNewTop = iszMin;
iszNewBottom = ryBottom - 1;
}
else if (iszNewBottom >= pwnd->cszLb)
{
iszNewBottom = pwnd->cszLb - 1;
if ((iszNewTop = iszNewBottom - (ryBottom - 1)) < 0)
iszNewTop = iszMin;
}
dry = iszNewTop - iszTop;
/* move selection if necessary */
if (pwnd->iszCurLb > iszNewBottom)
pwnd->iszCurLb = iszNewBottom;
else if (pwnd->iszCurLb < iszNewTop)
pwnd->iszCurLb = iszNewTop;
pwnd->iszTopLb = iszNewTop;
/* smooth scroll */
if (iszNewTop > iszTop && iszNewTop < iszBottom)
{
BltRrc(pwnd, 0, 0, rrc.rxRight, (BYTE) (ryBottom - dry),
0, (BYTE) dry);
rrc.ryTop = (RY) (ryBottom-dry);
FillRrc(pwnd, &rrc, ' ', pwnd->isaColor);
FillListBox(pwnd, rrc.ryTop, (RY) ryBottom, iszNewTop+rrc.ryTop);
}
else if (iszNewBottom > iszTop && iszNewBottom < iszBottom)
{
BltRrc(pwnd, 0, (RY) (0-dry), rrc.rxRight, (BYTE) (ryBottom + dry),
0, 0);
rrc.ryBottom = (RY) (0-dry);
FillRrc(pwnd, &rrc, ' ', pwnd->isaColor);
FillListBox(pwnd, 0, (RY) (0-dry), iszNewTop);
}
else if (iszNewTop != iszTop)
{
/* outside range to scroll => redraw it */
DisplayListBox(pwnd);
}
SetScrollWindow(pwnd);
HiliteListSel(pwnd, TRUE);
}
#ifdef LISTBOX_HORIZ
STATIC VOID
ScrollHorizListBox(pwnd, dcol)
/*
-- scroll a horizontal listbox by dcol columns (may be negative)
-- if hit top show first column, if hit bottom show last column
*/
REG PWND pwnd;
short dcol;
{
WORD iszTop;
BYTE dry;
RRC rrc;
short iszNewTop; /* note : use for signed compares */
Assert(pwnd->style & WS_HSCROLL);
GetClientRrc(pwnd,&rrc);
iszTop = pwnd->iszTopLb;
dry = rrc.ryBottom;
Assert(iszTop % dry == 0);
iszNewTop = iszTop + dcol * dry;
if (iszNewTop < 0)
{
pwnd->iszCurLb = iszNewTop = iszMin;
}
else if (iszNewTop >= pwnd->cszLb)
{
/* adjust to right hand side */
iszNewTop = ((pwnd->cszLb - 1) / dry) * dry;
pwnd->iszCurLb = pwnd->cszLb - 1; /* select last */
}
pwnd->iszTopLb = iszNewTop;
if (iszNewTop != iszTop)
FillListBox(pwnd, 0, dry, pwnd->iszTopLb = iszNewTop);
SetScrollWindow(pwnd);
HiliteListSel(pwnd, TRUE);
}
#endif /*LISTBOX_HORIZ*/
STATIC VOID
HiliteListSel(pwnd, fHilite)
/*
-- highlight/unhighlight the iszCur in the listbox.
-- if iszCur is not displayed force it to be displayed
*/
REG PWND pwnd;
BOOL fHilite; /* TRUE => hilite, FALSE => unhilite */
{
REG WORD iszCur;
RRC rrc;
#ifdef LISTBOX_HORIZ
BYTE dry; /* height */
#endif
iszCur = pwnd->iszCurLb;
/* Cursor should be always on */
Assert(pwnd->fCursorOn);
/* position must be valid (assume < 32K) */
Assert((short) iszCur >= 0);
GetClientRrc(pwnd, &rrc);
#ifdef LISTBOX_HORIZ
if (!(pwnd->style & WS_HSCROLL))
#endif
{
/* if out of visible range, scroll vertically into range */
if (fHilite &&
(iszCur < pwnd->iszTopLb ||
iszCur >= (pwnd->iszTopLb +
CitemVisible(pwnd, rrc.ryBottom))))
{
/* shift visible range */
if (iszCur > pwnd->cszLb -
CitemVisible(pwnd, rrc.ryBottom))
pwnd->iszTopLb = pwnd->cszLb -
CitemVisible(pwnd, rrc.ryBottom);
else
pwnd->iszTopLb = iszCur;
if (fDrawItem)
DisplayListBox(pwnd);
}
/* Vertical : compute 1 whole line to be [un]highlighted */
rrc.ryBottom = (rrc.ryTop = (RY) (iszCur - pwnd->iszTopLb)) + 1;
Assert(rrc.rxLeft == 0);
MoveCursor(pwnd, rxListBoxMin, rrc.ryTop);
}
#ifdef LISTBOX_HORIZ
else
{
Assert(pwnd->style & WS_HSCROLL);
dry = rrc.ryBottom - rrc.ryTop;
/* if out of visible range, scroll horizontally into range */
if (fHilite && iszCur < pwnd->iszTopLb)
{
/* adjust to be at the left column */
pwnd->iszTopLb = (iszCur / dry) * dry;
if (fDrawItem)
DisplayListBox(pwnd);
}
else if (fHilite &&
iszCur >= (pwnd->iszTopLb +
CitemVisible(pwnd, rrc.ryBottom)))
{
/* adjust to be at the right column */
pwnd->iszTopLb = (iszCur / dry) * dry;
if (pwnd->iszTopLb >= dry * (pwnd->citemWidthLb - 1))
pwnd->iszTopLb -= dry * (pwnd->citemWidthLb - 1);
if (fDrawItem)
DisplayListBox(pwnd);
}
/* Horizontal : compute partial line to hilight */
iszCur -= pwnd->iszTopLb; /* from top of listbox */
Assert((short)iszCur >= 0 &&
iszCur < CitemVisible(pwnd, rrc.ryBottom));
rrc.ryBottom = (rrc.ryTop = (RY) (iszCur % dry)) + 1;
/* width includes 1 space before and after */
Assert(rxListBoxMin == 1);
rrc.rxRight =
(rrc.rxLeft = RxLeftItem(pwnd, iszCur / dry) - 1) +
pwnd->drxItemLb + 2;
MoveCursor(pwnd, rrc.rxLeft + rxListBoxMin, rrc.ryTop);
}
#endif /*LISTBOX_HORIZ*/
if (fDrawItem)
{
FillRrc(pwnd, &rrc, '\0', DiMake(dmAttrOnly,
fHilite ? pwnd->isaHiliteColor : pwnd->isaColor));
#ifdef LISTBOX_COLOR
if (!fHilite)
{
/* refill the listbox to get correct colors */
SetFSelected(pwnd, FALSE); /* fake not selected */
FillListBox(pwnd, rrc.ryTop, rrc.ryTop+1, iszCur);
}
#endif
}
SetFSelected(pwnd, TRUE);
}
STATIC VOID
MoveSelection(pwnd, iszNew)
/*
-- move the selection to iszNew
*/
REG PWND pwnd;
WORD iszNew;
{
Assert(iszNew < pwnd->cszLb);
if (pwnd->iszCurLb == iszNew && FSelected(pwnd))
return; /* already there */
HiliteListSel(pwnd, FALSE); /* turn old off */
pwnd->iszCurLb = iszNew;
HiliteListSel(pwnd, TRUE);
}
STATIC VOID
MoveSelectionDown(pwnd)
/*
-- move iszCur down a line
*/
REG PWND pwnd;
{
WORD iszBottom;
RRC rrc;
GetClientRrc(pwnd,&rrc);
iszBottom = pwnd->iszTopLb + CitemVisible(pwnd, rrc.ryBottom) - 1;
if (FSelected(pwnd) && pwnd->iszCurLb + 1 < pwnd->cszLb)
{
HiliteListSel(pwnd, FALSE);
if (pwnd->iszCurLb++ == iszBottom)
{
ScrollListBox(pwnd, 1, FALSE);
return;
}
}
HiliteListSel(pwnd, TRUE);
}
STATIC VOID
MoveSelectionUp(pwnd)
/*
-- move iszCur up a line
*/
REG PWND pwnd;
{
if (FSelected(pwnd) && pwnd->iszCurLb != iszMin)
{
HiliteListSel(pwnd, FALSE);
if (pwnd->iszCurLb-- == pwnd->iszTopLb)
{
ScrollListBox(pwnd, -1, FALSE);
return;
}
}
HiliteListSel(pwnd, TRUE);
}
#ifdef LISTBOX_HORIZ
STATIC VOID
MoveSelectionLeft(pwnd, dcol)
/*
-- move selection left "dcol" columns
-- vertical listboxes => move up
*/
REG PWND pwnd;
WORD dcol;
{
if (pwnd->style & WS_VSCROLL)
{
Assert(dcol == 1);
MoveSelectionUp(pwnd);
}
else
{
// horizontal
WORD cszMove; /* # strings to move selection by */
RRC rrc;
GetClientRrc(pwnd,&rrc);
cszMove = rrc.ryBottom * dcol;
if (pwnd->iszCurLb - iszMin < cszMove)
MoveSelection(pwnd, iszMin);
else
MoveSelection(pwnd, pwnd->iszCurLb - cszMove);
}
}
STATIC VOID
MoveSelectionRight(pwnd, dcol)
/*
-- move selection right "dcol" columns (horizontal only)
-- vertical listboxes => move down
*/
REG PWND pwnd;
WORD dcol;
{
if (pwnd->style & WS_VSCROLL)
{
Assert(dcol == 1);
MoveSelectionDown(pwnd);
}
else
{
WORD iszNew;
RRC rrc;
GetClientRrc(pwnd,&rrc);
iszNew = pwnd->iszCurLb + rrc.ryBottom * dcol;
if (iszNew >= pwnd->cszLb)
MoveSelection(pwnd, pwnd->cszLb - 1);
else
MoveSelection(pwnd, iszNew);
}
}
#endif /*LISTBOX_HORIZ*/
STATIC BOOL
FLocateMatch(pwnd, wParam)
/*
-- find the entry in the list box beginning with ch (case insensitive)
-- move current location if found
-- return TRUE if selection made
*/
REG PWND pwnd;
WORD wParam; /* wParam of WM_CHAR message */
{
char FAR * lgpsz;
WORD FAR * lmpiszoff;
REG WORD iszCur;
BOOL fRet;
fRet = FALSE;
if (wParam > 0xff)
return FALSE; /* non-ascii */
iszCur = pwnd->iszCurLb;
if (FSelected(pwnd))
if (++iszCur >= pwnd->cszLb)
iszCur = iszMin; /* try from this point on */
lgpsz = LpvDeref(pwnd->hmemGpszLb);
lmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
/* convert to upper case */
if ((char) wParam >= 'a' && (char) wParam <= 'z')
wParam -= 'a' - 'A';
else if (wParam > 0x7f)
wParam = ChUpperFromChExt((char)wParam);
do
{
char FAR * lgpsz2;
char ch2;
WORD off;
if (pwnd->hmemGpszLb != NULL &&
(off = lmpiszoff[iszCur]) != offEmpty)
{
/* valid cached string */
lgpsz2 = lgpsz+off; /* &lgpsz[off] */
}
else
{
/* not in cache */
char szBuff[cchListTextMax];
GetOnDemand(pwnd, iszCur, &lmpiszoff, &lgpsz, szBuff);
lgpsz2 = (char FAR *) szBuff;
}
#ifdef EXTRAS
if (*lgpsz2 == chColorPrefix)
lgpsz2 += 2;
#endif
while (((unsigned char)(*lgpsz2) < '0') && (*lgpsz2 != '\0'))
lgpsz2++;
ch2 = *lgpsz2;
if (ch2 >= 'a' && ch2 <= 'z')
ch2 -= 'a' - 'A';
else if ((unsigned char) ch2 > 0x7f)
ch2 = ChUpperFromChExt(ch2);
if (ch2 == (char) wParam)
{
/* got it */
MoveSelection(pwnd, iszCur);
fRet = TRUE;
break;
}
/* move iszCur to next possibility */
if (++iszCur >= pwnd->cszLb)
iszCur = iszMin; /* wrap around */
}
while (iszCur != pwnd->iszCurLb);
/*GlobalUnlock(pwnd->hmemGpszLb);*/
/*GlobalUnlock(pwnd->hmemMpiszoffLb);*/
return (fRet);
}
STATIC VOID
ResetContent(pwnd)
/*
-- resets the contents of the list box
*/
REG PWND pwnd;
{
#ifdef LISTBOX_HORIZ
if (pwnd->citemWidthLb == 0)
{
RRC rrc;
GetClientRrc(pwnd,&rrc);
/* initialize horizontal listbox info */
pwnd->citemWidthLb = 1;
pwnd->drxItemLb = rrc.rxRight - 2;
/* 2 extra for start and end space */
}
#endif /*LISTBOX_HORIZ*/
/* free any listbox data */
if (pwnd->hmemGpszLb != NULL)
{
GlobalFree(pwnd->hmemGpszLb);
Assert(pwnd->hmemMpiszoffLb != NULL);
GlobalFree(pwnd->hmemMpiszoffLb);
pwnd->hmemGpszLb = NULL;
pwnd->hmemMpiszoffLb = NULL;
}
else
{
Assert(pwnd->hmemMpiszoffLb == NULL);
}
pwnd->cszLb = pwnd->iszTopLb = 0;
pwnd->iszCurLb = iszMin;
SetFSelected(pwnd, FALSE);
/* set cursor to no selection */
MoveCursor(pwnd, rxListBoxMin, 0);
}
PRIVATE VOID FARPRIVATE
AddListString(pwnd, sz)
/*
-- add an item to the list box
-- if sz == NULL, mark as not yet known (for fill on-demand)
*/
REG PWND pwnd;
char *sz;
{
AddListSz(pwnd, sz, FALSE);
}
PRIVATE VOID FARPRIVATE
AddListSz(pwnd, sz, fRedraw)
/*
-- add an item to the list box
-- if sz == NULL, mark as not yet known (for fill on-demand)
*/
REG PWND pwnd;
char *sz;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -