797 lines
17 KiB
C++
797 lines
17 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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:
|
||
|
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
|
||
|
|
||
|
|