Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

803 lines
18 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999.
//
// File: lview.cxx
//
// Contents:
//
// History: 15 Aug 1996 DLee Created
//
//--------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
//
// Window procedure for ListView
//
LRESULT WINAPI ListViewWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
CListView *pControl = (CListView *) GetWindowLongPtr(hwnd, 0);
LRESULT lRet = 0;
switch (msg)
{
case WM_CREATE :
pControl = new CListView;
pControl->Create (GetParent(hwnd), hwnd);
SetWindowLongPtr (hwnd, 0, (LONG_PTR) pControl);
break;
case WM_DESTROY :
delete pControl;
lRet = DefWindowProc(hwnd, msg, wParam, lParam);
break;
case WM_SETFONT:
pControl->SetFont ((HFONT)wParam);
break;
case WM_SETFOCUS:
pControl->SetFocus();
lRet = DefWindowProc(hwnd, msg, wParam, lParam);
break;
case wmInsertItem:
pControl->InsertItem ((int)lParam);
break;
case wmDeleteItem:
pControl->DeleteItem ((int)lParam);
break;
case wmUpdateItem:
pControl->InvalidateItem ((int)lParam);
break;
case wmSetCountBefore:
pControl->SetCountBefore ((int)lParam);
break;
case wmSetCount:
pControl->SetTotalCount ((int)lParam);
break;
case wmResetContents:
pControl->ResetContents();
break;
case WM_SIZE:
pControl->Size (wParam, LOWORD(lParam), HIWORD(lParam));
break;
case WM_PAINT:
{
PAINTSTRUCT paint;
BeginPaint ( hwnd, &paint );
pControl->Paint (paint);
EndPaint(hwnd, &paint );
}
break;
case WM_LBUTTONUP:
pControl->ButtonUp(HIWORD(lParam));
break;
case WM_LBUTTONDOWN:
pControl->ButtonDown(HIWORD(lParam));
break;
case WM_LBUTTONDBLCLK:
SendMessage (pControl->Parent(),
WM_COMMAND,
MAKEWPARAM(idListChild, LBN_DBLCLK),
(LPARAM) hwnd);
break;
case WM_KEYDOWN:
pControl->KeyDown ((int)wParam);
break;
case WM_VSCROLL:
pControl->Vscroll ((int)LOWORD(wParam), (int)HIWORD(wParam));
break;
case WM_MOUSEWHEEL :
lRet = pControl->MouseWheel( hwnd, wParam, lParam );
break;
case wmContextMenuHitTest:
lRet = pControl->ContextMenuHitTest( wParam, lParam );
break;
default :
lRet = DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
return lRet;
} //ListViewWndProc
CListView::CListView ()
: _hwndParent(0),
_hwnd(0),
_cBefore(0),
_cTotal (0),
_cx(0),
_cy(0),
_cyLine(1),
_cLines(0),
_hfont(0),
_iWheelRemainder(0)
{}
LRESULT CListView::MouseWheel(
HWND hwnd,
WPARAM wParam,
LPARAM lParam )
{
// forward what we don't process
if ( wParam & ( MK_SHIFT | MK_CONTROL ) )
return DefWindowProc( hwnd, WM_MOUSEWHEEL, wParam, lParam );
// add the current scroll to the remainder from last time
int iDelta = (int) (short) HIWORD( wParam );
iDelta += _iWheelRemainder;
// if there isn't enough to process this time, just return
if ( abs( iDelta ) < WHEEL_DELTA )
{
_iWheelRemainder = iDelta;
return 0;
}
// compute the remainder and amount to scroll
_iWheelRemainder = ( iDelta % WHEEL_DELTA );
iDelta /= WHEEL_DELTA;
BOOL fDown;
if ( iDelta < 0 )
{
fDown = TRUE;
iDelta = -iDelta;
}
else
fDown = FALSE;
// get the # of lines to scroll per WHEEL_DELTA
int cLines;
SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &cLines, 0 );
if ( 0 == cLines )
return 0;
int cVisibleLines = _cLines;
// if scrolling a page, do so. don't scroll more than one page
if ( WHEEL_PAGESCROLL == cLines )
iDelta = __max( 1, (cVisibleLines - 1) );
else
{
iDelta *= cLines;
if ( iDelta >= cVisibleLines )
iDelta = __max( 1, (cVisibleLines - 1) );
}
// phew. do the scroll
if ( 0 != iDelta )
{
if ( fDown )
_GoDown( iDelta );
else
_GoUp( iDelta );
}
return iDelta;
} //MouseWheel
LRESULT CListView::ContextMenuHitTest(
WPARAM wParam,
LPARAM lParam )
{
POINT pt;
// cast required to sign extend [multimon bug]
pt.x = (LONG)(short)LOWORD( lParam );
pt.y = (LONG)(short)HIWORD( lParam );
RECT rc;
GetWindowRect( _hwnd, &rc );
// did they click in the window?
if ( !PtInRect( &rc, pt ) )
return -1;
// convert y to window view coordinates
int vy = pt.y - rc.top;
// did they click on a line in the window?
int line = vy / _cyLine;
int newLine = line;
if ( line >= _cLines || line >= _cTotal )
return -1;
// make this line the current selection
ButtonDown( vy );
return line;
} //ContextMenuHitTest
//
// Create
//
void CListView::Create (HWND hwndParent, HWND hwnd)
{
_hwndParent = hwndParent;
_hwnd = hwnd;
MEASUREITEMSTRUCT measure;
measure.CtlType = odtListView;
//
// Owner: Measure item!
//
SendMessage (_hwndParent, wmMeasureItem, 0, (LPARAM) &measure);
_cyLine = measure.itemHeight;
} //Create
//
// Key Down
//
void CListView::KeyDown (int nKey)
{
switch (nKey)
{
case ' ' :
ButtonDown( 0 );
break;
case 11:
case 13:
// treat ENTER as a double-click
//
// Owner: Double click!
//
SendMessage (_hwndParent, WM_COMMAND, MAKEWPARAM(idListChild, LBN_DBLCLK), (LPARAM) _hwnd);
break;
//
// Translate keystrokes into scrolling actions
//
case VK_HOME:
SendMessage (_hwnd, WM_VSCROLL, SB_TOP, 0L);
break;
case VK_END:
SendMessage (_hwnd, WM_VSCROLL, SB_BOTTOM, 0L);
break;
case VK_PRIOR:
SendMessage (_hwnd, WM_VSCROLL, SB_PAGEUP, 0L);
break;
case VK_NEXT:
SendMessage (_hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L);
break;
case VK_UP:
SelectUp ();
break;
case VK_DOWN:
SelectDown ();
break;
}
} //KeyDown
void CListView::UpdateHighlight(
int oldLine,
int newLine )
{
// unhighlight
if ( -1 != oldLine )
RefreshRow( oldLine );
// highlight
if ( oldLine != newLine )
RefreshRow( newLine );
UpdateWindow (_hwnd);
} //UpdateHighlight
void CListView::SelectUp ()
{
int newLine;
if ( SendMessage( _hwndParent, wmListNotify, listSelectUp, (LPARAM)&newLine ))
UpdateHighlight( newLine + 1, newLine );
} //SelectUp
void CListView::SelectDown ()
{
int newLine;
if ( SendMessage( _hwndParent, wmListNotify, listSelectDown, (LPARAM)&newLine ))
UpdateHighlight( newLine - 1, newLine );
} //SelectDown
//
// Button up (select)
//
void CListView::ButtonUp (int y)
{
}
void CListView::ButtonDown (int y)
{
int line = y / _cyLine;
int newLine = line;
if (line >= _cLines)
return;
//
// Owner: Selection made!
//
if (SendMessage (_hwndParent, wmListNotify, listSelect, (LPARAM)&line ))
UpdateHighlight( line, newLine );
::SetFocus (_hwnd);
} //ButtonDown
void CListView::SetFocus()
{
//
// Owner: Focus!
//
SendMessage (_hwndParent, WM_COMMAND, MAKEWPARAM(idListChild, LBN_SETFOCUS), (LPARAM) _hwnd);
} //SetFocus
//
// Size
//
void CListView::Size (WPARAM flags, int cx, int cy)
{
int cxOld = _cx;
int cyOld = _cy;
_cx = cx;
_cy = cy;
BOOL fInvalidate = FALSE;
if (cy != cyOld)
{
_cLines = cy / _cyLine;
//
// Owner: Size!
//
long cRows = _cLines;
fInvalidate = (BOOL)SendMessage(_hwndParent, wmListNotify, listSize, (LPARAM) &cRows);
}
// Don't repaint the common area
RECT rect;
rect.top = 0;
rect.left = 0;
rect.bottom = min (cy, cyOld);
rect.right = min (cx, cxOld);
// no need -- user does this for free, and it causes repaint bugs
// ValidateRect (_hwnd, &rect );
if (cy != cyOld)
{
if ( fInvalidate )
InvalidateAndUpdateScroll();
else
UpdateScroll();
}
} //Size
//
// Paint
//
void CListView::Paint (PAINTSTRUCT& paint)
{
RECT& rect = paint.rcPaint;
int lineStart = rect.top / _cyLine;
int lineEnd = (rect.bottom + _cyLine - 1) / _cyLine;
DRAWITEMSTRUCT draw;
draw.hwndItem = _hwnd;
draw.itemAction = ODA_DRAWENTIRE;
HDC hdc = paint.hdc;
draw.hDC = hdc;
HFONT hfontOld = (HFONT) SelectObject (hdc, _hfont);
for (int i = lineStart; i < lineEnd; i++)
{
draw.itemState = 0;
if ( GetFocus() == _hwnd )
draw.itemState |= ODS_FOCUS;
draw.itemID = i;
draw.rcItem.top = 0;
draw.rcItem.left = 0;
draw.rcItem.bottom = _cyLine;
draw.rcItem.right = _cx;
SetViewportOrgEx( hdc, 0, i * _cyLine, 0 );
//
// Owner: Draw item!
//
SendMessage (_hwndParent, wmDrawItem, 0, (LPARAM)&draw);
}
SelectObject (hdc, hfontOld);
} //Paint
//
// Set Font
//
void CListView::SetFont (HFONT hfontNew)
{
_hfont = hfontNew;
MEASUREITEMSTRUCT measure;
measure.CtlType = odtListView;
//
// Owner: Measure item
//
SendMessage (_hwndParent, wmMeasureItem, 0, (LPARAM) &measure);
_cyLine = measure.itemHeight;
long cRows = (_cy + _cyLine - 1) / _cyLine;
_cLines = cRows;
//
// Owner: Size
//
SendMessage(_hwndParent, wmListNotify, listSize, (LPARAM) &cRows);
InvalidateAndUpdateScroll();
} //SetFont
//
// Scrolling
//
void CListView::Vscroll ( int action, int nPos)
{
switch (action)
{
case SB_LINEUP:
LineUp ();
break;
case SB_LINEDOWN:
LineDown ();
break;
case SB_THUMBTRACK:
// don't refresh when thumb dragging
// over many hits (too expensive)
break;
case SB_THUMBPOSITION:
if (_cTotal > 65535)
{
SCROLLINFO si; si.cbSize = sizeof si;
si.fMask = SIF_TRACKPOS;
GetScrollInfo (_hwnd, SB_VERT, &si);
nPos = si.nTrackPos;
}
ScrollPos (nPos);
break;
case SB_PAGEDOWN:
PageDown ();
break;
case SB_PAGEUP:
PageUp ();
break;
case SB_TOP:
Top ();
break;
case SB_BOTTOM:
Bottom ();
break;
}
} //VScroll
void CListView::LineUp ()
{
long cLine = 1;
//
// Owner: Line up!
//
SendMessage(_hwndParent, wmListNotify, listScrollLineUp, (LPARAM) &cLine);
if (cLine == 1)
{
if (_cBefore != 0)
_cBefore--;
// Force scroll and redraw
RECT rect;
GetClientRect (_hwnd, &rect);
MyScrollWindow (_hwnd, 0, _cyLine, &rect, &rect);
UpdateScroll();
}
} //LineUp
void CListView::LineDown ()
{
long cLine = 1;
//
// Owner: Line down!
//
SendMessage(_hwndParent, wmListNotify, listScrollLineDn, (LPARAM) &cLine);
if (cLine == 1)
{
RECT rect;
GetClientRect (_hwnd, &rect);
MyScrollWindow (_hwnd, 0, -_cyLine, &rect, &rect);
_cBefore++;
UpdateScroll();
}
} //LineDown
void CListView::_GoUp(
long cToGo )
{
CWaitCursor wait;
long count = cToGo;
count = __min( count, _cBefore );
//
// Owner: Page up!
//
SendMessage(_hwndParent, wmListNotify, listScrollPageUp, (LPARAM) &count);
// _cBefore is approximate; don't give up if it is too big
if ( 0 == count )
{
if ( _cBefore > 0 )
count = _cBefore - 1;
else
count = 1; // worst case; scroll up one line
SendMessage( _hwndParent,
wmListNotify,
listScrollPageUp,
(LPARAM) &count );
}
// gee, we're having a bad hair day
if ( 0 == count )
{
count = 1; // worst case; scroll up one line
SendMessage( _hwndParent,
wmListNotify,
listScrollPageUp,
(LPARAM) &count );
}
if ( 0 != count )
{
// count == number of lines open at the top
_cBefore -= count;
if (_cBefore < 0)
_cBefore = 0;
InvalidateAndUpdateScroll();
}
} //_GoUp
void CListView::PageUp ()
{
_GoUp( _cLines - 1 );
} //PageUp
void CListView::_GoDown(
long cToGo )
{
CWaitCursor wait;
long count = cToGo;
//
// Owner: Page Down!
//
SendMessage(_hwndParent, wmListNotify, listScrollPageDn, (LPARAM) &count);
// count == number of lines open at the bottom
if ( 0 != count )
{
_cBefore += count;
if (_cBefore >= ( _cTotal - _cLines ) )
_cBefore = ( _cTotal - _cLines );
InvalidateAndUpdateScroll();
}
} //_GoDown
void CListView::PageDown ()
{
_GoDown( _cLines - 1 );
} //PageDown
void CListView::Top ()
{
long count = _cLines;
//
// Owner: Top!
//
SendMessage(_hwndParent, wmListNotify, listScrollTop, (LPARAM) &count );
_cBefore = 0;
InvalidateAndUpdateScroll();
} //Top
void CListView::Bottom ()
{
long count = _cLines;
//
// Owner: Bottom!
//
SendMessage(_hwndParent, wmListNotify, listScrollBottom, (LPARAM) &count);
// count == number of lines visible
_cBefore = _cTotal - count;
if (_cBefore < 0)
_cBefore = 0;
InvalidateAndUpdateScroll();
} //Bottom
void CListView::ScrollPos (int pos)
{
long iRow = pos;
//
// Owner: Scroll Position!
//
SendMessage(_hwndParent, wmListNotify, listScrollPos, (LPARAM) &iRow);
if (iRow != -1)
{
_cBefore = iRow;
InvalidateAndUpdateScroll();
}
} //ScrollPos
//
// Message: Reset Contents
//
void CListView::ResetContents()
{
_cBefore = 0;
_cTotal = 0;
UpdateScroll();
RECT rect;
GetClientRect (_hwnd, &rect);
InvalidateRect (_hwnd, &rect, TRUE );
UpdateWindow (_hwnd);
} //ResetContents
void CListView::InvalidateAndUpdateScroll()
{
RECT rect;
GetClientRect (_hwnd, &rect);
InvalidateRect (_hwnd, &rect, TRUE );
UpdateScroll();
} //InvalidateAndUpdateScroll
//
// Message: Insert item after iRow
//
void CListView::InsertItem (int iRow)
{
Win4Assert (iRow < _cLines );
RECT rect;
GetClientRect (_hwnd, &rect);
rect.top = (iRow + 1) * _cyLine;
MyScrollWindow( _hwnd, 0, _cyLine, &rect, &rect, FALSE );
_cTotal++;
UpdateWindow (_hwnd);
UpdateScroll();
} //InsertItem
//
// Message: Delete item
//
void CListView::DeleteItem (int iRow)
{
Win4Assert (iRow < _cLines );
RECT rect;
GetClientRect (_hwnd, &rect);
rect.top = (iRow + 1) * _cyLine;
MyScrollWindow( _hwnd, 0, -_cyLine, &rect, &rect, FALSE );
_cTotal--;
if (_cTotal < 0)
_cTotal = 0;
// Invalidate the area which was
// scrolled up (the last row before scrolling), if visible
if ( _cTotal && _cTotal < _cLines )
{
RefreshRow( _cTotal );
}
UpdateScroll();
} //DeleteItem
//
// Message: Invalidate item
//
void CListView::InvalidateItem (int iRow)
{
Win4Assert (iRow <= _cLines );
RefreshRow (iRow);
UpdateWindow (_hwnd);
} //InvalidateItem
//
// Message: Set count before
//
void CListView::SetCountBefore (int cBefore)
{
_cBefore = cBefore;
SetScrollPos (_hwnd, SB_VERT, _cBefore, TRUE);
} //SetCountBefore
//
// Message: Set total count
//
void CListView::SetTotalCount (int cTotal)
{
_cTotal = cTotal;
UpdateScroll ();
} //SetTotalCount
//
// Internal methods
//
void CListView::RefreshRow (int iRow)
{
Win4Assert ( iRow < _cLines );
RECT rect;
rect.top = iRow * _cyLine;
rect.left = 0;
rect.bottom = rect.top + _cyLine;
rect.right = _cx;
InvalidateRect (_hwnd, &rect, TRUE );
} //RefreshRow
void CListView::UpdateScroll()
{
if (_cTotal - _cLines >= 0)
{
ShowScrollBar( _hwnd, SB_VERT, TRUE );
SetScrollRange (_hwnd, SB_VERT, 0, _cTotal - 1, FALSE);
SetScrollPos (_hwnd, SB_VERT, _cBefore, TRUE);
// proportional scroll box
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_PAGE;
si.nPage = _cLines;
SetScrollInfo( _hwnd, SB_VERT, &si, TRUE );
EnableScrollBar (_hwnd, SB_VERT, ESB_ENABLE_BOTH );
}
else
{
_cBefore = 0;
ShowScrollBar( _hwnd, SB_VERT, FALSE );
EnableScrollBar (_hwnd, SB_VERT, ESB_DISABLE_BOTH );
}
} //UpdateScroll