test: lboxctl1.c File Reference

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# lboxctl1.c File Reference

`#include "precomp.h"`

Go to the source code of this file.

## Functions

INT | xxxLBBinarySearchString (PLBIV plb, LPWSTR lpstr)
int | xxxSetLBScrollParms (PLBIV plb, int nCtl)
void | xxxLBShowHideScrollBars (PLBIV plb)
LONG_PTR | LBGetItemData (PLBIV plb, INT sItem)
INT | LBGetText (PLBIV plb, BOOL fLengthOnly, BOOL fAnsi, INT index, LPWSTR lpbuffer)
BOOL | GrowMem (PLBIV plb, INT numItems)
LONG | xxxLBInitStorage (PLBIV plb, BOOL fAnsi, INT cItems, INT cb)
INT | xxxLBInsertItem (PLBIV plb, LPWSTR lpsz, INT index, UINT wFlags)
INT | LBlstrcmpi (LPWSTR lpStr1, LPWSTR lpStr2, DWORD dwLocaleId)
BOOL | xxxLBResetContent (PLBIV plb)
INT | xxxLBoxCtlDelete (PLBIV plb, INT sItem)
void | xxxLBoxDeleteItem (PLBIV plb, INT sItem)
INT | xxxLBSetCount (PLBIV plb, INT cItems)
UINT | LBCalcAllocNeeded (PLBIV plb, INT cItems)

## Function Documentation

BOOL GrowMem | ( | PLBIV | plb,
|  | INT | numItems
| ) |

Definition at line 285 of file lboxctl1.c.

References BOOL, tagLBIV::cMax, FALSE, tagLBIV::fHasData, tagLBIV::fHasStrings, NULL, tagLBIV::OwnerDraw, OWNERDRAWVAR, tagLBIV::rgpch, SINGLESEL, TRUE, UserLocalAlloc, UserLocalReAlloc, and tagLBIV::wMultiple.

Referenced by xxxLBInitStorage(), and xxxLBInsertItem().

    00289 {
    00290     LONG cb;
    00291     HANDLE hMem;
    00292
    00293     /*
    00294      * Allocate memory for pointers to the strings.
    00295      */
    00296     cb = (plb->cMax + numItems) *
    00297             (plb->fHasStrings ? sizeof(LBItem)
    00298                               : (plb->fHasData ? sizeof(LBODItem)
    00299                                               : 0));
    00300
    00301     /*
    00302      * If multiple selection list box (MULTIPLESEL or EXTENDEDSEL), then
    00303      * allocate an extra byte per item to keep track of it's selection state.
    00304      */
    00305     if (plb->wMultiple != SINGLESEL) {
    00306         cb += (plb->cMax + numItems);
    00307     }
    00308
    00309     /*
    00310      * Extra bytes for each item so that we can store its height.
    00311      */
    00312     if (plb->OwnerDraw == OWNERDRAWVAR) {
    00313         cb += (plb->cMax + numItems);
    00314     }
    00315
    00316     /*
    00317      * Don't allocate more than 2G of memory
    00318      */
    00319     if (cb > MAXLONG)
    00320         return FALSE;
    00321
    00322     if (plb->rgpch == NULL) {
    00323         if ((plb->rgpch = UserLocalAlloc(HEAP_ZERO_MEMORY, (LONG)cb)) == NULL)
    00324             return FALSE;
    00325     } else {
    00326         if ((hMem = UserLocalReAlloc(plb->rgpch, (LONG)cb, HEAP_ZERO_MEMORY)) == NULL)
    00327             return FALSE;
    00328         plb->rgpch = hMem;
    00329     }
    00330
    00331     plb->cMax += numItems;
    00332
    00333     return TRUE;
    00334 }

UINT LBCalcAllocNeeded | ( | PLBIV | plb,
|  | INT | cItems
| ) |

Definition at line 1220 of file lboxctl1.c.

References tagLBIV::fHasData, tagLBIV::fHasStrings, tagLBIV::OwnerDraw, OWNERDRAWVAR, SINGLESEL, UINT, and tagLBIV::wMultiple.

Referenced by xxxLBSetCount().

    01223 {
    01224     UINT cb;
    01225
    01226     /*
    01227      * Allocate memory for pointers to the strings.
    01228      */
    01229     cb = cItems * (plb->fHasStrings ? sizeof(LBItem)
    01230                                     : (plb->fHasData ? sizeof(LBODItem)
    01231                                                     : 0));
    01232
    01233     /*
    01234      * If multiple selection list box (MULTIPLESEL or EXTENDEDSEL), then
    01235      * allocate an extra byte per item to keep track of it's selection state.
    01236      */
    01237     if (plb->wMultiple != SINGLESEL) {
    01238         cb += cItems;
    01239     }
    01240
    01241     /*
    01242      * Extra bytes for each item so that we can store its height.
    01243      */
    01244     if (plb->OwnerDraw == OWNERDRAWVAR) {
    01245         cb += cItems;
    01246     }
    01247
    01248     return cb;
    01249 }

LONG_PTR LBGetItemData | ( | PLBIV | plb,
|  | INT | sItem
| ) |

Definition at line 176 of file lboxctl1.c.

References tagLBIV::cMac, tagLBIV::fHasData, tagLBIV::fHasStrings, L, LBItem, LBODItem, lpLBODItem, and tagLBIV::rgpch.

Referenced by LBGetText(), ListBoxWndProcWorker(), xxxLBoxDeleteItem(), and xxxLBoxDrawItem().

    00179 {
    00180     LONG_PTR buffer;
    00181     LPBYTE lpItem;
    00182
    00183     if (sItem < 0 || sItem >= plb->cMac) {
    00184         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00185         return LB_ERR;
    00186     }
    00187
    00188     // No-data listboxes always return 0L
    00189     //
    00190     if (!plb->fHasData) {
    00191         return 0L;
    00192     }
    00193
    00194     lpItem = (plb->rgpch +
    00195             (sItem * (plb->fHasStrings ? sizeof(LBItem) : sizeof(LBODItem))));
    00196     buffer = (plb->fHasStrings ? ((lpLBItem)lpItem)->itemData : ((lpLBODItem)lpItem)->itemData);
    00197     return buffer;
    00198 }

INT LBGetText | ( | PLBIV | plb,
|  | BOOL | fLengthOnly,
|  | BOOL | fAnsi,
|  | INT | index,
|  | LPWSTR | lpbuffer
| ) |

Definition at line 214 of file lboxctl1.c.

References tagLBIV::cMac, FALSE, tagLBIV::fHasStrings, GetLpszItem(), INT, LBGetItemData(), tagLBIV::OwnerDraw, and RtlUnicodeToMultiByteSize().

