Annotation of mstools/samples/sdktools/winat/listhscr.c, revision 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.