Annotation of mstools/samples/sdktools/winat/listhscr.c, revision 1.1.1.1

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:     }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.