Referenced by ListBoxWndProcWorker().

    00220 {
    00221     LPWSTR lpItemText;
    00222     INT cchText;
    00223
    00224     if (index < 0 || index >= plb->cMac) {
    00225         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00226         return LB_ERR;
    00227     }
    00228
    00229     if (!plb->fHasStrings && plb->OwnerDraw) {
    00230
    00231         /*
    00232          * Owner draw without strings so we must copy the app supplied DWORD
    00233          * value.
    00234          */
    00235         cchText = sizeof(ULONG_PTR);
    00236
    00237         if (!fLengthOnly) {
    00238             LONG_PTR UNALIGNED *p = (LONG_PTR UNALIGNED *)lpbuffer;
    00239             *p = LBGetItemData(plb, index);
    00240         }
    00241     } else {
    00242         lpItemText = GetLpszItem(plb, index);
    00243         if (!lpItemText)
    00244             return LB_ERR;
    00245
    00246         /*
    00247          * These are strings so we are copying the text and we must include
    00248          * the terminating 0 when doing the RtlMoveMemory.
    00249          */
    00250         cchText = wcslen(lpItemText);
    00251
    00252         if (fLengthOnly) {
    00253             if (fAnsi)
    00254                 RtlUnicodeToMultiByteSize(&cchText, lpItemText, cchText*sizeof(WCHAR));
    00255         } else {
    00256             if (fAnsi) {
    00257 #ifdef FE_SB // LBGetText()
    00258                 cchText = WCSToMB(lpItemText, cchText+1, &((LPSTR)lpbuffer), (cchText+1)*sizeof(WORD), FALSE);
    00259                 /*
    00260                  * Here.. cchText contains null-terminate char, subtract it... Because, we pass cchText+1 to
    00261                  * above Unicode->Ansi convertsion to make sure the string is terminated with null.
    00262                  */
    00263                 cchText--;
    00264 #else
    00265                 WCSToMB(lpItemText, cchText+1, &((LPSTR)lpbuffer), cchText+1, FALSE);
    00266 #endif // FE_SB
    00267             } else {
    00268                 RtlCopyMemory(lpbuffer, lpItemText, (cchText+1)*sizeof(WCHAR));
    00269             }
    00270         }
    00271
    00272     }
    00273
    00274     return cchText;
    00275 }

INT LBlstrcmpi | ( | LPWSTR | lpStr1,
|  | LPWSTR | lpStr2,
|  | DWORD | dwLocaleId
| ) |

Definition at line 671 of file lboxctl1.c.

References GetClientInfo, INT, and TIF_16BIT.

Referenced by xxxLBBinarySearchString().

    00675 {
    00676
    00677     /*
    00678      * NOTE: This function is written so as to reduce the number of calls
    00679      * made to the costly IsCharAlphaNumeric() function because that might
    00680      * load a language module; It 'traps' the most frequently occurring cases
    00681      * like both strings starting with '[' or both strings NOT starting with '['
    00682      * first and only in abosolutely necessary cases calls IsCharAlphaNumeric();
    00683      */
    00684     if (*lpStr1 == TEXT('[')) {
    00685         if (*lpStr2 == TEXT('[')) {
    00686             goto LBL_End;
    00687         }
    00688         if (IsCharAlphaNumeric(*lpStr2)) {
    00689             return 1;
    00690         }
    00691     }
    00692
    00693     if ((*lpStr2 == TEXT('[')) && IsCharAlphaNumeric(*lpStr1)) {
    00694         return -1;
    00695     }
    00696
    00697 LBL_End:
    00698     if ((GetClientInfo()->dwTIFlags & TIF_16BIT) &&
    00699         dwLocaleId == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) {
    00700         /*
    00701          * This is how Windows95 does, bug #4199
    00702          */
    00703         return (*pfnWowIlstrcmp)(lpStr1, lpStr2);
    00704     }
    00705     return (INT)CompareStringW((LCID)dwLocaleId, NORM_IGNORECASE,
    00706             lpStr1, -1, lpStr2, -1 ) - 2;
    00707 }

INT xxxLBBinarySearchString | ( | PLBIV | plb,
|  | LPWSTR | lpstr
| ) |

Definition at line 722 of file lboxctl1.c.

References BYTE, CheckLock, tagLBIV::cMac, tagLBIV::dwLocaleId, FAR, tagLBIV::fHasStrings, tagLBIV::hStrings, HW, HWq, INT, LBlstrcmpi(), max, tagLBIV::rgpch, SendMessage(), tagWND::spmenu, tagLBIV::spwnd, tagLBIV::spwndParent, ThreadLock, ThreadUnlock, and UINT.

Referenced by xxxLBInsertItem().

    00725 {
    00726     BYTE *FAR *lprgpch;
    00727     INT sortResult;
    00728     COMPAREITEMSTRUCT cis;
    00729     LPWSTR pszLBBase;
    00730     LPWSTR pszLB;
    00731     INT itemhigh;
    00732     INT itemnew = 0;
    00733     INT itemlow = 0;
    00734     TL tlpwndParent;
    00735
    00736     CheckLock(plb->spwnd);
    00737
    00738     if (!plb->cMac)
    00739         return 0;
    00740
    00741     lprgpch = (BYTE *FAR *)(plb->rgpch);
    00742     if (plb->fHasStrings) {
    00743         pszLBBase = plb->hStrings;
    00744     }
    00745
    00746     itemhigh = plb->cMac - 1;
    00747     while (itemlow <= itemhigh) {
    00748         itemnew = (itemhigh + itemlow) / 2;
    00749
    00750         if (plb->fHasStrings) {
    00751
    00752             /*
    00753              * Searching for string matches.
    00754              */
    00755             pszLB = (LPWSTR)((LPSTR)pszLBBase + ((lpLBItem)lprgpch)[itemnew].offsz);
    00756             sortResult = LBlstrcmpi(pszLB, lpstr, plb->dwLocaleId);
    00757         } else {
    00758
    00759             /*
    00760              * Send compare item messages to the parent for sorting
    00761              */
    00762             cis.CtlType = ODT_LISTBOX;
    00763             cis.CtlID = PtrToUlong(plb->spwnd->spmenu);
    00764             cis.hwndItem = HWq(plb->spwnd);
    00765             cis.itemID1 = itemnew;
    00766             cis.itemData1 = ((lpLBODItem)lprgpch)[itemnew].itemData;
    00767             cis.itemID2 = (UINT)-1;
    00768             cis.itemData2 = (ULONG_PTR)lpstr;
    00769             cis.dwLocaleId = plb->dwLocaleId;
    00770             ThreadLock(plb->spwndParent, &tlpwndParent);
    00771             sortResult = (INT)SendMessage(HW(plb->spwndParent), WM_COMPAREITEM,
    00772                     cis.CtlID, (LPARAM)&cis);
    00773             ThreadUnlock(&tlpwndParent);
    00774         }
    00775
    00776         if (sortResult < 0) {
    00777             itemlow = itemnew + 1;
    00778         } else if (sortResult > 0) {
    00779             itemhigh = itemnew - 1;
    00780         } else {
    00781             itemlow = itemnew;
    00782             goto FoundIt;
    00783         }
    00784     }
    00785
    00786 FoundIt:
    00787
    00788     return max(0, itemlow);
    00789 }

