iconlbox.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 12k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /***************************************************************************/
  2. /**                  Microsoft Windows                                    **/
  3. /**            Copyright(c) Microsoft Corp., 1993                         **/
  4. /***************************************************************************/
  5. /****************************************************************************
  6.     ICONLBOX.C
  7.     Implementation for IconListBox class
  8.     May 93, JimH
  9.     See ICONLBOX.H for details on use.
  10. ****************************************************************************/
  11. #include "npcommon.h"
  12. #include <windows.h>
  13. #include <memory.h>
  14. #include <iconlbox.h>
  15. #pragma intrinsic(memcpy)
  16. #if defined(DEBUG)
  17. static const char szFileName[] = __FILE__;
  18. #define _FILENAME_DEFINED_ONCE szFileName
  19. #endif
  20. #include <npassert.h>
  21. /****************************************************************************
  22. IconListBox constructor
  23. Some initialization is done here, and some is done in SetHeight
  24. (when window handles are known.)
  25. ****************************************************************************/
  26. IconListBox::IconListBox(HINSTANCE hInst, int nCtlID,
  27.                     int iconWidth, int iconHeight) :
  28.                     _nCtlID(nCtlID), _hInst(hInst),
  29.                     _iconWidth(iconWidth), _iconHeight(iconHeight),
  30.                     _hbrSelected(NULL), _hbrUnselected(NULL),
  31.                     _fCombo(FALSE), _cIcons(0), _cTabs(0),_iCurrentMaxHorzExt(0),
  32.                     _hwndDialog(NULL), _hwndListBox(NULL)
  33. {
  34.     _colSel       = ::GetSysColor(COLOR_HIGHLIGHT);
  35.     _colSelText   = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  36.     _colUnsel     = ::GetSysColor(COLOR_WINDOW);
  37.     _colUnselText = ::GetSysColor(COLOR_WINDOWTEXT);
  38. }
  39. /****************************************************************************
  40. IconListBox destructor
  41. deletes any GDI objects created by IconListBox
  42. ****************************************************************************/
  43. IconListBox::~IconListBox()
  44. {
  45.     for (int i = 0; i < _cIcons; i++)
  46.     {
  47.         if (_aIcons[i].hbmSelected)
  48.         {
  49.             if (_aIcons[i].hbmSelected)
  50.             {
  51.                 ::DeleteObject(_aIcons[i].hbmSelected);
  52.                 ::DeleteObject(_aIcons[i].hbmUnselected);
  53.             }
  54.             // Subsequent _aIcons may have used the same bitmap.
  55.             // Mark those as already deleted.
  56.             for (int j = i + 1; j < _cIcons; j++)
  57.             {
  58.                 if (_aIcons[j].nResID == _aIcons[i].nResID)
  59.                 {
  60.                     _aIcons[j].hbmSelected = NULL;
  61.                     _aIcons[j].hbmUnselected = NULL;
  62.                 }
  63.             }
  64.         }
  65.     }
  66.     if (_hbrSelected)
  67.         ::DeleteObject(_hbrSelected);
  68.     if (_hbrUnselected)
  69.         ::DeleteObject(_hbrUnselected);
  70. }
  71. /****************************************************************************
  72. IconListBox::SetHeight
  73. This function MUST be called in reponse to the WM_MEASUREITEM message.
  74. It creates some GDI objects, and initializes class variables not known
  75. at construction time.
  76. ****************************************************************************/
  77. void IconListBox::SetHeight(HWND hwndDlg,
  78.                         LPMEASUREITEMSTRUCT lpm,
  79.                         int itemHeight)             // defaults to 16
  80. {
  81.     ASSERT(hwndDlg != NULL);
  82.     ASSERT((int)lpm->CtlID == _nCtlID);
  83.     _hwndDialog  = hwndDlg;
  84.     _hwndListBox = ::GetDlgItem(_hwndDialog, _nCtlID);
  85.     // Determine if this is a combo box
  86.     char    szClass[32];
  87.     GetClassName(_hwndListBox,szClass,sizeof(szClass));
  88.     if (::lstrcmpi(szClass,"combobox") == 0 )
  89.          _fCombo = TRUE;
  90.     // Create the background brushes used for filling listbox entries...
  91.     _hbrSelected   = ::CreateSolidBrush(_colSel);
  92.     _hbrUnselected = ::CreateSolidBrush(_colUnsel);
  93.     // Calculate how to centre the text vertically in the listbox item.
  94.     TEXTMETRIC  tm;
  95.     HDC         hDC = ::GetDC(hwndDlg);
  96.     GetTextMetrics(hDC, &tm);
  97.     // Set the only lpm entry that matters
  98. // allow larger height if passed in - but at least large enough
  99. // to fit font.
  100. lpm->itemHeight = max( itemHeight, tm.tmHeight + tm.tmExternalLeading );
  101.     _nTextOffset = tm.tmExternalLeading / 2 + 1;
  102.     ::ReleaseDC(hwndDlg, hDC);
  103. }
  104. /****************************************************************************
  105. IconListBox::DrawItem
  106. This function MUST be called in response to the WM_DRAWITEM message.
  107. It takes care of drawing listbox items in selected or unselected state.
  108. Drawing and undrawing the focus rectangle takes advantage of the fact
  109. that DrawFocusRect uses an XOR pen, and Windows is nice enough to assume
  110. this in the order of the ODA_FOCUS messages.
  111. ****************************************************************************/
  112. void IconListBox::DrawItem(LPDRAWITEMSTRUCT lpd)
  113. {
  114.     ASSERT(_hwndDialog != NULL);    // make sure SetHeight has been called
  115.     char string[MAXSTRINGLEN];
  116.     BOOL bSelected = (lpd->itemState & ODS_SELECTED);
  117.     GetString(lpd->itemID, string);
  118.     // fill entire rectangle with background color
  119.     ::FillRect(lpd->hDC, &(lpd->rcItem),
  120.                             bSelected ? _hbrSelected : _hbrUnselected);
  121.     // Look for registered icon to display, and paint it if found
  122.     for (int id = 0; id < _cIcons; id++)
  123.         if (_aIcons[id].nID == (int) lpd->itemData)
  124.             break;
  125.     if (id != _cIcons)              // if we found a bitmap to display
  126.     {
  127.         HDC hdcMem = ::CreateCompatibleDC(lpd->hDC);
  128.         HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hdcMem,
  129.             bSelected ? _aIcons[id].hbmSelected : _aIcons[id].hbmUnselected);
  130.         // draw bitmap ICONSPACE pixels from left and centred vertically
  131.         int x = lpd->rcItem.left + ICONSPACE;
  132.         int y = ((lpd->rcItem.bottom - lpd->rcItem.top) - _iconHeight) / 2;
  133.         y += lpd->rcItem.top;
  134.         ::BitBlt(lpd->hDC, x, y, _iconWidth, _iconHeight, hdcMem,
  135.                     _aIcons[id].x, _aIcons[id].y, SRCCOPY);
  136.         ::SelectObject(hdcMem, hOldBitmap);
  137.         ::DeleteDC(hdcMem);
  138.     }
  139. if (lpd->itemState & ODS_FOCUS)
  140.         ::DrawFocusRect(lpd->hDC, &(lpd->rcItem));
  141.     lpd->rcItem.left += (_iconWidth + (2 * ICONSPACE));
  142.     // Paint string
  143.     ::SetTextColor(lpd->hDC, bSelected ? _colSelText : _colUnselText);
  144.     ::SetBkColor(lpd->hDC, bSelected ? _colSel : _colUnsel);
  145.     (lpd->rcItem.top) += _nTextOffset;
  146.     if (_cTabs == 0)        // if no tabs registered
  147.     {
  148.         ::DrawText(lpd->hDC, string, lstrlen(string), &(lpd->rcItem),
  149.                         DT_LEFT | DT_EXPANDTABS);
  150.     }
  151.     else
  152.     {
  153.         ::TabbedTextOut(lpd->hDC, lpd->rcItem.left, lpd->rcItem.top,
  154.                 string, lstrlen(string), _cTabs, _aTabs, 0);
  155.     }
  156. }
  157. /****************************************************************************
  158. IconListBox::RegisterIcons
  159. Icons must be registered before they can be referenced in AddString.
  160. Note that if you are using several icons from the same bitmap (with different
  161. x and y offsets) they must all have the same background color.
  162. ****************************************************************************/
  163. void IconListBox::RegisterIcon( int nIconID,            // caller's code
  164.                                 int nResID,             // RC file id
  165.                                 int x, int y,           // top left corner
  166.                                 COLORREF colTransparent)  // def. bright green
  167. {
  168.     ASSERT( _cIcons < MAXICONS );
  169.     _aIcons[_cIcons].nID    = nIconID;
  170.     _aIcons[_cIcons].nResID = nResID;
  171.     _aIcons[_cIcons].x = x;
  172.     _aIcons[_cIcons].y = y;
  173.     // Check to see if we already have bitmaps for this resource ID
  174.     // (which may have different x and y offsets.)
  175.     for (int i = 0; i < _cIcons; i++)
  176.     {
  177.         if (_aIcons[i].nResID == nResID)
  178.         {
  179.             _aIcons[_cIcons].hbmSelected   = _aIcons[i].hbmSelected;
  180.             _aIcons[_cIcons].hbmUnselected = _aIcons[i].hbmUnselected;
  181.             _cIcons++;
  182.             return;
  183.         }
  184.     }
  185.     // Otherwise, create new selected and unselected bitmaps
  186.     // Get pointer to DIB
  187.     HRSRC h = ::FindResource(_hInst, MAKEINTRESOURCE(nResID), RT_BITMAP);
  188.     if (h == NULL)
  189.         return;
  190.     HANDLE hRes = ::LoadResource(_hInst, h);
  191.     if (hRes == NULL)
  192.         return;
  193.     LPBITMAPINFOHEADER lpInfo = (LPBITMAPINFOHEADER) LockResource(hRes);
  194.     // Get pointers to start of color table, and start of actual bitmap bits
  195.     // Note that we make a copy of the bitmap header info and the color
  196.     // table.  This is so applications that use iconlistbox can keep their
  197.     // resource segments read only.
  198.     LPBYTE lpBits = (LPBYTE)
  199.                 (lpInfo + 1) + (1 << (lpInfo->biBitCount)) * sizeof(RGBQUAD);
  200.     int cbCopy = (int) (lpBits - (LPBYTE)lpInfo);
  201.     BYTE *lpCopy = new BYTE[cbCopy];
  202.     if (!lpCopy)
  203.         return;
  204.     memcpy(lpCopy, lpInfo, cbCopy);
  205.     RGBQUAD FAR *lpRGBQ =
  206.                     (RGBQUAD FAR *) ((LPSTR)lpCopy + lpInfo->biSize);
  207.     // Find transparent color in color table
  208.     BOOL bFound = FALSE;            // did we find a transparent match?
  209.     int nColorTableSize = (int) (lpBits - (LPBYTE)lpRGBQ);
  210.     nColorTableSize /= sizeof(RGBQUAD);
  211.     for (i = 0; i < nColorTableSize; i++)
  212.     {
  213.         if (colTransparent ==
  214.                 RGB(lpRGBQ[i].rgbRed, lpRGBQ[i].rgbGreen, lpRGBQ[i].rgbBlue))
  215.         {
  216.             bFound = TRUE;
  217.             break;
  218.         }
  219.     }
  220.     // Replace the transparent color with the background for selected and
  221.     // unselected entries.  Use these to create selected and unselected
  222.     // bitmaps, and restore color table.
  223.     RGBQUAD rgbqTemp;                       // color table entry to replace
  224.     HDC hDC = ::GetDC(_hwndDialog);
  225.     if (bFound)
  226.     {
  227.         rgbqTemp = lpRGBQ[i];
  228.         lpRGBQ[i].rgbRed   = GetRValue(_colUnsel);
  229.         lpRGBQ[i].rgbBlue  = GetBValue(_colUnsel);
  230.         lpRGBQ[i].rgbGreen = GetGValue(_colUnsel);
  231.     }
  232.     _aIcons[_cIcons].hbmUnselected = ::CreateDIBitmap(hDC,
  233.                             (LPBITMAPINFOHEADER)lpCopy, CBM_INIT, lpBits,
  234.                             (LPBITMAPINFO)lpCopy, DIB_RGB_COLORS);
  235.     if (bFound)
  236.     {
  237.         lpRGBQ[i].rgbRed   = GetRValue(_colSel);
  238.         lpRGBQ[i].rgbBlue  = GetBValue(_colSel);
  239.         lpRGBQ[i].rgbGreen = GetGValue(_colSel);
  240.     }
  241.     _aIcons[_cIcons].hbmSelected = ::CreateDIBitmap(hDC,
  242.                             (LPBITMAPINFOHEADER)lpCopy, CBM_INIT, lpBits,
  243.                             (LPBITMAPINFO)lpCopy, DIB_RGB_COLORS);
  244.     if (bFound)
  245.         lpRGBQ[i] = rgbqTemp;           // restore original color table entry
  246.     ::ReleaseDC(_hwndDialog, hDC);
  247.     ::FreeResource(hRes);
  248.     delete lpCopy;
  249.     _cIcons++;
  250. }
  251. /****************************************************************************
  252. IconListBox::SetTabStops
  253. Since this is an owner-draw listbox, we can't rely on LB_SETTABS.
  254. Instead, tabs are registered here and TabbedTextOut is used to display
  255. strings.  Dialogbox units have to be converted to pixels.
  256. ****************************************************************************/
  257. void IconListBox::SetTabStops(int cTabs, const int *pTabs)
  258. {
  259.     ASSERT(cTabs <= MAXTABS);
  260.     int nSize  = (int) LOWORD(GetDialogBaseUnits());
  261.     for (int i = 0; i < cTabs; i++)
  262.         _aTabs[i] = ((nSize * pTabs[i]) / 4);
  263.     _cTabs = cTabs;
  264. }
  265. /****************************************************************************
  266. IconListBox::UpdateHorizontalExtent
  267. ****************************************************************************/
  268. int IconListBox::UpdateHorizontalExtent(int nIcon,const char *string)
  269. {
  270.     ASSERT(_hwndDialog != NULL);    // make sure SetHeight has been called
  271. if (!string)
  272. return 0;
  273. // Calculate width in pixels for given string, taking into account icon, spacing and tabs
  274.     int iItemWidth = ICONSPACE + (_iconWidth + (2 * ICONSPACE));
  275.     HDC hDC = ::GetDC(_hwndDialog);
  276. iItemWidth += LOWORD(GetTabbedTextExtent(hDC,string,::lstrlen(string),_cTabs, _aTabs));
  277.     ::ReleaseDC(_hwndDialog, hDC);
  278. // Update maximum value
  279.     _iCurrentMaxHorzExt = max(_iCurrentMaxHorzExt,iItemWidth);
  280. return (int)SendDlgItemMessage(_hwndDialog,_nCtlID,
  281. LB_SETHORIZONTALEXTENT,
  282. (WPARAM)_iCurrentMaxHorzExt,0L);
  283. }