|
|
1.1 ! root 1: /* ! 2: * LISTHSCR.C ! 3: * ! 4: * Added functions to support horizontal listbox scrolling. This ! 5: * DLL is generalized to support any listbox. The FInitListboxExtents ! 6: * function allocates local memory (from the DLLs DATA segment) for ! 7: * the list of string extents to go in the listbox. The local handle ! 8: * is then assigned as a property of the window, so every other ! 9: * function first looks at this property. ! 10: * ! 11: * This means that any number of horizontal scrolling listboxes can ! 12: * be used in the system and make use of these functions, as long ! 13: * as the DLLs memory is not full. ! 14: * ! 15: */ ! 16: ! 17: ! 18: #include <windows.h> ! 19: #include "listhscr.h" ! 20: ! 21: ! 22: /* ! 23: * This is just the label of the property given to each listbox ! 24: * that asks for an extent list. ! 25: */ ! 26: ! 27: char szXTList[]="XTList"; ! 28: ! 29: ! 30: ! 31: ! 32: ! 33: /* ! 34: * FInitListboxExtents ! 35: * ! 36: * Purpose: ! 37: * Simple helper function to initialize everything for maintaining ! 38: * horizontal extents in a listbox. This function allocates memory ! 39: * to hold the list of extents and assigns it to the window as a property. ! 40: * ! 41: * Parameters: ! 42: * hList HWND of the listbox concerned. ! 43: * ! 44: * Return Value: ! 45: * BOOL TRUE if the function was successful. ! 46: * FALSE if memory could not be allocated. ! 47: */ ! 48: ! 49: BOOL FAR PASCAL FInitListboxExtents(HWND hList) ! 50: { ! 51: HANDLE hMem; ! 52: WORD *pw; ! 53: ! 54: /* ! 55: * Initially allocate 260 bytes, or 130 WORDs since the majority ! 56: * of listbox usage will not require a reallocation, and ! 57: * allocating 256 bytes is just as efficient as allocating 2 ! 58: * bytes, if not more so because of reduces overhead. ! 59: * ! 60: * The extra two words store the current number of extent entries ! 61: * and the maximum number possible in this memory block. ! 62: * ! 63: */ ! 64: ! 65: hMem=LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, CBALLOCUNIT + sizeof(WORD)<<1); ! 66: ! 67: if (hMem==NULL) ! 68: return FALSE; ! 69: ! 70: /* ! 71: * Set the first two words in the memory to the appropriate values. ! 72: * If we can't lock it we can;'t use it! ! 73: */ ! 74: pw=(WORD *)LocalLock(hMem); ! 75: ! 76: if (pw==NULL) ! 77: { ! 78: LocalFree(hMem); ! 79: return FALSE; ! 80: } ! 81: ! 82: *pw=0; //cExtentEntries ! 83: *(pw+1)=CALLOCUNITS; //cExtentEntriesMax ! 84: ! 85: LocalUnlock(hMem); ! 86: ! 87: /* ! 88: * Assign the memory handle as a property of the listbox. This allows ! 89: * this code to take any hList and get it's extent entry list, ! 90: * therefore having full support for multiple listboxes. ! 91: */ ! 92: SetProp(hList, (LPSTR)szXTList, hMem); ! 93: return TRUE; ! 94: } ! 95: ! 96: ! 97: ! 98: ! 99: ! 100: /* ! 101: * FFreeListboxExtents ! 102: * ! 103: * Purpose: ! 104: * Release any memory used for storing the extents of the ! 105: * horizontal listbox. This MUST be called when the listbox ! 106: * is destroyed, like in the WM_DESTROY case of the parent window. ! 107: * ! 108: * Parameters: ! 109: * hList HWND of the listbox concerned. ! 110: * ! 111: * Return Value: ! 112: * BOOL TRUE if the function was successful. ! 113: * FALSE if there is an error. ! 114: */ ! 115: ! 116: BOOL FAR PASCAL FFreeListboxExtents(HWND hList) ! 117: { ! 118: HANDLE hMem; ! 119: BOOL fSuccess; ! 120: ! 121: //Load the handle to free. ! 122: hMem=GetProp(hList, (LPSTR)szXTList); ! 123: ! 124: /* ! 125: * Return a BOOL on the result. An app could keep calling this ! 126: * function until it worked since hMem is still around. ! 127: */ ! 128: fSuccess=(BOOL)LocalFree(hMem); ! 129: ! 130: if (fSuccess) ! 131: RemoveProp(hList, (LPSTR)szXTList); //Only if handle was freed! ! 132: ! 133: return fSuccess; ! 134: } ! 135: ! 136: ! 137: ! 138: ! 139: /* ! 140: * ResetListboxExtents ! 141: * ! 142: * Purpose: ! 143: * Deletes all extents in the extent list to be used AFTER an ! 144: * LB_RESETCONTENT is sent to the listbox. ! 145: * ! 146: * Parameters: ! 147: * hList HWND of the listbox. ! 148: * ! 149: * Return Value: ! 150: * none ! 151: * ! 152: */ ! 153: ! 154: void FAR PASCAL ResetListboxExtents(HWND hList) ! 155: { ! 156: FFreeListboxExtents(hList); ! 157: FInitListboxExtents(hList); ! 158: ! 159: SendMessage(hList, LB_SETHORIZONTALEXTENT, 0, 0L); ! 160: ! 161: //This is required to remove the scrollbar. ! 162: SendMessage(hList, LB_DELETESTRING, 0, 0L); ! 163: return; ! 164: } ! 165: ! 166: ! 167: ! 168: ! 169: ! 170: /* ! 171: * WAddExtentEntry ! 172: * ! 173: * Purpose: ! 174: * Facilitates handling of the horizontal listbox by keeping ! 175: * track of the pixel width of the longest string in the listbox. ! 176: * The number of pixels that the listbox scrolls is the width ! 177: * of the longest string. ! 178: * ! 179: * Parameters: ! 180: * hList HWND of the listbox. ! 181: * psz Pointer to string that is added. This must be passed ! 182: * instead of an index into the listbox since this must ! 183: * be called before the string is added if the scrollbar ! 184: * is to be maintained properly. ! 185: * ! 186: * Return Value: ! 187: * WORD 0 if the string added was not the longest string in ! 188: * the listbox and therefore did not change the visibility ! 189: * of the horizontal scrollbar. ! 190: * ! 191: * wExtent if the added string was the longest, thus either ! 192: * making the scrollbar visible or changing the extent. ! 193: * ! 194: * -1 on an error. ! 195: * ! 196: */ ! 197: ! 198: WORD FAR PASCAL WAddExtentEntry(HWND hList, LPSTR psz) ! 199: { ! 200: HANDLE hMem; ! 201: WORD cExtentEntries; ! 202: WORD cExtentEntriesMax; ! 203: WORD *pw; //Pointer to extent memory. ! 204: WORD wExtent; ! 205: WORD i=0; ! 206: WORD iRev; ! 207: ! 208: ! 209: hMem=GetProp(hList, (LPSTR)szXTList); ! 210: ! 211: if (hMem==NULL) ! 212: return ((WORD)-1); ! 213: ! 214: ! 215: pw=(WORD *)LocalLock(hMem); ! 216: ! 217: if (pw==NULL) ! 218: return ((WORD)-1); ! 219: ! 220: //Load the values and set pointer to start of list. ! 221: cExtentEntries=*pw++; ! 222: cExtentEntriesMax=*pw++; ! 223: ! 224: //Reallocate if necessary. ! 225: if (cExtentEntries==cExtentEntriesMax) ! 226: { ! 227: LocalUnlock(hMem); ! 228: ! 229: //This call takes care of cExtentEntriesMax ! 230: if (!FReAllocExtentList(hMem, TRUE)) ! 231: return ((WORD)-1); ! 232: ! 233: cExtentEntriesMax += CALLOCUNITS; ! 234: pw=(WORD *)LocalLock(hMem); ! 235: ! 236: if (pw==NULL) ! 237: return ((WORD)-1); ! 238: ! 239: pw+=2; //Skip the two counters. ! 240: } ! 241: ! 242: wExtent=WGetListboxStringExtent(hList, psz); ! 243: ! 244: ! 245: /* ! 246: * Insert the new extent into the list. This list is just a sorted ! 247: * list (descending) of the largest to smallest extents in the ! 248: * listbox. When deleting a string, we just need to look in this ! 249: * list for it's extent and remove that entry. ! 250: * ! 251: * Yeah, this can be inefficient, but this is not a real case for ! 252: * optimization. ! 253: * ! 254: */ ! 255: ! 256: if (cExtentEntries==0) ! 257: pw[0]=wExtent; ! 258: else ! 259: { ! 260: i=IFindExtentInList(pw, wExtent, cExtentEntries); ! 261: ! 262: for (iRev=cExtentEntries+1; iRev > i; iRev--) ! 263: pw[iRev]=pw[iRev-1]; ! 264: ! 265: pw[i]=wExtent; ! 266: } ! 267: ! 268: cExtentEntries++; ! 269: ! 270: //Save these values back. pw must be decremented first. ! 271: *(--pw)=cExtentEntriesMax; ! 272: *(--pw)=cExtentEntries; ! 273: ! 274: LocalUnlock(hMem); ! 275: ! 276: ! 277: /* ! 278: * Check if the one we added is now the first. If so, then ! 279: * we need to reset the horizontal extent. ! 280: */ ! 281: ! 282: if (i==0) ! 283: { ! 284: SendMessage(hList, LB_SETHORIZONTALEXTENT, wExtent, 0L); ! 285: return wExtent; ! 286: } ! 287: ! 288: return ((WORD)0); ! 289: } ! 290: ! 291: ! 292: ! 293: ! 294: ! 295: ! 296: ! 297: ! 298: /* ! 299: * WRemoveExtentEntry ! 300: * ! 301: * Purpose: ! 302: * Facilitates handling of the horizontal listbox by keeping ! 303: * track of the pixel width of the longest string in the listbox. ! 304: * The number of pixels that the listbox scrolls is the width ! 305: * of the longest string. ! 306: * ! 307: * Parameters: ! 308: * hList HWND of the listbox. ! 309: * iSel WORD index of the string to be removed. ! 310: * ! 311: * Return Value: ! 312: * WORD 0 if the string removed did not affect the visibilty ! 313: * of the horizontal scrollbar, i.e. if there still is ! 314: * a longer string or there is no scrollbar in the first ! 315: * place. ! 316: * ! 317: * wExtent of the new longest string if the one removed ! 318: * was the longest. ! 319: * ! 320: * -1 on an error. ! 321: */ ! 322: ! 323: WORD FAR PASCAL WRemoveExtentEntry(HWND hList, WORD iSel) ! 324: { ! 325: WORD *pw; //Pointer to extent memory. ! 326: WORD cExtentEntries; ! 327: WORD cExtentEntriesMax; ! 328: WORD wExtent; ! 329: WORD i; ! 330: WORD iSave; ! 331: HANDLE hMem; ! 332: HANDLE hMemT; ! 333: char *pch; ! 334: WORD cb; ! 335: ! 336: ! 337: hMem=GetProp(hList, (LPSTR)szXTList); ! 338: ! 339: if (hMem==NULL) ! 340: return ((WORD)-1); ! 341: ! 342: ! 343: pw=(WORD *)LocalLock(hMem); ! 344: ! 345: if (pw==NULL) ! 346: return ((WORD)-1); ! 347: ! 348: //Load the values and set pointer to start of list. ! 349: cExtentEntries=*pw++; ! 350: cExtentEntriesMax=*pw++; ! 351: ! 352: if (cExtentEntries==0) ! 353: { ! 354: LocalUnlock(hMem); ! 355: return ((WORD)-1); ! 356: } ! 357: ! 358: ! 359: //Free up memory if necessary. No reallocating smaller is not fatal. ! 360: if ((cExtentEntriesMax-cExtentEntries)==CALLOCUNITS) ! 361: { ! 362: LocalUnlock(hMem); ! 363: ! 364: if (!FReAllocExtentList(hMem, FALSE)) ! 365: return ((WORD)-1); ! 366: ! 367: cExtentEntriesMax += CALLOCUNITS; ! 368: pw=(WORD *)LocalLock(hMem); ! 369: ! 370: if (pw==NULL) ! 371: return ((WORD)-1); ! 372: ! 373: pw+=2; //Skip the two counters. ! 374: } ! 375: ! 376: cb=(WORD)SendMessage(hList, LB_GETTEXTLEN, iSel, 0L); ! 377: ! 378: //Temporary memory to copy the listbox string so we can get the extent. ! 379: hMemT=LocalAlloc(LMEM_MOVEABLE, cb+2); //One extra to be safe. ! 380: pch=LocalLock(hMemT); ! 381: ! 382: if (pch==NULL) ! 383: { ! 384: LocalUnlock(hMem); ! 385: LocalFree(hMemT); ! 386: return ((WORD)-1); ! 387: } ! 388: ! 389: cb=(WORD)SendMessage(hList, LB_GETTEXT, iSel, (LONG)(LPSTR)pch); ! 390: ! 391: wExtent=WGetListboxStringExtent(hList, (LPSTR)pch); ! 392: ! 393: LocalUnlock(hMemT); ! 394: LocalFree(hMemT); ! 395: ! 396: ! 397: /* ! 398: * Find the extent in the list and remove it. If it's the first, ! 399: * then reset the horizontal extent to the second. ! 400: */ ! 401: ! 402: i=IFindExtentInList(pw, wExtent, cExtentEntries); ! 403: iSave=i; ! 404: ! 405: while (i < cExtentEntries) ! 406: pw[i++]=pw[i+1]; ! 407: ! 408: cExtentEntries--; ! 409: ! 410: //Save these values back. pw must be decremented first. ! 411: *(--pw)=cExtentEntriesMax; ! 412: *(--pw)=cExtentEntries; ! 413: ! 414: LocalUnlock(hMem); ! 415: ! 416: if (iSave==0) ! 417: { ! 418: /* ! 419: * Before we change the horizontal extent, we must make sure that ! 420: * the origin of the listbox is visible through forcing a scroll. ! 421: * If this is not done, and the listbox is scrolled one or ! 422: * more pixels to the right, the scrollbar WILL NOT disappear ! 423: * even if all remaining strings fit inside the client area ! 424: * of the listbox. ! 425: * ! 426: * This is only done here since this the only case where this ! 427: * might happen is when we change the extent. ! 428: */ ! 429: SendMessage(hList, WM_HSCROLL, SB_TOP, MAKELONG(0, hList)); ! 430: SendMessage(hList, LB_SETHORIZONTALEXTENT, pw[2], 0L); ! 431: ! 432: return pw[2]; ! 433: } ! 434: ! 435: ! 436: return ((WORD)0); ! 437: } ! 438: ! 439: ! 440: ! 441: ! 442: ! 443: ! 444: /* ! 445: * FReAllocExtentList ! 446: * ! 447: * Purpose: ! 448: * Handles reallocation of the list in blocks of +/- CBALLOCUNIT ! 449: * ! 450: * Parameters: ! 451: * fGrow BOOL if TRUE, instructs this function to allocate ! 452: * an additional ALLOCUNIT. ! 453: * If FALSE, shrinks the memory block by an ALLOCUNIT. ! 454: * ! 455: * Return Value: ! 456: * BOOL TRUE if successfully reallocated. FALSE otherwise. ! 457: * ! 458: */ ! 459: ! 460: BOOL FReAllocExtentList(HANDLE hMem, BOOL fGrow) ! 461: { ! 462: WORD wSize; ! 463: ! 464: /* ! 465: * Allocate an additional 128 entries. A 256 byte block is a ! 466: * decent reallocation size. ! 467: */ ! 468: wSize=LocalSize((HLOCAL)hMem); ! 469: wSize+=(fGrow) ? ((int)CBALLOCUNIT) : (-(int)CBALLOCUNIT); ! 470: ! 471: /* ! 472: * This returns FALSE if the realloc was unsuccessful. TRUE ! 473: * otherwise because the return handle is !=0 ! 474: * ! 475: */ ! 476: return (BOOL)LocalReAlloc(hMem, wSize, LMEM_MOVEABLE | LMEM_ZEROINIT); ! 477: } ! 478: ! 479: ! 480: ! 481: ! 482: ! 483: ! 484: /* ! 485: * WGetListboxStringExtent ! 486: * ! 487: * Purpose: ! 488: * Returns the extent, in pixels, of a string that will be or is ! 489: * in a listbox. The hDC of the listbox is used and an extra ! 490: * average character width is added to the extent to insure that ! 491: * a horizontal scrolling listbox that is based on this extent ! 492: * will scroll such that the end of the string is visible. ! 493: * ! 494: * Parameters: ! 495: * hList HWND handle to the listbox. ! 496: * psz LPSTR pointer to string in question. ! 497: * ! 498: * Return Value: ! 499: * WORD Extent of the string relative to listbox. ! 500: * ! 501: */ ! 502: ! 503: WORD WGetListboxStringExtent(HWND hList, LPSTR psz) ! 504: { ! 505: TEXTMETRIC tm; ! 506: HDC hDC; ! 507: HFONT hFont; ! 508: WORD wExtent; ! 509: ! 510: ! 511: /* ! 512: * Make sure we are using the correct font. ! 513: */ ! 514: hDC=GetDC(hList); ! 515: hFont=(HFONT)SendMessage(hList, WM_GETFONT, 0, 0L); ! 516: ! 517: if (hFont!=NULL) ! 518: SelectObject(hDC, hFont); ! 519: ! 520: GetTextMetrics(hDC, &tm); ! 521: ! 522: /* ! 523: * Add one average text width to insure that we see the end of the ! 524: * string when scrolled horizontally. ! 525: */ ! 526: ! 527: // ! 528: // changed to GetTextExtentPoint - KoryG - 3/24/92 ! 529: // ! 530: { ! 531: SIZE Size; ! 532: ! 533: GetTextExtentPoint(hDC, psz, lstrlen(psz), &Size); ! 534: // fudge for tabs! ! 535: wExtent=(WORD)Size.cx + (WORD)tm.tmAveCharWidth + 180; ! 536: } ! 537: ! 538: ReleaseDC(hList, hDC); ! 539: ! 540: return wExtent; ! 541: } ! 542: ! 543: ! 544: ! 545: ! 546: ! 547: ! 548: /* ! 549: * IFindExtentInList ! 550: * ! 551: * Purpose: ! 552: * Does an binary search on the sorted extent list and returns ! 553: * an index to the one that matches. If there is no match, ! 554: * the index gives the point where the extent entry should go. ! 555: * ! 556: * Note that an altered search algorithm is used since the list ! 557: * is descending instead of ascending. ! 558: * ! 559: * Parameters: ! 560: * pw WORD * pointer to extent list. ! 561: * wExtent WORD extent to find or find an index for. ! 562: * cExtentEntries WORD count of entries in list. ! 563: * ! 564: * Return Value: ! 565: * iExtent WORD index into lpw where wExtent exists or where ! 566: * it should be inserted. ! 567: * ! 568: */ ! 569: ! 570: WORD IFindExtentInList(WORD *pw, WORD wExtent, WORD cExtentEntries) ! 571: { ! 572: int i = 0; //These MUST be signed! ! 573: int iPrev; ! 574: int iMin; ! 575: int iMax; ! 576: ! 577: //Set upper limits on search. ! 578: iMin=0; ! 579: iMax=cExtentEntries+1; ! 580: ! 581: ! 582: do ! 583: { ! 584: iPrev=i; ! 585: i=(iMin + iMax) >> 1; ! 586: ! 587: if (i==iPrev) ! 588: { ! 589: i++; ! 590: break; ! 591: } ! 592: ! 593: //Change the min and max depending on which way we need to look. ! 594: if (wExtent < pw[i]) // < since list is descending. > otherwise ! 595: iMin=i; ! 596: else ! 597: iMax=i; ! 598: ! 599: if (iMax==iMin) ! 600: break; ! 601: } ! 602: while (wExtent != pw[i]); ! 603: ! 604: ! 605: /* ! 606: * When we get here, i is either where wExtent is or where it should ! 607: * go--so return it. ! 608: */ ! 609: return i; ! 610: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.