LONG xxxLBInitStorage | ( | PLBIV | plb,
|  | BOOL | fAnsi,
|  | INT | cItems,
|  | INT | cb
| ) |

Definition at line 342 of file lboxctl1.c.

References tagLBIV::cchStrings, tagLBIV::cMac, tagLBIV::cMax, tagLBIV::fHasStrings, GrowMem(), tagLBIV::hStrings, tagLBIV::ichAlloc, INT, UserLocalReAlloc, and xxxNotifyOwner().

Referenced by ListBoxWndProcWorker().

    00343 {
    00344     HANDLE hMem;
    00345     INT    cbChunk;
    00346
    00347     /*
    00348      * if the app is talking ANSI, then adjust for the worst case in unicode
    00349      * where each single ansi byte translates to one 16 bit unicode value
    00350      */
    00351     if (fAnsi) {
    00352         cb *= sizeof(WCHAR) ;
    00353     } /* if */
    00354
    00355     /*
    00356      * Fail if either of the parameters look bad.
    00357      */
    00358     if ((cItems < 0) || (cb < 0)) {
    00359         xxxNotifyOwner(plb, LBN_ERRSPACE);
    00360         return LB_ERRSPACE;
    00361     } /* if */
    00362
    00363     /*
    00364      * try to grow the pointer array (if necessary) accounting for the free space
    00365      * already available.
    00366      */
    00367     cItems -= plb->cMax - plb->cMac ;
    00368     if ((cItems > 0) && !GrowMem(plb, cItems)) {
    00369         xxxNotifyOwner(plb, LBN_ERRSPACE);
    00370         return LB_ERRSPACE;
    00371     } /* if */
    00372
    00373     /*
    00374      * now grow the string space if necessary
    00375      */
    00376     if (plb->fHasStrings) {
    00377         if ((cbChunk = (plb->ichAlloc + cb)) > plb->cchStrings) {
    00378
    00379             /*
    00380              * Round up to the nearest 256 byte chunk.
    00381              */
    00382             cbChunk = (cbChunk & ~0xff) + 0x100;
    00383             if (!(hMem = UserLocalReAlloc(plb->hStrings, (LONG)cbChunk, 0))) {
    00384                 xxxNotifyOwner(plb, LBN_ERRSPACE);
    00385                 return LB_ERRSPACE;
    00386             }
    00387             plb->hStrings = hMem;
    00388             plb->cchStrings = cbChunk;
    00389         } /* if */
    00390     } /* if */
    00391
    00392     /*
    00393      * return the number of items that can be stored
    00394      */
    00395     return plb->cMax ;
    00396 }

INT xxxLBInsertItem | ( | PLBIV | plb,
|  | LPWSTR | lpsz,
|  | INT | index,
|  | UINT | wFlags
| ) |

Definition at line 407 of file lboxctl1.c.

