📄 listbox.c
字号:
WORD fRedraw;
{
#ifdef LISTBOX_DIR
if (!(pwnd->style & LBS_SORT))
{
/* not sorted : we must fit it in !!! */
InsertSz(pwnd, pwnd->cszLb, sz, TRUE, fRedraw);
}
else if (pwnd->cszLb == 0)
{
/* first element in sorted listbox */
InsertSz(pwnd, 0, sz, FALSE, fRedraw);
}
else
{
/* insert in sorted (no OnDemand concerns) */
char FAR * lgpsz;
WORD FAR * lmpiszoff;
short iszLo, iszHi;
Assert(sz != NULL); /* on-demand not allowed */
lgpsz = LpvDeref(pwnd->hmemGpszLb);
lmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
iszLo = iszMin;
iszHi = pwnd->cszLb;
do
{
REG short iszProbe = (iszLo + iszHi) / 2;
#ifdef KANJI
if (fdircmp((char *) sz, lgpsz+lmpiszoff[iszProbe]) > 0)
#else
if (fstrcmp((char *) sz, lgpsz+lmpiszoff[iszProbe]) > 0)
#endif
iszLo = iszProbe+1;
else
iszHi = iszProbe;
}
while (iszLo < iszHi);
/*GlobalUnlock(pwnd->hmemGpszLb);*/
/*GlobalUnlock(pwnd->hmemMpiszoffLb);*/
InsertSz(pwnd, iszLo, sz, FALSE, fRedraw);
}
#else
/* no DIR listboxes -- don't bother with sort option */
Assert(!(pwnd->style & LBS_SORT));
InsertSz(pwnd, pwnd->cszLb, sz, FALSE, fRedraw); /* add at end */
#endif
}
#ifdef KANJI
STATIC int
/*
* it is not for KANJI.
* sorting dirname as same as WINDOWS.
* order is as follows
* 1: x.xxx files
* 2: [..] parent directory
* 3: [xxx] directories
* 4: [-x-] drives
*/
fdircmp(s1, s2)
char FAR *s1, FAR *s2;
{
if (*s1 != '[') {
if (*s2 == '[') return(-1);
} else if (*s2 != '[') {
return(1);
} else {
++s1, ++s2;
if (*s1 == '.') return(-1);
if (*s2 == '.') return(1);
if (*s1 != '-') {
if (*s2 == '-') return(-1);
} else if (*s2 != '-') return(1);
}
#ifdef KANJI
return(fjstrcmp(s1, s2)); /* really needs for KANJI */
#else
return(fstrcmp(s1, s2));
#endif
}
#define iskanji(c) ( ((c)>=0x81 && (c)<=0x9F)||((c)>=0xE0 && (c)<= 0xFC) )
STATIC int
fjstrcmp(s1, s2)
unsigned char FAR *s1, FAR *s2;
{
register unsigned short c1, c2;
for (;;) {
c1 = *s1++;
if (iskanji(c1))
c1 = (*s1 == 0)? 0: (c1 << 8)|*s1++;
c2 = *s2++;
if (iskanji(c2))
c2 = (*s2 == 0)? 0: (c2 << 8)|*s2++;
if (c1 < c2) return(-1);
if (c1 > c2) return(1);
if (c1 == 0) return(0);
}
}
#endif /* KANJI */
STATIC VOID
InsertSz(pwnd, isz, sz, fForce, fRedraw)
/*
-- insert a string at the specified position in the listbox
-- if no memory left, do not add (no error condition)
-- if sz == NULL, mark as special (on-demand)
-- if previous position empty, replace string
-- if changing size and fForce and no memory then go to low memory case
(free any blocks and do everything on demand)
*/
REG PWND pwnd;
WORD isz;
char *sz;
BOOL fForce;
WORD fRedraw;
{
WORD FAR * lmpiszoff; /* string pointers */
WORD cch;
WORD off;
RRC rrc;
cch = (sz != NULL) ? (strlen(sz) + 1) : 0;
if (pwnd->cszLb == 0)
{
/* first time allocation */
Assert(pwnd->hmemGpszLb == NULL);
Assert(pwnd->hmemMpiszoffLb == NULL);
if ((pwnd->hmemGpszLb = GlobalAlloc(GMEM_MOVEABLE,
(DWORD) cbInitLb)) == NULL)
{
/* out of memory for string data */
if (!fForce)
return;
/* force => no handle on demand all the time */
}
else if ((pwnd->hmemMpiszoffLb = GlobalAlloc(GMEM_MOVEABLE,
(DWORD) coffInitLb * sizeof(WORD))) == NULL)
{
/* out of memory for string indices */
GlobalFree(pwnd->hmemGpszLb);
pwnd->hmemGpszLb = NULL;
if (!fForce)
return;
}
/* initialize it */
pwnd->offLb = 0;
pwnd->iszTopLb = iszMin;
pwnd->offMaxLb = cbInitLb;
pwnd->iszMacLb = coffInitLb;
pwnd->iszCurLb = iszMin; /* start at top */
}
if (pwnd->hmemGpszLb == NULL)
{
/* we are doing things on demand */
if (fForce)
RevertToOomLb(pwnd, isz);
return;
}
/* try to insert into the cache */
Assert(pwnd->hmemGpszLb != NULL);
Assert(pwnd->hmemMpiszoffLb != NULL);
if (pwnd->cszLb >= pwnd->iszMacLb)
{
/* try to grow for indices */
/* if >64K then request to GlobalReAlloc should fail! */
WORD hmem;
if ((hmem = GlobalReAlloc(pwnd->hmemMpiszoffLb,
(DWORD) (pwnd->iszMacLb + coffGrowLb) * sizeof(WORD),
GMEM_MOVEABLE)) == NULL)
{
if (fForce)
RevertToOomLb(pwnd, isz);
return;
}
pwnd->iszMacLb += coffGrowLb;
pwnd->hmemMpiszoffLb = hmem;
}
if (((off = pwnd->offLb) + cch) >= pwnd->offMaxLb)
{
WORD hmem;
if ((hmem = GlobalReAlloc(pwnd->hmemGpszLb,
(DWORD) pwnd->offMaxLb + cbGrowLb,
GMEM_MOVEABLE)) == NULL)
{
if (fForce)
RevertToOomLb(pwnd, isz);
return;
}
pwnd->offMaxLb += cbGrowLb;
pwnd->hmemGpszLb = hmem;
}
/* now place in cache */
if (sz == NULL)
{
off = offEmpty;
}
else
{
char FAR * lgpsz; /* string data */
lgpsz = LpvDeref(pwnd->hmemGpszLb);
bltbytex((char FAR *) sz, lgpsz+off, cch);
/*GlobalUnlock(pwnd->hmemGpszLb);*/
}
/* Insert offset into list */
lmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
if (isz >= pwnd->cszLb)
{
/* easy insertion at end of list */
lmpiszoff[pwnd->cszLb++] = off;
}
else
{
/* may be empty ? */
WORD FAR * lpoff;
lpoff = &lmpiszoff[isz]; /* where it should go */
if (*lpoff != offEmpty)
{
/* move space in index block */
bltbytex(lpoff, lpoff+1,
(pwnd->cszLb - isz) * sizeof(WORD));
pwnd->cszLb++;
/* if string was added before visible portion, update
* listbox indices (for top and current) */
if (isz < pwnd->iszTopLb)
{
pwnd->iszTopLb++;
pwnd->iszCurLb++;
}
}
Debug(else Assert(off != offEmpty));
/* else just replacing current on-demand string */
*lpoff = off;
}
GetClientRrc(pwnd,&rrc);
if ((isz >= pwnd->iszTopLb)
&& (isz <= pwnd->iszTopLb + (WORD) rrc.ryBottom) && fRedraw)
DrawWindow(pwnd);
/*GlobalUnlock(pwnd->hmemMpiszoffLb);*/
pwnd->offLb += cch;
}
STATIC VOID
DeleteSz(pwnd, isz, fRedraw)
/*
-- delete a string at the specified position in the listbox
*/
REG PWND pwnd;
WORD isz;
WORD fRedraw;
{
char FAR * lgpsz; /* string data */
WORD FAR * lmpiszoff; /* string pointers */
WORD cch;
WORD off;
WORD offOld;
WORD iszLoop;
WORD FAR * lpoff;
RRC rrc;
Assert((isz >= 0) && (isz < pwnd->cszLb));
/* try to insert into the cache */
Assert(pwnd->hmemGpszLb != NULL);
Assert(pwnd->hmemMpiszoffLb != NULL);
lgpsz = LpvDeref(pwnd->hmemGpszLb);
lmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
off = lmpiszoff[isz];
Assert(off != offEmpty); /* can't be on-demand */
cch = fstrlen(lgpsz+off);
bltbytex(lgpsz+off+cch,lgpsz+off,(pwnd->offLb-off-cch));
pwnd->offLb -= cch;
lpoff = &lmpiszoff[isz]; /* where it is */
if (isz != pwnd->cszLb) bltbytex(lpoff+1, lpoff,
(pwnd->cszLb - isz) * sizeof(WORD));
pwnd->cszLb--;
for (iszLoop = 0; iszLoop < pwnd->cszLb; iszLoop++)
{
if ((offOld = lmpiszoff[iszLoop]) >= off)
lmpiszoff[iszLoop] = offOld-cch;
}
GetClientRrc(pwnd,&rrc);
if (pwnd->cszLb == 0)
{
SendMessage(pwnd,LB_RESETCONTENT,0,0L);
}
else
{
if (isz < pwnd->iszTopLb)
{
pwnd->iszTopLb--;
if (pwnd->iszCurLb > 0) pwnd->iszCurLb--;
}
if (pwnd->iszCurLb >= pwnd->cszLb)
pwnd->iszCurLb--;
if ((pwnd->iszTopLb > 0)
&&(pwnd->iszTopLb + (WORD) rrc.ryBottom > pwnd->cszLb))
pwnd->iszTopLb--;
}
if ((isz >= pwnd->iszTopLb)
&& (isz <= pwnd->iszTopLb + (WORD) rrc.ryBottom) && fRedraw)
DrawWindow(pwnd);
}
STATIC VOID
ReplaceSz(pwnd, isz, sz)
/*
-- replace a string in the listbox
-- update the screen if necessary
*/
REG PWND pwnd;
WORD isz;
char *sz;
{
char FAR * lgpsz;
WORD FAR * lmpiszoff;
WORD off;
RY ry;
RRC rrc;
/* lock down string buffer and indexes (handles may be NULL) */
lgpsz = LpvDeref(pwnd->hmemGpszLb);
lmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
Assert(isz < pwnd->cszLb);
if (pwnd->hmemGpszLb != NULL &&
(off = lmpiszoff[isz]) != offEmpty)
{
/* valid cached string */
Assert(strlen(sz) == fstrlen((char FAR *)(lgpsz+off)));
fstrcpy(lgpsz+off, (char FAR *) sz);
}
GetClientRrc(pwnd,&rrc);
if ((isz >= pwnd->iszTopLb)
&& (isz < pwnd->iszTopLb + (WORD) rrc.ryBottom))
{
/* item is displayed */
ry = (RY) (isz - pwnd->iszTopLb);
TextOut(pwnd, rxListBoxMin, ry, sz, -1, isaListBox);
if (isz == pwnd->iszCurLb && FSelected(pwnd))
{
rrc.ryBottom = (rrc.ryTop = ry) + 1;
FillRrc(pwnd, &rrc, '\0', DiMake(dmAttrOnly,
pwnd->isaHiliteColor));
}
}
}
STATIC VOID
RevertToOomLb(pwnd, isz)
/*
-- revert to low memory useage of listbox data
(both handles NULL, all data by on-demand)
-- must not be sorted
*/
REG PWND pwnd;
WORD isz; /* string that is inserted */
{
Assert(!(pwnd->style & LBS_SORT));
if (pwnd->hmemGpszLb != NULL)
{
GlobalFree(pwnd->hmemGpszLb);
Assert(pwnd->hmemMpiszoffLb != NULL);
GlobalFree(pwnd->hmemMpiszoffLb);
pwnd->hmemGpszLb = NULL;
pwnd->hmemMpiszoffLb = NULL;
}
/* if the new string is after the end of the listbox, adjust size */
if (isz >= pwnd->cszLb)
pwnd->cszLb = isz + 1;
}
PRIVATE WORD FARPRIVATE
GetListText(pwnd, sz, cchMax)
/*
-- fill sz with the contents of the currently selected string
-- return number of characters copied
*/
REG PWND pwnd;
char *sz;
WORD cchMax;
{
char FAR * lgpsz;
WORD FAR * lmpiszoff;
char FAR * lsz;
WORD cch;
char szBuff[cchListTextMax];
/* don't copy anything if the listbox is empty or cursor is not
on anything. */
if (pwnd->cszLb == 0 || !FSelected(pwnd))
{
sz[0] = '\0';
return (0);
}
if (pwnd->hmemGpszLb != NULL)
{
/* get from cache */
lgpsz = LpvDeref(pwnd->hmemGpszLb);
lmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
Assert(lmpiszoff[pwnd->iszCurLb] != offEmpty);
lsz = (char FAR *) lgpsz + lmpiszoff[pwnd->iszCurLb];
/*GlobalUnlock(pwnd->hmemMpiszoffLb);*/
}
else
{
GetOnDemand(pwnd, pwnd->iszCurLb, NULL, NULL, szBuff);
lsz = (char FAR *) szBuff;
}
if ((cch = fstrlen(lsz) + 1) > cchMax)
cch = cchMax;
/* copy on the number of characters needed */
bltbytex(lsz, (char FAR *) sz, cch);
/*GlobalUnlock(pwnd->hmemGpszLb);*/
return(cchMax);
}
STATIC VOID
GetOnDemand(pwnd, isz, plmpiszoff, plgpsz, szDest)
/*
-- get a string for an on-demand listbox
-- unlock the blocks, call listbox proc, relock the block
-- fill szDest with string
-- save string (so we don't have to go through this again) if room
*/
REG PWND pwnd;
WORD isz;
WORD FAR ** plmpiszoff;
char FAR ** plgpsz;
char * szDest;
{
/*GlobalUnlock(pwnd->hmemGpszLb);*/
/*GlobalUnlock(pwnd->hmemMpiszoffLb);*/
(*PwfnCtlLb(pwnd))(tmmText, szDest, isz, pwnd->id, 0, 0);
if (pwnd->cszLb == 0 || pwnd->hmemGpszLb)
{
/* starting a new listbox or not oom listbox */
InsertSz(pwnd, isz, szDest, FALSE, FALSE); /* may fail */
}
*plgpsz = LpvDeref(pwnd->hmemGpszLb);
*plmpiszoff = LpvDeref(pwnd->hmemMpiszoffLb);
}
STATIC VOID FAR *
LpvDeref(hmem)
/*
-- defererence a handle
-- (or return NULL if handle is NULL)
*/
WORD hmem;
{
return (hmem == NULL) ? NULL : LpvGlobalDeref(hmem);
}
/**************************************************************************/
/* Public interface for listboxes */
/**************************************************************************/
#ifndef LISTBOX_HORIZ // only supported for vertical
PUBLIC VOID FARPUBLIC
InitListBox(pwnd, pwfn_ctl)
PWND pwnd;
PWFN_CTL pwfn_ctl;
/*
-- fix color
-- put on demand function supplied into the wnd struct
-- reset listbox
-- fill listbox
*/
{
StartPublic();
/* Non-directory ListBox */
WORD isz;
WORD csz;
char szBuffer[cchListTextMax];
if (pwfn_ctl != NULL) PwfnCtlLb(pwnd) = pwfn_ctl;
pwfn_ctl = PwfnCtlLb(pwnd);
SendMessageShort(pwnd, LB_RESETCONTENT);
csz = (*pwfn_ctl)(tmmCount, NULL, NULL, pwnd->id, 0, 0);
isz = 0;
if ((csz == cszUnknown)||(pwnd->style && LBS_SORT))
{
/* we must fill in the listbox */
while (csz == cszUnknown || isz < csz)
{
if ((*pwfn_ctl)(tmmText, szBuffer, isz++, pwnd->id,
0, 0))
{
/* we have a string */
SendMessage(pwnd, LB_ADDSTRING,
(WORD) szBuffer, 0L);
}
else if (csz == cszUnknown)
break; /* stop filling */
}
}
else
{
/* fill on demand (fill with empties) */
Assert(csz != cszUnknown);
while (csz--)
SendMessage(pwnd, LB_ADDSTRING, 0, 0L);
}
StopPublic();
}
PUBLIC VOID FARPUBLIC
GetListBoxOrientation(pwnd, pisz, pdisz)
PWND pwnd;
WORD * pisz;
WORD * pdisz;
{
*pisz = (WORD) SendMessage(pwnd, LB_GETCURSEL, 0, 0L);
*pdisz = (*pisz == iszNil) ? 0 : (*pisz - pwnd->iszTopLb);
}
PUBLIC VOID FARPUBLIC
InitListBoxOriented(pwnd, pwfn_ctl, pisz, pdisz)
PWND pwnd;
PWFN_CTL pwfn_ctl;
WORD * pisz; /* current selection */
WORD * pdisz; /* distance from top of box */
/*
-- Init then orient listbox
*/
{
StartPublic();
InitListBox(pwnd, pwfn_ctl);
if (*pisz != iszNil)
{
if (pwnd->cszLb == 0)
{
*pisz = iszNil;
*pdisz = 0;
}
else
{
RRC rrc;
WORD dry;
GetClientRrc(pwnd,&rrc);
dry = (WORD) rrc.ryBottom;
/* 1 - make selection legal
2 - make sure no blank space at the bottom
3 - make distance from top legal */
*pisz = min(*pisz, pwnd->cszLb - 1);
if (pwnd->cszLb + *pdisz < *pisz + dry)
*pdisz = *pisz + dry - pwnd->cszLb;
*pdisz = min(*pisz, min(*pdisz, dry-1));
pwnd->iszTopLb = *pisz - *pdisz;
pwnd->iszCurLb = *pisz;
}
}
DrawWindow(pwnd);
SendMessage(pwnd,LB_SETCURSEL,*pisz,0L);
StopPublic();
}
#endif /*!LISTBOX_HORIZ*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -