lvlist.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 17k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. // list view (small icons, multiple columns)
  2. #include "ctlspriv.h"
  3. #include "listview.h"
  4. #define COLUMN_VIEW
  5. BOOL ListView_LDrawItem(PLVDRAWITEM plvdi)
  6. {
  7.     RECT rcIcon;
  8.     RECT rcLabel;
  9.     RECT rcBounds;
  10.     RECT rcT;
  11.     LV_ITEM item;
  12.     TCHAR ach[CCHLABELMAX];
  13.     LV* plv = plvdi->plv;
  14.     int i = (int) plvdi->nmcd.nmcd.dwItemSpec;
  15.     // moved here to reduce call backs in OWNERDATA case
  16.     //
  17.     item.iItem = i;
  18.     item.iSubItem = 0;
  19.     item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
  20.     item.stateMask = LVIS_ALL;
  21.     item.pszText = ach;
  22.     item.cchTextMax = ARRAYSIZE(ach);
  23.     ListView_OnGetItem(plv, &item);
  24.     ListView_LGetRects(plv, i, &rcIcon, &rcLabel, &rcBounds, NULL);
  25.     if (!plvdi->prcClip || IntersectRect(&rcT, &rcBounds, plvdi->prcClip))
  26.     {
  27.         UINT fText;
  28.         if (plvdi->lpptOrg)
  29.         {
  30.             OffsetRect(&rcIcon, plvdi->lpptOrg->x - rcBounds.left,
  31.                                 plvdi->lpptOrg->y - rcBounds.top);
  32.             OffsetRect(&rcLabel, plvdi->lpptOrg->x - rcBounds.left,
  33.                                 plvdi->lpptOrg->y - rcBounds.top);
  34.         }
  35.         fText = ListView_DrawImage(plv, &item, plvdi->nmcd.nmcd.hdc,
  36.             rcIcon.left, rcIcon.top, plvdi->flags) | SHDT_ELLIPSES;
  37.         // Don't draw the label if it is being edited.
  38.         if (plv->iEdit != i)
  39.         {
  40.             int ItemCxSingleLabel;
  41.             UINT ItemState;
  42.             if (ListView_IsOwnerData( plv ))
  43.             {
  44.                LISTITEM listitem;
  45.                // calculate lable sizes from iItem
  46.                    listitem.pszText = ach;
  47.                ListView_RecomputeLabelSize( plv, &listitem, i, plvdi->nmcd.nmcd.hdc, TRUE );
  48.                ItemCxSingleLabel = listitem.cxSingleLabel;
  49.                ItemState = item.state;
  50.             }
  51.             else
  52.             {
  53.                ItemCxSingleLabel = plvdi->pitem->cxSingleLabel;
  54.                ItemState = plvdi->pitem->state;
  55.             }
  56.             if (plvdi->flags & LVDI_TRANSTEXT)
  57.                 fText |= SHDT_TRANSPARENT;
  58.             if (ItemCxSingleLabel == SRECOMPUTE) {
  59.                 ListView_RecomputeLabelSize(plv, plvdi->pitem, i, plvdi->nmcd.nmcd.hdc, FALSE);
  60.                 ItemCxSingleLabel = plvdi->pitem->cxSingleLabel;
  61.             }
  62.             if (ItemCxSingleLabel < rcLabel.right - rcLabel.left)
  63.                 rcLabel.right = rcLabel.left + ItemCxSingleLabel;
  64.             if ((fText & SHDT_SELECTED) && (plvdi->flags & LVDI_HOTSELECTED))
  65.                 fText |= SHDT_HOTSELECTED;
  66. #ifdef WINDOWS_ME
  67.             if( plv->dwExStyle & WS_EX_RTLREADING)
  68.                 fText |= SHDT_RTLREADING;
  69. #endif
  70.             SHDrawText(plvdi->nmcd.nmcd.hdc, item.pszText, &rcLabel, LVCFMT_LEFT, fText,
  71.                        plv->cyLabelChar, plv->cxEllipses,
  72.                        plvdi->nmcd.clrText, plvdi->nmcd.clrTextBk);
  73.             if ((plvdi->flags & LVDI_FOCUS) && (ItemState & LVIS_FOCUSED)
  74. #ifdef KEYBOARDCUES
  75. && !(CCGetUIState(&(plvdi->plv->ci)) & UISF_HIDEFOCUS)
  76. #endif
  77. )
  78.                 DrawFocusRect(plvdi->nmcd.nmcd.hdc, &rcLabel);
  79.         }
  80.     }
  81.     return TRUE;
  82. }
  83. DWORD ListView_LApproximateViewRect(LV* plv, int iCount, int iWidth, int iHeight)
  84. {
  85.     int cxItem = plv->cxItem;
  86.     int cyItem = plv->cyItem;
  87.     int cCols;
  88.     int cRows;
  89.     cRows = iHeight / cyItem;
  90.     cRows = min(cRows, iCount);
  91.     if (cRows == 0)
  92.         cRows = 1;
  93.     cCols = (iCount + cRows - 1) / cRows;
  94.     iWidth = cCols * cxItem;
  95.     iHeight = cRows * cyItem;
  96.     return MAKELONG(iWidth + g_cxEdge, iHeight + g_cyEdge);
  97. }
  98. int NEAR ListView_LItemHitTest(LV* plv, int x, int y, UINT FAR* pflags, int *piSubItem)
  99. {
  100.     int iHit;
  101.     int i;
  102.     int iCol;
  103.     int xItem; //where is the x in relation to the item
  104.     UINT flags;
  105.     LISTITEM FAR* pitem;
  106.     if (piSubItem)
  107.         *piSubItem = 0;
  108.     flags = LVHT_NOWHERE;
  109.     iHit = -1;
  110. #ifdef COLUMN_VIEW
  111.     i = y / plv->cyItem;
  112.     if (i >= 0 && i < plv->cItemCol)
  113.     {
  114.         iCol = (x + plv->xOrigin) / plv->cxItem;
  115.         i += iCol * plv->cItemCol;
  116.         if (i >= 0 && i < ListView_Count(plv))
  117.         {
  118.             iHit = i;
  119.             xItem = x + plv->xOrigin - iCol * plv->cxItem;
  120.             if (xItem < plv->cxState) {
  121.                 flags = LVHT_ONITEMSTATEICON;
  122.             } else if (xItem < (plv->cxState + plv->cxSmIcon)) {
  123.                     flags = LVHT_ONITEMICON;
  124.             }
  125.             else
  126.             {
  127.             int ItemCxSingleLabel;
  128.             if (ListView_IsOwnerData( plv ))
  129.             {
  130.                LISTITEM item;
  131.                // calculate lable sizes from iItem
  132.                ListView_RecomputeLabelSize( plv, &item, i, NULL, FALSE );
  133.                ItemCxSingleLabel = item.cxSingleLabel;
  134.             }
  135.             else
  136.             {
  137.                 pitem = ListView_FastGetItemPtr(plv, i);
  138.                 if (pitem->cxSingleLabel == SRECOMPUTE)
  139.                 {
  140.                     ListView_RecomputeLabelSize(plv, pitem, i, NULL, FALSE);
  141.                 }
  142.                 ItemCxSingleLabel = pitem->cxSingleLabel;
  143.             }
  144.             if (xItem < (plv->cxSmIcon + plv->cxState + ItemCxSingleLabel))
  145.                 flags = LVHT_ONITEMLABEL;
  146.             }
  147.         }
  148.     }
  149. #else
  150.     i = x / plv->cxItem;
  151.     if (i < plv->cItemCol)
  152.     {
  153.         i += ((y + plv->xOrigin) / plv->cyItem) * plv->cItemCol;
  154.         if (i < ListView_Count(plv))
  155.         {
  156.             iHit = i;
  157.             flags = LVHT_ONITEMICON;
  158.         }
  159.     }
  160. #endif
  161.     *pflags = flags;
  162.     return iHit;
  163. }
  164. void NEAR ListView_LGetRects(LV* plv, int i, RECT FAR* prcIcon,
  165.         RECT FAR* prcLabel, RECT FAR *prcBounds, RECT FAR* prcSelectBounds)
  166. {
  167.     RECT rcIcon;
  168.     RECT rcLabel;
  169.     int x, y;
  170.     int cItemCol = plv->cItemCol;
  171.     if (cItemCol == 0)
  172.     {
  173.         // Called before other data has been initialized so call
  174.         // update scrollbars which should make sure that that
  175.         // we have valid data...
  176.         ListView_UpdateScrollBars(plv);
  177.         // but it's possible that updatescrollbars did nothing because of
  178.         // LVS_NOSCROLL or redraw
  179.         // BUGBUG raymondc v6.0:  Get it right even if no redraw. Fix for v6.
  180.         if (plv->cItemCol == 0)
  181.             cItemCol = 1;
  182.         else
  183.             cItemCol = plv->cItemCol;
  184.     }
  185. #ifdef COLUMN_VIEW
  186.     x = (i / cItemCol) * plv->cxItem;
  187.     y = (i % cItemCol) * plv->cyItem;
  188.     rcIcon.left   = x - plv->xOrigin + plv->cxState;
  189.     rcIcon.top    = y;
  190. #else
  191.     x = (i % cItemCol) * plv->cxItem;
  192.     y = (i / cItemCol) * plv->cyItem;
  193.     rcIcon.left   = x;
  194.     rcIcon.top    = y - plv->xOrigin;
  195. #endif
  196.     rcIcon.right  = rcIcon.left + plv->cxSmIcon;
  197.     rcIcon.bottom = rcIcon.top + plv->cyItem;
  198.     if (prcIcon)
  199.         *prcIcon = rcIcon;
  200.     rcLabel.left  = rcIcon.right;
  201.     rcLabel.right = rcIcon.left + plv->cxItem - plv->cxState;
  202.     rcLabel.top   = rcIcon.top;
  203.     rcLabel.bottom = rcIcon.bottom;
  204.     if (prcLabel)
  205.         *prcLabel = rcLabel;
  206.     if (prcBounds)
  207.     {
  208.         *prcBounds = rcLabel;
  209.         prcBounds->left = rcIcon.left - plv->cxState;
  210.     }
  211.     if (prcSelectBounds)
  212.     {
  213.         *prcSelectBounds = rcLabel;
  214.         prcSelectBounds->left = rcIcon.left;
  215.     }
  216. }
  217. void NEAR ListView_LUpdateScrollBars(LV* plv)
  218. {
  219.     RECT rcClient;
  220.     int cItemCol;
  221.     int cCol;
  222.     int cColVis;
  223.     SCROLLINFO si;
  224.     ASSERT(plv);
  225.     ListView_GetClientRect(plv, &rcClient, FALSE, NULL);
  226. #ifdef COLUMN_VIEW
  227.     cColVis = (rcClient.right - rcClient.left) / plv->cxItem;
  228.     cItemCol = max(1, (rcClient.bottom - rcClient.top) / plv->cyItem);
  229. #else
  230.     cColVis = (rcClient.bottom - rcClient.top) / plv->cyItem;
  231.     cItemCol = max(1, (rcClient.right - rcClient.left) / plv->cxItem);
  232. #endif
  233.     cCol     = (ListView_Count(plv) + cItemCol - 1) / cItemCol;
  234.     // Make the client area smaller as appropriate, and
  235.     // recompute cCol to reflect scroll bar.
  236.     //
  237.     si.cbSize = sizeof(SCROLLINFO);
  238.     si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  239.     si.nPage = cColVis;
  240.     si.nMin = 0;
  241. #ifdef COLUMN_VIEW
  242.     rcClient.bottom -= ListView_GetCyScrollbar(plv);
  243.     cItemCol = max(1, (rcClient.bottom - rcClient.top) / plv->cyItem);
  244.     cCol = (ListView_Count(plv) + cItemCol - 1) / cItemCol;
  245.     si.nPos = plv->xOrigin / plv->cxItem;
  246.     si.nMax = cCol - 1;
  247.     ListView_SetScrollInfo(plv, SB_HORZ, &si, TRUE);
  248. #else
  249.     rcClient.right -= ListView_GetCxScrollbar(plv);
  250.     cItemCol = max(1, (rcClient.right - rcClient.left) / plv->cxItem);
  251.     cCol = (ListView_Count(plv) + cItemCol - 1) / cItemCol;
  252.     si.nPos = plv->xOrigin / plv->cyItem;
  253.     si.nMax = cCol - 1;
  254.     ListView_SetScrollInfo(plv, SB_VERT, &si, TRUE);
  255. #endif
  256.     // Update number of visible lines...
  257.     //
  258.     if (plv->cItemCol != cItemCol)
  259.     {
  260.         plv->cItemCol = cItemCol;
  261.         InvalidateRect(plv->ci.hwnd, NULL, TRUE);
  262.     }
  263.     // make sure our position and page doesn't hang over max
  264.     if ((si.nPos + (LONG)si.nPage - 1 > si.nMax) && si.nPos > 0) {
  265.         int iNewPos, iDelta;
  266.         iNewPos = (int)si.nMax - (int)si.nPage + 1;
  267.         if (iNewPos < 0) iNewPos = 0;
  268.         if (iNewPos != si.nPos) {
  269.             iDelta = iNewPos - (int)si.nPos;
  270. #ifdef COLUMN_VIEW
  271.             ListView_LScroll2(plv, iDelta, 0, 0);
  272. #else
  273.             ListView_LScroll2(plv, 0, iDelta, 0);
  274. #endif
  275.             ListView_LUpdateScrollBars(plv);
  276.         }
  277.     }
  278.     // never have the other scrollbar
  279. #ifdef COLUMN_VIEW
  280.     ListView_SetScrollRange(plv, SB_VERT, 0, 0, TRUE);
  281. #else
  282.     ListView_SetScrollRange(plv, SB_HORZ, 0, 0, TRUE);
  283. #endif
  284. }
  285. //
  286. //  We need a smoothscroll callback so our background image draws
  287. //  at the correct origin.  If we don't have a background image,
  288. //  then this work is superfluous but not harmful either.
  289. //
  290. int CALLBACK ListView_LScroll2_SmoothScroll(
  291.     HWND hwnd,
  292.     int dx,
  293.     int dy,
  294.     CONST RECT *prcScroll,
  295.     CONST RECT *prcClip,
  296.     HRGN hrgnUpdate,
  297.     LPRECT prcUpdate,
  298.     UINT flags)
  299. {
  300.     LV* plv = ListView_GetPtr(hwnd);
  301.     if (plv)
  302.     {
  303. #ifdef COLUMN_VIEW
  304.         plv->xOrigin -= dx;
  305. #else
  306.         plv->xOrigin -= dy;
  307. #endif
  308.     }
  309.     // Now do what SmoothScrollWindow would've done if we weren't
  310.     // a callback
  311.     return ScrollWindowEx(hwnd, dx, dy, prcScroll, prcClip, hrgnUpdate, prcUpdate, flags);
  312. }
  313. void FAR PASCAL ListView_LScroll2(LV* plv, int dx, int dy, UINT uSmooth)
  314. {
  315. #ifdef COLUMN_VIEW
  316.     if (dx)
  317.     {
  318.         dx *= plv->cxItem;
  319.         {
  320.             SMOOTHSCROLLINFO si;
  321.             si.cbSize = sizeof(si);
  322.             si.fMask = SSIF_SCROLLPROC;
  323.             si.hwnd =plv->ci.hwnd ;
  324.             si.dx =-dx ;
  325.             si.dy = 0;
  326.             si.lprcSrc = NULL;
  327.             si.lprcClip = NULL;
  328.             si.hrgnUpdate = NULL;
  329.             si.lprcUpdate = NULL;
  330.             si.fuScroll = SW_INVALIDATE | SW_ERASE;
  331.             si.pfnScrollProc = ListView_LScroll2_SmoothScroll;
  332.             SmoothScrollWindow(&si);
  333.         }
  334.         UpdateWindow(plv->ci.hwnd);
  335.     }
  336. #else
  337.     if (dy)
  338.     {
  339.         dy *= plv->cyItem;
  340.         {
  341.             SMOOTHSCROLLINFO si;
  342.             si.cbSize = sizeof(si);
  343.             si.fMask = SSIF_SCROLLPROC;
  344.             si.hwnd = plv->ci.hwnd;
  345.             si.dx = 0;
  346.             si.dy = -dy;
  347.             si.lprcSrc = NULL;
  348.             si.lprcClip = NULL;
  349.             si.hrgnUpdate = NULL;
  350.             si.lprcUpdate = NULL;
  351.             si.fuScroll = SW_INVALIDATE | SW_ERASE;
  352.             si.pfnScrollProc = ListView_LScroll2_SmoothScroll;
  353.             SmoothScrollWindow(&si);
  354.         }
  355.         UpdateWindow(plv->ci.hwnd);
  356.     }
  357. #endif
  358. }
  359. void NEAR ListView_LOnScroll(LV* plv, UINT code, int posNew, UINT sb)
  360. {
  361.     RECT rcClient;
  362.     int cPage;
  363.     if (plv->hwndEdit)
  364.         ListView_DismissEdit(plv, FALSE);
  365.     ListView_GetClientRect(plv, &rcClient, TRUE, NULL);
  366. #ifdef COLUMN_VIEW
  367.     cPage = (rcClient.right - rcClient.left) / plv->cxItem;
  368.     ListView_ComOnScroll(plv, code, posNew, SB_HORZ, 1,
  369.                          cPage ? cPage : 1);
  370. #else
  371.     cPage = (rcClient.bottom - rcClient.top) / plv->cyItem;
  372.     ListView_ComOnScroll(plv, code, posNew, SB_VERT, 1,
  373.                          cPage ? cPage : 1);
  374. #endif
  375. }
  376. int NEAR ListView_LGetScrollUnitsPerLine(LV* plv, UINT sb)
  377. {
  378.     return 1;
  379. }
  380. //------------------------------------------------------------------------------
  381. //
  382. // Function: ListView_LCalcViewItem
  383. //
  384. // Summary: This function will calculate which item slot is at the x, y location
  385. //
  386. // Arguments:
  387. //    plv [in] -  The list View to work with
  388. //    x [in] - The x location
  389. //    y [in] - The y location
  390. //
  391. // Returns: the valid slot the point was within.
  392. //
  393. //  Notes:
  394. //
  395. //  History:
  396. //    Nov-3-94 MikeMi   Created
  397. //
  398. //------------------------------------------------------------------------------
  399. int ListView_LCalcViewItem( LV* plv, int x, int y )
  400. {
  401.    int iItem;
  402.    int iRow = 0;
  403.    int iCol = 0;
  404.    ASSERT( plv );
  405. #ifdef COLUMN_VIEW
  406.    iRow = y / plv->cyItem;
  407.    iRow = max( iRow, 0 );
  408.    iRow = min( iRow, plv->cItemCol - 1 );
  409.    iCol = (x + plv->xOrigin) / plv->cxItem;
  410.    iItem = iRow + iCol * plv->cItemCol;
  411. #else
  412.    iCol = x / plv->cxItem;
  413.    iCol = max( iCol, 0 );
  414.    iCol = min( iCol, plv->cItemCol - 1 );
  415.    iRow = (y + plv->xOrigin) / plv->cyItem;
  416.    iItem = iCol + iRow * plv->cItemCol;
  417. #endif
  418.    iItem = max( iItem, 0 );
  419.    iItem = min( iItem, ListView_Count(plv) - 1);
  420.    return( iItem );
  421. }
  422. int LV_GetNewColWidth(LV* plv, int iFirst, int iLast)
  423. {
  424.     int cxMaxLabel = 0;
  425.     // Don't do anything stupid if there are no items to measure
  426.     if (iFirst <= iLast)
  427.     {
  428.         LVFAKEDRAW lvfd;
  429.         LV_ITEM lvitem;
  430.         LISTITEM item;
  431.         if (ListView_IsOwnerData( plv ))
  432.         {
  433.             int iViewFirst;
  434.             int iViewLast;
  435.             iViewFirst = ListView_LCalcViewItem( plv, 1, 1 );
  436.             iViewLast = ListView_LCalcViewItem( plv,
  437.                                                plv->sizeClient.cx - 1,
  438.                                                plv->sizeClient.cy - 1 );
  439.             if ((iLast - iFirst) > (iViewLast - iViewFirst))
  440.             {
  441.                 iFirst = max( iFirst, iViewFirst );
  442.                 iLast = min( iLast, iViewLast );
  443.             }
  444.             iLast = min( ListView_Count( plv ), iLast );
  445.             iFirst = max( 0, iFirst );
  446.             iLast = max( iLast, iFirst );
  447.             ListView_NotifyCacheHint( plv, iFirst, iLast );
  448.         }
  449.         ListView_BeginFakeCustomDraw(plv, &lvfd, &lvitem);
  450.         lvitem.iSubItem = 0;
  451.         lvitem.mask = LVIF_PARAM;
  452.         item.lParam = 0;
  453.         while (iFirst <= iLast)
  454.         {
  455.             LISTITEM FAR* pitem;
  456.             if (ListView_IsOwnerData( plv ))
  457.             {
  458.                 pitem = &item;
  459.                 pitem->cxSingleLabel = SRECOMPUTE;
  460.             }
  461.             else
  462.             {
  463.                 pitem = ListView_FastGetItemPtr(plv, iFirst);
  464.             }
  465.             if (pitem->cxSingleLabel == SRECOMPUTE)
  466.             {
  467.                 lvitem.iItem = iFirst;
  468.                 lvitem.lParam = pitem->lParam;
  469.                 ListView_BeginFakeItemDraw(&lvfd);
  470.                 ListView_RecomputeLabelSize(plv, pitem, iFirst, lvfd.nmcd.nmcd.hdc, FALSE);
  471.                 ListView_EndFakeItemDraw(&lvfd);
  472.             }
  473.             if (pitem->cxSingleLabel > cxMaxLabel)
  474.                 cxMaxLabel = pitem->cxSingleLabel;
  475.             iFirst++;
  476.         }
  477.         ListView_EndFakeCustomDraw(&lvfd);
  478.     }
  479.     // We have the max label width, see if this plus the rest of the slop will
  480.     // cause us to want to resize.
  481.     //
  482.     cxMaxLabel += plv->cxSmIcon + g_cxIconMargin + plv->cxState;
  483.     if (cxMaxLabel > g_cxScreen)
  484.         cxMaxLabel = g_cxScreen;
  485.     return cxMaxLabel;
  486. }
  487. //------------------------------------------------------------------------------
  488. // This function will see if the size of column should be changed for the listview
  489. // It will check to see if the items between first and last exceed the current width
  490. // and if so will see if the columns are currently big enough.  This wont happen
  491. // if we are not currently in listview or if the caller has set an explicit size.
  492. //
  493. // OWNERDATA CHANGE
  494. // This function is normally called with the complete list range,
  495. // This will has been changed to be called only with currently visible
  496. // to the user when in OWNERDATA mode.  This will be much more effiencent.
  497. //
  498. BOOL FAR PASCAL ListView_MaybeResizeListColumns(LV* plv, int iFirst, int iLast)
  499. {
  500.     HDC hdc = NULL;
  501.     int cxMaxLabel;
  502.     if (!ListView_IsListView(plv) || (plv->flags & LVF_COLSIZESET))
  503.         return(FALSE);
  504.     cxMaxLabel = LV_GetNewColWidth(plv, iFirst, iLast);
  505.     // Now see if we should resize the columns...
  506.     if (cxMaxLabel > plv->cxItem)
  507.     {
  508.         int iScroll = plv->xOrigin / plv->cxItem;
  509.         TraceMsg(TF_LISTVIEW, "LV Resize Columns: %d", cxMaxLabel);
  510.         ListView_ISetColumnWidth(plv, 0, cxMaxLabel, FALSE);
  511.         plv->xOrigin = iScroll * plv->cxItem;
  512.         return(TRUE);
  513.     }
  514.     return(FALSE);
  515. }