References BYTE, tagLBIV::cchStrings, CharLowerBuffW(), CharUpperBuffW(), CheckLock, CITEMSALLOC, tagLBIV::cMac, tagLBIV::cMax, FALSE, tagLBIV::fFromInsert, tagLBIV::fHasData, tagLBIV::fHasStrings, tagLBIV::fHorzBar, tagLBIV::fMultiColumn, tagLBIV::fRightAlign, tagLBIV::fSort, FWINABLE, gpsi, GrowMem(), tagLBIV::hStrings, HW, tagLBIV::ichAlloc, INT, tagLBIV::iSel, tagLBIV::iSelBase, tagLBItem::itemData, tagLBODItem::itemData, tagLBIV::iTop, L, LBEvent(), LBI_ADD, LBSetCItemFullMax(), LOWERCASE, MSGFLAG_SPECIAL_THUNK, tagLBItem::offsz, tagLBIV::OwnerDraw, OWNERDRAWVAR, PBYTE, tagLBIV::rgpch, SendMessage(), SINGLESEL, tagWND::spmenu, tagLBIV::spwnd, tagLBIV::spwndParent, ThreadLock, ThreadUnlock, TRUE, UINT, UPPERCASE, UserLocalAlloc, UserLocalReAlloc, tagLBIV::wMultiple, xxxCheckRedraw(), xxxLBBinarySearchString(), xxxLBoxCtlHScroll(), xxxLBShowHideScrollBars(), and xxxNotifyOwner().

    00417 {
    00418     MEASUREITEMSTRUCT measureItemStruct;
    00419     INT cbString;
    00420     INT cbChunk;
    00421     PBYTE lp;
    00422     PBYTE lpT;
    00423     PBYTE lpHeightStart;
    00424     LONG cbItem;     /* sizeof the Item in rgpch */
    00425     HANDLE hMem;
    00426     TL tlpwndParent;
    00427
    00428     CheckLock(plb->spwnd);
    00429
    00430     if (wFlags & LBI_ADD)
    00431         index = (plb->fSort) ? xxxLBBinarySearchString(plb, lpsz) : -1;
    00432
    00433     if (!plb->rgpch) {
    00434         if (index != 0 && index != -1) {
    00435             RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00436             return LB_ERR;
    00437         }
    00438
    00439         plb->iSel = -1;
    00440         plb->iSelBase = 0;
    00441         plb->cMax = 0;
    00442         plb->cMac = 0;
    00443         plb->iTop = 0;
    00444         plb->rgpch = UserLocalAlloc(HEAP_ZERO_MEMORY, 0L);
    00445         if (!plb->rgpch)
    00446             return LB_ERR;
    00447     }
    00448
    00449     if (index == -1) {
    00450         index = plb->cMac;
    00451     }
    00452
    00453     if (index > plb->cMac || plb->cMac >= MAXLONG) {
    00454         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00455         return LB_ERR;
    00456     }
    00457
    00458     if (plb->fHasStrings) {
    00459
    00460         /*
    00461          * we must store the string in the hStrings memory block.
    00462          */
    00463         cbString = (wcslen(lpsz) + 1)*sizeof(WCHAR);  /* include 0 terminator */
    00464
    00465         if ((cbChunk = (plb->ichAlloc + cbString)) > plb->cchStrings) {
    00466
    00467             /*
    00468              * Round up to the nearest 256 byte chunk.
    00469              */
    00470             cbChunk = (cbChunk & ~0xff) + 0x100;
    00471             if (!(hMem = UserLocalReAlloc(plb->hStrings, (LONG)cbChunk,
    00472                     0))) {
    00473                 xxxNotifyOwner(plb, LBN_ERRSPACE);
    00474                 return LB_ERRSPACE;
    00475             }
    00476             plb->hStrings = hMem;
    00477
    00478             plb->cchStrings = cbChunk;
    00479         }
    00480
    00481         /*
    00482          * Note difference between Win 95 code with placement of new string
    00483          */
    00484         if (wFlags & UPPERCASE)
    00485             CharUpperBuffW((LPWSTR)lpsz, cbString / sizeof(WCHAR));
    00486         else if (wFlags & LOWERCASE)
    00487             CharLowerBuffW((LPWSTR)lpsz, cbString / sizeof(WCHAR));
    00488
    00489         lp = (PBYTE)(plb->hStrings);
    00490         RtlMoveMemory(lp + plb->ichAlloc, lpsz, cbString);
    00491     }
    00492
    00493     /*
    00494      * Now expand the pointer array.
    00495      */
    00496     if (plb->cMac >= plb->cMax) {
    00497         if (!GrowMem(plb, CITEMSALLOC)) {
    00498             xxxNotifyOwner(plb, LBN_ERRSPACE);
    00499             return LB_ERRSPACE;
    00500         }
    00501     }
    00502
    00503     lpHeightStart = lpT = lp = plb->rgpch;
    00504
    00505     /*
    00506      * Now calculate how much room we must make for the string pointer (lpsz).
    00507      * If we are ownerdraw without LBS_HASSTRINGS, then a single DWORD
    00508      * (LBODItem.itemData) stored for each item, but if we have strings with
    00509      * each item then a LONG string offset (LBItem.offsz) is also stored.
    00510      */
    00511     cbItem = (plb->fHasStrings ? sizeof(LBItem)
    00512                                : (plb->fHasData ? sizeof(LBODItem):0));
    00513     cbChunk = (plb->cMac - index) * cbItem;
    00514
    00515     if (plb->wMultiple != SINGLESEL) {
    00516
    00517         /*
    00518          * Extra bytes were allocated for selection flag for each item
    00519          */
    00520         cbChunk += plb->cMac;
    00521     }
    00522
    00523     if (plb->OwnerDraw == OWNERDRAWVAR) {
    00524
    00525         /*
    00526          * Extra bytes were allocated for each item's height
    00527          */
    00528         cbChunk += plb->cMac;
    00529     }
    00530
    00531     /*
    00532      * First, make room for the 2 byte pointer to the string or the 4 byte app
    00533      * supplied value.
    00534      */
    00535     lpT += (index * cbItem);
    00536     RtlMoveMemory(lpT + cbItem, lpT, cbChunk);
    00537     if (!plb->fHasStrings && plb->OwnerDraw) {
    00538         if (plb->fHasData) {
    00539             /*
    00540              * Ownerdraw so just save the DWORD value
    00541              */
    00542             lpLBODItem p = (lpLBODItem)lpT;
    00543             p->itemData = (ULONG_PTR)lpsz;
    00544         }
    00545     } else {
    00546         lpLBItem p = ((lpLBItem)lpT);
    00547
    00548         /*
    00549          * Save the start of the string.  Let the item data field be 0
    00550          */
    00551         p->offsz = (LONG)(plb->ichAlloc);
    00552         p->itemData = 0;
    00553         plb->ichAlloc += cbString;
    00554     }
    00555
    00556     /*
    00557      * Now if Multiple Selection lbox, we have to insert a selection status
    00558      * byte.  If var height ownerdraw, then we also have to move up the height
    00559      * bytes.
    00560      */
    00561     if (plb->wMultiple != SINGLESEL) {
    00562         lpT = lp + ((plb->cMac + 1) * cbItem) + index;
    00563         RtlMoveMemory(lpT + 1, lpT, plb->cMac - index +
    00564                 (plb->OwnerDraw == OWNERDRAWVAR ? plb->cMac : 0));
    00565         *lpT = 0;  /* fSelected = FALSE */
    00566     }
    00567
    00568     /*
    00569      * Increment count of items in the listbox now before we send a message to
    00570      * the app.
    00571      */
    00572     plb->cMac++;
    00573
    00574     /*
    00575      * If varheight ownerdraw, we much insert an extra byte for the item's
    00576      * height.
    00577      */
    00578     if (plb->OwnerDraw == OWNERDRAWVAR) {
    00579
    00580         /*
    00581          * Variable height owner draw so we need to get the height of each item.
    00582          */
    00583         lpHeightStart += (plb->cMac * cbItem) + index +
    00584                 (plb->wMultiple ? plb->cMac : 0);
    00585
    00586         RtlMoveMemory(lpHeightStart + 1, lpHeightStart, plb->cMac - 1 - index);
    00587
    00588         /*
    00589          * Query for item height only if we are var height owner draw.
    00590          */
    00591         measureItemStruct.CtlType = ODT_LISTBOX;
    00592         measureItemStruct.CtlID = PtrToUlong(plb->spwnd->spmenu);
    00593         measureItemStruct.itemID = index;
    00594
    00595         /*
    00596          * System font height is default height
    00597          */
    00598         measureItemStruct.itemHeight = (UINT)gpsi->cySysFontChar;
    00599         measureItemStruct.itemData = (ULONG_PTR)lpsz;
    00600
    00601         /*
    00602          * If "has strings" then add the special thunk bit so the client data
    00603          * will be thunked to a client side address.  LB_DIR sends a string
    00604          * even if the listbox is not HASSTRINGS so we need to special
    00605          * thunk this case.  HP Dashboard for windows send LB_DIR to a non
    00606          * HASSTRINGS listbox needs the server string converted to client.
    00607          * WOW needs to know about this situation as well so we mark the
    00608          * previously uninitialized itemWidth as FLAT.
    00609          */
    00610         if (plb->fHasStrings || (wFlags & MSGFLAG_SPECIAL_THUNK)) {
    00611             measureItemStruct.itemWidth = MIFLAG_FLAT;
    00612         }
    00613
    00614         ThreadLock(plb->spwndParent, &tlpwndParent);
    00615         SendMessage(HW(plb->spwndParent),
    00616                 WM_MEASUREITEM,
    00617                 measureItemStruct.CtlID,
    00618                 (LPARAM)&measureItemStruct);
    00619         ThreadUnlock(&tlpwndParent);
    00620         *lpHeightStart = (BYTE)measureItemStruct.itemHeight;
    00621     }
    00622
    00623
    00624     /*
    00625      * If the item was inserted above the current selection then move
    00626      * the selection down one as well.
    00627      */
    00628     if ((plb->wMultiple == SINGLESEL) && (plb->iSel >= index))
    00629         plb->iSel++;
    00630
    00631     if (plb->OwnerDraw == OWNERDRAWVAR)
    00632         LBSetCItemFullMax(plb);
    00633
    00634     /*
    00635      * Check if scroll bars need to be shown/hidden
    00636      */
    00637     plb->fFromInsert = TRUE;
    00638     xxxLBShowHideScrollBars(plb);
    00639     if (plb->fHorzBar && plb->fRightAlign && !(plb->fMultiColumn || plb->OwnerDraw)) {
    00640         /*
    00641          * origin to right
    00642          */
    00643         xxxLBoxCtlHScroll(plb, SB_BOTTOM, 0);
    00644     }
    00645     plb->fFromInsert = FALSE;
    00646
    00647     xxxCheckRedraw(plb, TRUE, index);
    00648
    00649     if (FWINABLE()) {
    00650         LBEvent(plb, EVENT_OBJECT_CREATE, index);
    00651     }
    00652
    00653     return index;
    00654 }

INT xxxLBoxCtlDelete | ( | PLBIV | plb,
|  | INT | sItem
| ) |

Definition at line 842 of file lboxctl1.c.

References CheckLock, tagLBIV::cMac, EXTENDEDSEL, FALSE, tagLBIV::fFromInsert, tagLBIV::fHasData, tagLBIV::fHasStrings, FWINABLE, tagLBIV::hStrings, tagLBIV::ichAlloc, tagLBIV::iMouseDown, INT, tagLBIV::iSel, tagLBIV::iSelBase, tagLBIV::iTop, LBEvent(), LBGetItemRect(), LBSetCItemFullMax(), min, NULL, tagLBItem::offsz, tagLBIV::OwnerDraw, OWNERDRAWVAR, PBYTE, tagLBIV::pcbox, tagLBIV::rgpch, SendMessageWorker(), SINGLESEL, tagLBIV::spwnd, tagCBox::spwnd, TestWF, ThreadLock, ThreadUnlock, TRUE, WFWIN40COMPAT, tagLBIV::wMultiple, xxxCBInternalUpdateEditWindow(), xxxCheckRedraw(), xxxInsureVisible(), xxxLBInvalidateRect(), xxxLBoxDeleteItem(), and xxxLBShowHideScrollBars().

Referenced by ListBoxWndProcWorker().

    00845 {
    00846     LONG cb;
    00847     LPBYTE lp;
    00848     LPBYTE lpT;
    00849     RECT rc;
    00850     int cbItem;    /* size of Item in rgpch */
    00851     LPWSTR lpString;
    00852     PBYTE pbStrings;
    00853     INT cbStringLen;
    00854     LPBYTE itemNumbers;
    00855     INT sTmp;
    00856     TL tlpwnd;
    00857
    00858     CheckLock(plb->spwnd);
    00859
    00860     if (sItem < 0 || sItem >= plb->cMac) {
    00861         RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
    00862         return LB_ERR;
    00863     }
    00864
    00865     if (FWINABLE()) {
    00866         LBEvent(plb, EVENT_OBJECT_DESTROY, sItem);
    00867     }
    00868
    00869     if (plb->cMac == 1) {
    00870
    00871         /*
    00872          * When the item count is 0, we send a resetcontent message so that we
    00873          * can reclaim our string space this way.
    00874          */
    00875         SendMessageWorker(plb->spwnd, LB_RESETCONTENT, 0, 0, FALSE);
    00876         goto FinishUpDelete;
    00877     }
    00878
    00879     /*
    00880      * Get the rectangle associated with the last item in the listbox.  If it is
    00881      * visible, we need to invalidate it.  When we delete an item, everything
    00882      * scrolls up to replace the item deleted so we must make sure we erase the
    00883      * old image of the last item in the listbox.
    00884      */
    00885     if (LBGetItemRect(plb, (INT)(plb->cMac - 1), &rc)) {
    00886         xxxLBInvalidateRect(plb, &rc, TRUE);
    00887     }
    00888
    00889     // 3.1 and earlier used to only send WM_DELETEITEMs if it was an ownerdraw
    00890     // listbox.  4.0 and above will send WM_DELETEITEMs for every item that has
    00891     // nonzero item data.
    00892     if (TestWF(plb->spwnd, WFWIN40COMPAT) || (plb->OwnerDraw && plb->fHasData)) {
    00893         xxxLBoxDeleteItem(plb, sItem);
    00894     }
    00895
    00896     plb->cMac--;
    00897
    00898     cbItem = (plb->fHasStrings ? sizeof(LBItem)
    00899                                : (plb->fHasData ? sizeof(LBODItem): 0));
    00900     cb = ((plb->cMac - sItem) * cbItem);
    00901
    00902     /*
    00903      * Byte for the selection status of the item.
    00904      */
    00905     if (plb->wMultiple != SINGLESEL) {
    00906         cb += (plb->cMac + 1);
    00907     }
    00908
    00909     if (plb->OwnerDraw == OWNERDRAWVAR) {
    00910
    00911         /*
    00912          * One byte for the height of the item.
    00913          */
    00914         cb += (plb->cMac + 1);
    00915     }
    00916
    00917     /*
    00918      * Might be nodata and singlesel, for instance.
    00919      * but what out for the case where cItem == cMac (and cb == 0).
    00920      */
    00921     if ((cb != 0) || plb->fHasStrings) {
    00922         lp = plb->rgpch;
    00923
    00924         lpT = (lp + (sItem * cbItem));
    00925
    00926         if (plb->fHasStrings) {
    00927             /*
    00928              * If we has strings with each item, then we want to compact the string
    00929              * heap so that we can recover the space occupied by the string of the
    00930              * deleted item.
    00931              */
    00932             /*
    00933              * Get the string which we will be deleting
    00934              */
    00935             pbStrings = (PBYTE)(plb->hStrings);
    00936             lpString = (LPTSTR)(pbStrings + ((lpLBItem)lpT)->offsz);
    00937             cbStringLen = (wcslen(lpString) + 1) * sizeof(WCHAR);  /* include null terminator */
    00938
    00939             /*
    00940              * Now compact the string array
    00941              */
    00942             plb->ichAlloc = plb->ichAlloc - cbStringLen;
    00943
    00944             RtlMoveMemory(lpString, (PBYTE)lpString + cbStringLen,
    00945                     plb->ichAlloc + (pbStrings - (LPBYTE)lpString));
    00946
    00947             /*
    00948              * We have to update the string pointers in plb->rgpch since all the
    00949              * string after the deleted string have been moved down stringLength
    00950              * bytes.  Note that we have to explicitly check all items in the list
    00951              * box if the string was allocated after the deleted item since the
    00952              * LB_SORT style allows a lower item number to have a string allocated
    00953              * at the end of the string heap for example.
    00954              */
    00955             itemNumbers = lp;
    00956             for (sTmp = 0; sTmp <= plb->cMac; sTmp++) {
    00957                 lpLBItem p =(lpLBItem)itemNumbers;
    00958                 if ( (LPTSTR)(p->offsz + pbStrings) > lpString ) {
    00959                     p->offsz -= cbStringLen;
    00960                 }
    00961                 p++;
    00962                 itemNumbers=(LPBYTE)p;
    00963             }
    00964         }
    00965
    00966         /*
    00967          * Now compact the pointers to the strings (or the long app supplied values
    00968          * if ownerdraw without strings).
    00969          */
    00970         RtlMoveMemory(lpT, lpT + cbItem, cb);
    00971
    00972         /*
    00973          * Compress the multiselection bytes
    00974          */
    00975         if (plb->wMultiple != SINGLESEL) {
    00976             lpT = (lp + (plb->cMac * cbItem) + sItem);
    00977             RtlMoveMemory(lpT, lpT + 1, plb->cMac - sItem +
    00978                     (plb->OwnerDraw == OWNERDRAWVAR ? plb->cMac + 1 : 0));
    00979         }
    00980
    00981         if (plb->OwnerDraw == OWNERDRAWVAR) {
    00982             /*
    00983              * Compress the height bytes
    00984              */
    00985             lpT = (lp + (plb->cMac * cbItem) + (plb->wMultiple ? plb->cMac : 0)
    00986                     + sItem);
    00987             RtlMoveMemory(lpT, lpT + 1, plb->cMac - sItem);
    00988         }
    00989
    00990     }
    00991
    00992     if (plb->wMultiple == SINGLESEL) {
    00993         if (plb->iSel == sItem) {
    00994             plb->iSel = -1;
    00995
    00996             if (plb->pcbox != NULL) {
    00997                 ThreadLock(plb->pcbox->spwnd, &tlpwnd);
    00998                 xxxCBInternalUpdateEditWindow(plb->pcbox, NULL);
    00999                 ThreadUnlock(&tlpwnd);
    01000             }
    01001         } else if (plb->iSel > sItem)
    01002             plb->iSel--;
    01003     }
    01004
    01005     if ((plb->iMouseDown != -1) && (sItem <= plb->iMouseDown))
    01006         plb->iMouseDown = -1;
    01007
    01008     if (plb->iSelBase && sItem == plb->iSelBase)
    01009         plb->iSelBase--;
    01010
    01011     if (plb->cMac) {
    01012         plb->iSelBase = min(plb->iSelBase, plb->cMac - 1);
    01013     } else {
    01014         plb->iSelBase = 0;
    01015     }
    01016
    01017     if ((plb->wMultiple == EXTENDEDSEL) && (plb->iSel == -1))
    01018         plb->iSel = plb->iSelBase;
    01019
    01020     if (plb->OwnerDraw == OWNERDRAWVAR)
    01021         LBSetCItemFullMax(plb);
    01022
    01023     /*
    01024      * We always set a new iTop.  The iTop won't change if it doesn't need to
    01025      * but it will change if:  1.  The iTop was deleted or 2.  We need to change
    01026      * the iTop so that we fill the listbox.
    01027      */
    01028     xxxInsureVisible(plb, plb->iTop, FALSE);
    01029
    01030 FinishUpDelete:
    01031
    01032     /*
    01033      * Check if scroll bars need to be shown/hidden
    01034      */
    01035     plb->fFromInsert = TRUE;
    01036     xxxLBShowHideScrollBars(plb);
    01037     plb->fFromInsert = FALSE;
    01038
    01039     xxxCheckRedraw(plb, TRUE, sItem);
    01040     xxxInsureVisible(plb, plb->iSelBase, FALSE);
    01041
    01042     return plb->cMac;
    01043 }

void xxxLBoxDeleteItem | ( | PLBIV | plb,
|  | INT | sItem
| ) |

Definition at line 1053 of file lboxctl1.c.

References CheckLock, tagLBIV::fHasData, HWq, LBGetItemData(), NULL, SendMessage(), tagWND::spmenu, tagLBIV::spwnd, tagLBIV::spwndParent, ThreadLock, and ThreadUnlock.

Referenced by xxxLBoxCtlDelete(), and xxxLBoxDoDeleteItems().

    01056 {
    01057     DELETEITEMSTRUCT dis;
    01058     TL tlpwndParent;
    01059
    01060     CheckLock(plb->spwnd);
    01061     if (plb->spwnd == NULL)
    01062         return;
    01063
    01064     /*
    01065      * Bug 262122 - joejo
    01066      * No need to send message if no data!
    01067      */
    01068     if (!plb->fHasData) {
    01069         return;
    01070     }
    01071
    01072     /*
    01073      * Fill the DELETEITEMSTRUCT
    01074      */
    01075     dis.CtlType = ODT_LISTBOX;
    01076     dis.CtlID = PtrToUlong(plb->spwnd->spmenu);
    01077     dis.itemID = sItem;
    01078     dis.hwndItem = HWq(plb->spwnd);
    01079
    01080     /*
    01081      * Bug 262122 - joejo
    01082      * Fixed in 93 so that ItemData was passed. For some reason, not
    01083      * merged in.
    01084      */
    01085     dis.itemData = LBGetItemData(plb, sItem);
    01086
    01087     if (plb->spwndParent != NULL) {
    01088         ThreadLock(plb->spwndParent, &tlpwndParent);
    01089         SendMessage(HWq(plb->spwndParent), WM_DELETEITEM, dis.CtlID,
    01090                 (LPARAM)&dis);
    01091         ThreadUnlock(&tlpwndParent);
    01092     }
    01093 }

BOOL xxxLBResetContent | ( | PLBIV | plb | ) |

Definition at line 797 of file lboxctl1.c.

References BOOL, tagLBIV::cMac, tagLBIV::cMax, FALSE, tagLBIV::hStrings, HWq, tagLBIV::iLastSelection, InitHStrings(), tagLBIV::iSel, tagLBIV::iSelBase, IsVisible(), tagLBIV::iTop, NtUserInvalidateRect(), NULL, tagLBIV::rgpch, tagLBIV::spwnd, TestWF, TRUE, UserLocalFree, WFWIN31COMPAT, tagLBIV::xOrigin, xxxCheckRedraw(), xxxLBoxDoDeleteItems(), and xxxLBShowHideScrollBars().

Referenced by ListBoxWndProcWorker().

    00799 {
    00800     if (!plb->cMac)
    00801         return TRUE;
    00802
    00803     xxxLBoxDoDeleteItems(plb);
    00804
    00805     if (plb->rgpch != NULL) {
    00806         UserLocalFree(plb->rgpch);
    00807         plb->rgpch = NULL;
    00808     }
    00809
    00810     if (plb->hStrings != NULL) {
    00811         UserLocalFree(plb->hStrings);
    00812         plb->hStrings = NULL;
    00813     }
    00814
    00815     InitHStrings(plb);
    00816
    00817     if (TestWF(plb->spwnd, WFWIN31COMPAT))
    00818         xxxCheckRedraw(plb, FALSE, 0);
    00819     else if (IsVisible(plb->spwnd))
    00820         NtUserInvalidateRect(HWq(plb->spwnd), NULL, TRUE);
    00821
    00822     plb->iSelBase =  0;
    00823     plb->iTop =  0;
    00824     plb->cMac =  0;
    00825     plb->cMax =  0;
    00826     plb->xOrigin =  0;
    00827     plb->iLastSelection =  0;
    00828     plb->iSel = -1;
    00829
    00830     xxxLBShowHideScrollBars(plb);
    00831     return TRUE;
    00832 }

INT xxxLBSetCount | ( | PLBIV | plb,
|  | INT | cItems
| ) |

Definition at line 1107 of file lboxctl1.c.

References BOOL, CheckLock, CITEMSALLOC, tagLBIV::cMac, tagLBIV::cMax, FALSE, tagLBIV::fHasData, tagLBIV::fHasStrings, tagLBIV::fRedraw, tagLBIV::iLastSelection, INT, tagLBIV::iSel, tagLBIV::iSelBase, tagLBIV::iTop, L, LBCalcAllocNeeded(), NULL, tagLBIV::rgpch, SendMessageWorker(), tagLBIV::spwnd, TRUE, UINT, UserLocalAlloc, UserLocalReAlloc, tagLBIV::xOrigin, xxxLBInvalidateRect(), xxxLBSetRedraw(), xxxLBShowHideScrollBars(), and xxxNotifyOwner().

Referenced by ListBoxWndProcWorker().

    01110 {
    01111     UINT  cbRequired;
    01112     BOOL    fRedraw;
    01113
    01114     CheckLock(plb->spwnd);
    01115
    01116     /*
    01117      * SetCount is only valid on lazy-eval ("nodata") listboxes.
    01118      * All other lboxen must add their items one at a time, although
    01119      * they may SetCount(0) via RESETCONTENT.
    01120      */
    01121     if (plb->fHasStrings || plb->fHasData) {
    01122         RIPERR0(ERROR_SETCOUNT_ON_BAD_LB, RIP_VERBOSE, "");
    01123         return LB_ERR;
    01124     }
    01125
    01126     if (cItems == 0) {
    01127         SendMessageWorker(plb->spwnd, LB_RESETCONTENT, 0, 0, FALSE);
    01128         return 0;
    01129     }
    01130
    01131     // If redraw isn't turned off, turn it off now
    01132     if (fRedraw = plb->fRedraw)
    01133         xxxLBSetRedraw(plb, FALSE);
    01134
    01135     cbRequired = LBCalcAllocNeeded(plb, cItems);
    01136
    01137     /*
    01138      * Reset selection and position
    01139      */
    01140     plb->iSelBase = 0;
    01141     plb->iTop = 0;
    01142     plb->cMax = 0;
    01143     plb->xOrigin = 0;
    01144     plb->iLastSelection = 0;
    01145     plb->iSel = -1;
    01146
    01147     if (cbRequired != 0) { // Only if record instance data required
    01148
    01149         /*
    01150          * If listbox was previously empty, prepare for the
    01151          * realloc-based alloc strategy ahead.
    01152          */
    01153         if (plb->rgpch == NULL) {
    01154             plb->rgpch = UserLocalAlloc(HEAP_ZERO_MEMORY, 0L);
    01155             plb->cMax = 0;
    01156
    01157             if (plb->rgpch == NULL) {
    01158                 xxxNotifyOwner(plb, LBN_ERRSPACE);
    01159                 return LB_ERRSPACE;
    01160             }
    01161         }
    01162
    01163         /*
    01164          * rgpch might not have enough room for the new record instance
    01165          * data, so check and realloc as necessary.
    01166          */
    01167         if (cItems >= plb->cMax) {
    01168             INT    cMaxNew;
    01169             UINT   cbNew;
    01170             HANDLE hmemNew;
    01171
    01172             /*
    01173              * Since GrowMem presumes a one-item-at-a-time add schema,
    01174              * SetCount can't use it.  Too bad.
    01175              */
    01176             cMaxNew = cItems+CITEMSALLOC;
    01177             cbNew = LBCalcAllocNeeded(plb, cMaxNew);
    01178             hmemNew = UserLocalReAlloc(plb->rgpch, cbNew, HEAP_ZERO_MEMORY);
    01179
    01180             if (hmemNew == NULL) {
    01181                 xxxNotifyOwner(plb, LBN_ERRSPACE);
    01182                 return LB_ERRSPACE;
    01183             }
    01184
    01185             plb->rgpch = hmemNew;
    01186             plb->cMax = cMaxNew;
    01187         }
    01188
    01189         /*
    01190          * Reset the item instance data (multisel annotations)
    01191          */
    01192         RtlZeroMemory(plb->rgpch, cbRequired);
    01193     }
    01194
    01195     plb->cMac = cItems;
    01196
    01197     // Turn redraw back on
    01198     if (fRedraw)
    01199         xxxLBSetRedraw(plb, TRUE);
    01200
    01201     xxxLBInvalidateRect(plb, NULL, TRUE);
    01202 // Not In Chicago -- FritzS
    01203 //    NtUserSetScrollPos(plb->spwnd, SB_HORZ, 0, plb->fRedraw);
    01204 //    NtUserSetScrollPos(plb->spwnd, SB_VERT, 0, plb->fRedraw);
    01205     xxxLBShowHideScrollBars(plb); // takes care of fRedraw
    01206
    01207     return 0;
    01208 }

void xxxLBShowHideScrollBars | ( | PLBIV | plb | ) |

Definition at line 125 of file lboxctl1.c.

References BOOL, FALSE, tagLBIV::fFromInsert, tagLBIV::fHorzBar, tagLBIV::fMultiColumn, tagLBIV::fRedraw, tagLBIV::fVertBar, tagLBIV::iTop, TRUE, tagLBIV::xOrigin, xxxLBoxCtlHScroll(), xxxNewITop(), and xxxSetLBScrollParms().

Referenced by ListBoxWndProcWorker(), xxxLbDir(), xxxLBInsertItem(), xxxLBoxCtlDelete(), xxxLBoxCtlHScroll(), xxxLBoxCtlHScrollMultiColumn(), xxxLBoxCtlKeyInput(), xxxLBoxCtlScroll(), xxxLBResetContent(), xxxLBSetCount(), xxxLBSetRedraw(), and xxxLBSize().

    00127 {
    00128     BOOL fVertDone = FALSE;
    00129     BOOL fHorzDone = FALSE;
    00130
    00131     // Don't do anything if there are no scrollbars or if parents
    00132     // are invisible.
    00133     if ((!plb->fHorzBar && !plb->fVertBar) || !plb->fRedraw)
    00134         return;
    00135
    00136     //
    00137     // Adjust iTop if necessary but DO NOT REDRAW PERIOD.  We never did
    00138     // in 3.1.  There's a potential bug:
    00139     //      If someone doesn't have redraw off and inserts an item in the
    00140     // same position as the caret, we'll tell them to draw before they may
    00141     // have called LB_SETITEMDATA for their item.  This is because we turn
    00142     // the caret off & on inside of NewITop(), even if the item isn't
    00143     // changing.
    00144     //      So we just want to reflect the position/scroll changes.
    00145     // CheckRedraw() will _really_ redraw the visual changes later if
    00146     // redraw isn't off.
    00147     //
    00148
    00149     if (!plb->fFromInsert) {
    00150         xxxNewITop(plb, plb->iTop);
    00151         fVertDone = TRUE;
    00152     }
    00153
    00154     if (!plb->fMultiColumn) {
    00155         if (!plb->fFromInsert) {
    00156             fHorzDone = TRUE;
    00157             xxxLBoxCtlHScroll(plb, SB_THUMBPOSITION, plb->xOrigin);
    00158         }
    00159
    00160         if (!fVertDone)
    00161             xxxSetLBScrollParms(plb, SB_VERT);
    00162     }
    00163     if (!fHorzDone)
    00164         xxxSetLBScrollParms(plb, SB_HORZ);
    00165 }

int xxxSetLBScrollParms | ( | PLBIV | plb,
|  | int | nCtl
| ) |

Definition at line 26 of file lboxctl1.c.

References BOOL, tagLBIV::cItemFullMax, _SCROLLPOS::cItems, tagLBIV::cMac, FALSE, tagLBIV::fDisableNoScroll, tagLBIV::fHorzBar, tagLBIV::fHorzInitialized, _SCROLLPOS::fMask, tagLBIV::fMultiColumn, tagLBIV::fRedraw, tagLBIV::fRightAlign, tagLBIV::fVertBar, tagLBIV::fVertInitialized, tagLBIV::HPos, HWq, _SCROLLPOS::iPage, _SCROLLPOS::iPos, _SCROLLPOS::iReturn, tagLBIV::itemsPerColumn, tagLBIV::iTop, max, tagLBIV::maxWidth, min, NtUserSetScrollInfo(), tagLBIV::numberOfColumns, PSCROLLPOS, tagWND::rcClient, tagLBIV::spwnd, TRUE, UINT, tagLBIV::VPos, and tagLBIV::xOrigin.

Referenced by xxxLBoxCtlHScroll(), xxxLBShowHideScrollBars(), and xxxNewITopEx().

    00027 {
    00028     int         iPos;
    00029     int         cItems;
    00030     UINT        iPage;
    00031     SCROLLINFO  si;
    00032     BOOL        fNoScroll = FALSE;
    00033     PSCROLLPOS  psp;
    00034     BOOL        fCacheInitialized;
    00035     int         iReturn;
    00036
    00037     if (nCtl == SB_VERT) {
    00038         iPos = plb->iTop;
    00039         cItems = plb->cMac;
    00040         iPage = plb->cItemFullMax;
    00041         if (!plb->fVertBar)
    00042             fNoScroll = TRUE;
    00043         psp = &plb->VPos;
    00044         fCacheInitialized = plb->fVertInitialized;
    00045     } else {
    00046         if (plb->fMultiColumn) {
    00047             iPos   = plb->iTop / plb->itemsPerColumn;
    00048             cItems = plb->cMac ? ((plb->cMac - 1) / plb->itemsPerColumn) + 1 : 0;
    00049             iPage = plb->numberOfColumns;
    00050             if (plb->fRightAlign && cItems)
    00051                 iPos = cItems - iPos - 1;
    00052         } else {
    00053             iPos = plb->xOrigin;
    00054             cItems = plb->maxWidth;
    00055             iPage = plb->spwnd->rcClient.right - plb->spwnd->rcClient.left;
    00056         }
    00057
    00058         if (!plb->fHorzBar)
    00059             fNoScroll = TRUE;
    00060         psp = &plb->HPos;
    00061         fCacheInitialized = plb->fHorzInitialized;
    00062     }
    00063
    00064     if (cItems)
    00065         cItems--;
    00066
    00067     if (fNoScroll) {
    00068         // Limit page to 0, posMax + 1
    00069         iPage = max(min((int)iPage, cItems + 1), 0);
    00070
    00071         // Limit pos to 0, posMax - (page - 1).
    00072         return(max(min(iPos, cItems - ((iPage) ? (int)(iPage - 1) : 0)), 0));
    00073     } else {
    00074         si.fMask    = SIF_ALL;
    00075         if (plb->fDisableNoScroll)
    00076             si.fMask |= SIF_DISABLENOSCROLL;
    00077
    00078         /*
    00079          * If the scrollbar is already where we want it, do nothing.
    00080          */
    00081         if (fCacheInitialized) {
    00082             if (psp->fMask == si.fMask &&
    00083                     psp->cItems == cItems && psp->iPage == iPage &&
    00084                     psp->iPos == iPos)
    00085                 return psp->iReturn;
    00086         } else if (nCtl == SB_VERT) {
    00087             plb->fVertInitialized = TRUE;
    00088         } else {
    00089             plb->fHorzInitialized = TRUE;
    00090         }
    00091
    00092         si.cbSize   = sizeof(SCROLLINFO);
    00093         si.nMin     = 0;
    00094         si.nMax     = cItems;
    00095         si.nPage    = iPage;
    00096
    00097         if (plb->fMultiColumn && plb->fRightAlign)
    00098             si.nPos =  (iPos+1) > (int)iPage ? iPos - iPage + 1 : 0;
    00099         else
    00100             si.nPos = iPos;
    00101
    00102         iReturn = NtUserSetScrollInfo(HWq(plb->spwnd), nCtl, &si, plb->fRedraw);
    00103         if (plb->fMultiColumn && plb->fRightAlign)
    00104             iReturn = cItems - (iReturn + iPage - 1);
    00105
    00106         /*
    00107          * Update the position cache
    00108          */
    00109         psp->fMask = si.fMask;
    00110         psp->cItems = cItems;
    00111         psp->iPage = iPage;
    00112         psp->iPos = iPos;
    00113         psp->iReturn = iReturn;
    00114
    00115         return iReturn;
    00116     }
    00117 }