//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 2000. // // File: brview.cxx // // Contents: // // History: 15 Aug 1996 DLee Created // //-------------------------------------------------------------------------- #include #pragma hdrstop #define TheModel _layout.GetModel() #define UNICODE_PARAGRAPH_SEPARATOR 0x2029 const int BUFLEN = 256; WCHAR LineBuffer[BUFLEN]; const int cpLeftMargin = 3; int TrimEOL (WCHAR * pwcLine, int cwcLine) { // If the line ends in \r\n or \n, don't include that in the length. // TabbedTextOut() prints garbage when it sees \r or \n if ((cwcLine >= 2) && (pwcLine[cwcLine - 2] == L'\r')) cwcLine -= 2; else if ((cwcLine >= 1) && ((pwcLine[cwcLine - 1] == L'\r') || (pwcLine[cwcLine - 1] == UNICODE_PARAGRAPH_SEPARATOR) || (pwcLine[cwcLine - 1] == L'\n'))) cwcLine--; return cwcLine; } //TrimEOL void TextMetrics::GetSizes ( CharDim& dim ) { dim.cxChar = _tm.tmAveCharWidth; dim.cyChar = _tm.tmHeight + _tm.tmExternalLeading; } //GetSizes void View::_NoSelection() { _Selection.None(); } //NoSelection void View::_UpdateSelection( LPARAM lParam ) { int x = (int) (short) LOWORD( lParam ); int y = (int) (short) HIWORD( lParam ); if ( y < 0 ) y = 0; else if ( y > _cyClient ) y = _cyClient; int para, o; GetParaAndOffset( x, y, para, o ); if ( _fStartIsAnchor ) { if ( ( para < _Selection.ParaStart() ) || ( ( para == _Selection.ParaStart() ) && ( o < _Selection.OffStart() ) ) ) { _Selection.SetEnd( _Selection.ParaStart(), _Selection.OffStart() ); _Selection.SetStart( para, o ); _fStartIsAnchor = FALSE; } else { _Selection.SetEnd( para, o ); } } else { if ( ( para > _Selection.ParaEnd() ) || ( ( para == _Selection.ParaEnd() ) && ( o > _Selection.OffEnd() ) ) ) { _Selection.SetStart( _Selection.ParaEnd(), _Selection.OffEnd() ); _Selection.SetEnd( para, o ); _fStartIsAnchor = TRUE; } else { _Selection.SetStart( para, o ); } } if ( _fFullSelRepaint ) { InvalidateRect( _hwnd, NULL, FALSE ); _fFullSelRepaint = FALSE; } else { int yMin = __min( y, _cpLastSelY ); int yMax = __max( y, _cpLastSelY ); RECT rc; rc.left = 0; rc.right = _cxClient; rc.top = yMin - LineHeight(); rc.bottom = yMax + LineHeight(); InvalidateRect( _hwnd, &rc, FALSE ); } _cpLastSelY = y; } //_UpdateSelection void View::ButtonUp( WPARAM wParam, LPARAM lParam ) { _fSelecting = FALSE; if ( GetCapture() == _hwnd ) ReleaseCapture(); if ( _fDblClk ) return; if ( _Selection.IsNull() ) { _Selection.None(); return; } else { _UpdateSelection( lParam ); } } //ButtonUp void View::MouseMove( WPARAM wParam, LPARAM lParam ) { if ( _fSelecting && ( wParam & MK_LBUTTON ) ) _UpdateSelection( lParam ); } //MouseMove void View::ButtonDown( WPARAM wParam, LPARAM lParam ) { BOOL fOldSel = _Selection.SelectionExists(); _fDblClk = FALSE; SetCapture( _hwnd ); _fStartIsAnchor = TRUE; _fSelecting = TRUE; _NoSelection(); int x = LOWORD( lParam ); int y = HIWORD( lParam ); _cpLastSelY = y; int para, o; GetParaAndOffset( x, y, para, o ); _Selection.SetStart( para, o ); _fFullSelRepaint = FALSE; if ( fOldSel ) InvalidateRect( _hwnd, NULL, FALSE ); } //ButtonDown int GetCharOffset( HDC hdc, int iClickX, WCHAR * pwcLine, int cwcLine, int cpLeft ) { // a click in the left margin counts if ( 0 != cwcLine && iClickX < cpLeft ) return 0; int l = cpLeft; for ( int c = 0; c < cwcLine; c++ ) { int dx = LOWORD( GetTabbedTextExtent( hdc, pwcLine, 1 + c, 0, 0 ) ); if ( iClickX >= l && iClickX <= dx + cpLeft ) break; l = dx + cpLeft; } return c; } //GetCharOffset void View::GetParaAndOffset( int x, int y, int & para, int & offset ) { offset = 0; HDC hdc = GetDC( _hwnd ); if ( 0 == hdc ) return; HFONT hOldFont = (HFONT) SelectObject( hdc, _layout.Font() ); para = _layout.FirstPara(); int paLine = _layout.FirstLineInPara(); // line within paragraph int paOffBeg; // line beginning offset within paragraph int paOffEnd; // line end offset within paragraph int line = 0; // line # counting from top of window int left = cpLeftMargin - _layout.XBegin(); while ( _layout.GetLineOffsets( para, paLine, paOffBeg, paOffEnd ) ) { do { int top = _layout.Y ( line ); int bottom = top + _layout.CyChar(); if ( y >= top && y <= bottom ) { // got the line, now find the word selected int cwcLine = __min ( BUFLEN, paOffEnd - paOffBeg ); if ( TheModel.GetLine(para, paOffBeg, cwcLine, LineBuffer ) ) { cwcLine = TrimEOL( LineBuffer, cwcLine ); offset = paOffBeg + GetCharOffset( hdc, x, LineBuffer, cwcLine, cpLeftMargin ); } goto cleanup; } line++; if (line >= _layout.MaxLines()) goto cleanup; paLine++; } while ( _layout.GetLineOffsets( para, paLine, paOffBeg, paOffEnd ) ); // next paragraph para++; paLine = 0; } cleanup: SelectObject( hdc, hOldFont ); ReleaseDC( _hwnd, hdc ); } //GetParaAndOffset void View::EditCopy( HWND hwnd, WPARAM wParam ) { if ( _Selection.SelectionExists() ) { // is everything in one paragraph? -- easy case if ( _Selection.IsInOnePara() ) { int cwcLine = __min ( BUFLEN, _Selection.OffEnd() - _Selection.OffStart() ); TheModel.GetLine( _Selection.ParaStart(), _Selection.OffStart(), cwcLine, LineBuffer ); cwcLine = TrimEOL( LineBuffer, cwcLine ); LineBuffer[cwcLine] = 0; PutInClipboard( LineBuffer ); } else { // compute how much text to copy int cwcTotal = 0; for ( int p = _Selection.ParaStart(); p <= _Selection.ParaEnd(); p++ ) { int cwcLine = BUFLEN; if ( p == _Selection.ParaStart() ) { TheModel.GetLine( p, _Selection.OffStart(), cwcLine, LineBuffer ); } else if ( p == _Selection.ParaEnd() ) { TheModel.GetLine( p, 0, cwcLine, LineBuffer ); cwcLine = _Selection.OffEnd(); } else { TheModel.GetLine( p, 0, cwcLine, LineBuffer ); } cwcTotal += cwcLine; } // allocate a buffer and copy the text XArray aClip( cwcTotal + 1 ); WCHAR *pwc = (WCHAR *) aClip.GetPointer(); cwcTotal = 0; for ( p = _Selection.ParaStart(); p <= _Selection.ParaEnd(); p++ ) { int cwcLine = BUFLEN; if ( p == _Selection.ParaStart() ) { TheModel.GetLine( p, _Selection.OffStart(), cwcLine, LineBuffer ); } else if ( p == _Selection.ParaEnd() ) { TheModel.GetLine( p, 0, cwcLine, LineBuffer ); cwcLine = _Selection.OffEnd(); } else { TheModel.GetLine( p, 0, cwcLine, LineBuffer ); } LineBuffer[cwcLine] = 0; wcscpy( pwc + cwcTotal, LineBuffer ); cwcTotal += cwcLine; } PutInClipboard( pwc ); } } } //EditCopy BOOL isWhite( WCHAR c ) { // well, actually white space and C++ break characters return ( L' ' == c || L'\r' == c || L'\n' == c || L'\t' == c || L'\\' == c || L'\'' == c || L'\"' == c || L':' == c || L';' == c || L',' == c || L'[' == c || L']' == c || L'{' == c || L'}' == c || L'(' == c || L')' == c || L'/' == c || L'+' == c || L'-' == c || L'=' == c || L'*' == c || L'^' == c || L'~' == c || L'&' == c || L'!' == c || L'?' == c || L'<' == c || L'>' == c || L'.' == c || L'|' == c || UNICODE_PARAGRAPH_SEPARATOR == c ); } //isWhite BOOL GetSelectedWord( HDC hdc, int iClickX, WCHAR *pwcLine, int cwcLine, int cpLeft, int &rStart, int &rEnd ) { // what character had the click? int c = GetCharOffset( hdc, iClickX, pwcLine, cwcLine, cpLeft ); // move left and right till white space is found if ( c != cwcLine ) { rEnd = c; while ( rEnd < (cwcLine - 1) && !isWhite( pwcLine[ rEnd ] ) ) rEnd++; // selection doesn't include end if ( ( rEnd == ( cwcLine - 1 ) ) && ( !isWhite( pwcLine[ rEnd ] ) ) ) rEnd++; rStart = c; while ( rStart > 0 && !isWhite( pwcLine[ rStart ] ) ) rStart--; // don't include white space if not at start of line if ( rStart < c && isWhite( pwcLine[ rStart ] ) ) rStart++; // did we grab anything? return ( rEnd > rStart ); } else { return FALSE; } } //GetSelectedWord int View::ParaFromY( int y ) { int para = _layout.FirstPara(); int paLine = _layout.FirstLineInPara(); // line within paragraph int paOffBeg; // line beginning offset within paragraph int paOffEnd; // line end offset within paragraph int line = 0; // line # counting from top of window int left = cpLeftMargin - _layout.XBegin(); while ( _layout.GetLineOffsets( para, paLine, paOffBeg, paOffEnd ) ) { do { int top = _layout.Y( line ); int bottom = top + _layout.CyChar(); if ( y >= top && y <= bottom ) { return 1 + para; } line++; if (line >= _layout.MaxLines()) return _layout.FirstPara(); paLine++; } while ( _layout.GetLineOffsets( para, paLine, paOffBeg, paOffEnd ) ); // next paragraph para++; paLine = 0; } return _layout.FirstPara(); } //ParaFromY void View::DblClk( WPARAM wParam, LPARAM lParam ) { _fDblClk = TRUE; BOOL fCtrl = ( 0 != ( 0x8000 & GetAsyncKeyState( VK_CONTROL ) ) ); int x = LOWORD( lParam ); int y = HIWORD( lParam ); Selection oldSel( _Selection ); _Selection.None(); HDC hdc = GetDC( _hwnd ); if ( 0 == hdc ) return; HFONT hOldFont = (HFONT) SelectObject( hdc, _layout.Font() ); int para = _layout.FirstPara(); int paLine = _layout.FirstLineInPara(); // line within paragraph int paOffBeg; // line beginning offset within paragraph int paOffEnd; // line end offset within paragraph int line = 0; // line # counting from top of window int left = cpLeftMargin - _layout.XBegin(); while (_layout.GetLineOffsets ( para, paLine, paOffBeg, paOffEnd )) { do { int top = _layout.Y ( line ); int bottom = top + _layout.CyChar(); if ( y >= top && y <= bottom ) { // if ctrl key is down, attempt to fire up an editor if ( fCtrl ) { ViewFile( _pModel->Filename(), fileEdit, 1+para ); goto cleanup; } // got the line, now find the word selected int cwcLine = __min ( BUFLEN, paOffEnd - paOffBeg ); if ( TheModel.GetLine(para, paOffBeg, cwcLine, LineBuffer ) ) { cwcLine = TrimEOL( LineBuffer, cwcLine ); int iStart, iEnd; if ( GetSelectedWord( hdc, x, LineBuffer, cwcLine, cpLeftMargin, iStart, iEnd ) ) _Selection.Set( para, paOffBeg + iStart, para, paOffBeg + iEnd ); RECT rc; rc.left = 0; rc.right = _cxClient; rc.top = top; rc.bottom = bottom; InvalidateRect( _hwnd, &rc, FALSE ); } } else if ( oldSel.IsInSelection( para ) ) { RECT rc; rc.left = 0; rc.right = _cxClient; rc.top = top; rc.bottom = bottom; InvalidateRect( _hwnd, &rc, FALSE ); } line++; if (line >= _layout.MaxLines()) goto cleanup; paLine++; } while (_layout.GetLineOffsets (para, paLine, paOffBeg, paOffEnd )); // next paragraph para++; paLine = 0; } cleanup: SelectObject( hdc, hOldFont ); ReleaseDC( _hwnd, hdc ); UpdateWindow( _hwnd ); } //DblClk void View::Size ( int cx, int cy ) { _cyClient = cy; _cxClient = cx; } void View::SetScrollMax () { int linesFromEnd = _cyClient / _layout.CyChar() - 2; int cline; for (int para = TheModel.Paras() - 1; para >= 0; para--) { cline = _layout.LinesInPara(para); if (linesFromEnd < cline) break; linesFromEnd -= cline; } _paraVScrollMax = TheModel.Paras() - 1; if ( _paraVScrollMax < 0 ) { _paraVScrollMax = 0; _paLineVScrollMax = 0; } else { _paLineVScrollMax = cline - 1 - linesFromEnd; } } void View::SetRange ( int maxParaLen, int cParas ) { _layout.SetParaRange(cParas); #if 0 _nHScrollMax = 2 + maxParaLen - _cxClient / _layout.CxChar(); if ( _nHScrollMax < 0 ) #endif _nHScrollMax = 0; } void View::SetScroll( Position & pos ) { _fFullSelRepaint = TRUE; int paLine, paOffBeg, paOffEnd; _layout.Locate (pos.Para(), pos.BegOff(), paLine, paOffBeg, paOffEnd); if (paLine >= 3) { _paraVScroll = pos.Para(); _paLineVScroll = paLine - 3; } else { // show last line of prev para int iOffset = ( 0 == _cyClient ) ? 6 : ( VisibleLines() / 3 ); _paraVScroll = pos.Para() - iOffset; if (_paraVScroll >= 0 ) { _paLineVScroll = _layout.LinesInPara(_paraVScroll) - 1; } else { _paraVScroll = 0; _paLineVScroll = 0; } } #if 0 if ( pos.EndOff() - _nHScrollPos + 1 > _cxClient / _layout.CxChar() ) _nHScrollPos = pos.EndOff() - _cxClient / _layout.CxChar() + 1; else _nHScrollPos = 0; _nHScrollPos = min ( _nHScrollPos, _nHScrollMax ); #else _nHScrollPos = 0; #endif } int View::JumpToPara ( int para ) { _fFullSelRepaint = TRUE; int delta = 0; int paraStart; int paraEnd; if (para == _paraVScroll) { return 0; } else if (para < _paraVScroll) { // jumping backwards, delta negative delta = -_paLineVScroll; for ( int p = _paraVScroll - 1; p >= para; p--) delta -= _layout.LinesInPara(p); } else { // jumping forward, delta positive delta = _layout.LinesInPara(_paraVScroll) - _paLineVScroll; for (int p = _paraVScroll + 1; p < para; p++) delta += _layout.LinesInPara(p); } _paraVScroll = para; _paLineVScroll = 0; // return delta from previous position return delta; } int View::IncVScrollPos ( int cLine ) { _fFullSelRepaint = TRUE; int para; if (cLine >= 0) { // first back up to the beginning // of the current para int cLineLeft = cLine + _paLineVScroll; // move forward for (para = _paraVScroll; para <= _paraVScrollMax; para++) { int ln = _layout.LinesInPara(para); if (cLineLeft < ln) break; cLineLeft -= ln; } if (para > _paraVScrollMax) { // overshot the end // move back _paraVScroll = _paraVScrollMax; int cline = _layout.LinesInPara(_paraVScroll); _paLineVScroll = _paLineVScrollMax; cLineLeft += cline - _paLineVScrollMax; cLine -= cLineLeft; } else if (para == _paraVScrollMax && cLineLeft > _paLineVScrollMax) { _paraVScroll = _paraVScrollMax; _paLineVScroll = _paLineVScrollMax; cLineLeft -= _paLineVScrollMax; cLine -= cLineLeft; } else { // cLineLeft < Lines In Para _paraVScroll = para; _paLineVScroll = cLineLeft; } } else if (cLine < 0) { // first skip to the end // of the current para int cLineLeft = - cLine + (_layout.LastLineInPara(_paraVScroll) - _paLineVScroll); // move backward for (para = _paraVScroll; para >= 0; para--) { int ln = _layout.LinesInPara(para); if (ln > cLineLeft) break; cLineLeft -= ln; } if (para < 0) { // overshot the beginning. // move up one line _paraVScroll = 0; _paLineVScroll = 0; cLineLeft++; cLine += cLineLeft; } else { // cLineLeft < Lines In Para _paraVScroll = para; _paLineVScroll = _layout.LinesInPara(para) - cLineLeft - 1; } } return cLine; } int View::IncHScrollPos ( int delta ) { Win4Assert ( FALSE ); // Clip the increment if ( delta < -_nHScrollPos ) delta = -_nHScrollPos; else if ( delta > _nHScrollMax - _nHScrollPos ) delta = _nHScrollMax - _nHScrollPos; _nHScrollPos += delta; return delta; } void View::Paint( HWND hwnd ) { _layout.Adjust ( _cxClient, _cyClient, _paraVScroll, _paLineVScroll, _nHScrollPos); PaintText paint (hwnd, _paraVScroll, _paLineVScroll, _layout, _Selection); paint.PrintLines (); paint.HiliteHits (); } PaintText::PaintText(HWND hwnd, int paraFirst, int paLineFirst, Layout& layout, Selection & Selection ) : Paint(hwnd), _paraFirst(paraFirst), _paLineFirst(paLineFirst), _layout(layout), _Selection( Selection ) { _hOldFont = (HFONT) SelectObject ( hdc, _layout.Font() ); SetBkColor ( hdc, GetSysColor(COLOR_WINDOW) ); SetTextColor( hdc, GetSysColor(COLOR_WINDOWTEXT) ); } PaintText::~PaintText() { SelectObject ( hdc, _hOldFont ); } void Layout::SetParaRange (int cParas) { _cParas = cParas; _aParaLine = _pModel->GetParaLine(); } void Layout::Adjust (int cx, int cy, int& paraVScroll, int& paLineVScroll, int nHScrollPos) { _cLine = (cy + _dim.cyChar - 1) / _dim.cyChar; _cCharWidth = cx / _dim.cxChar; _xBegin = nHScrollPos * _dim.cxChar; if ( paraVScroll < 0 ) { paraVScroll = 0; paLineVScroll = 0; } _paLineFirst = paLineVScroll; _paraFirst = paraVScroll; } int Layout::Y (int line ) const { return line * _dim.cyChar; } void Layout::Locate (int para, int paOff, int& paLine, int& paOffBeg, int& paOffEnd ) const { Win4Assert(para < _cParas); paLine = 0; paOffBeg = 0; for (ParaLine const* p = &_aParaLine[para]; p != 0 && p->offEnd <= paOff; p = p->next) { paOffBeg = p->offEnd; paLine++; } if (p == 0) paOffEnd = 0; else paOffEnd = p->offEnd; } BOOL Layout::GetLineOffsets (int para, int paLine, int& paOffBeg, int& paOffEnd) const { if (para < _paraFirst || para > LastPara() || para >= _cParas) return FALSE; ParaLine const * p = &_aParaLine[para]; paOffBeg = 0; for (int line = 0; line < paLine; line++) { paOffBeg = p->offEnd; p = p->next; if (p == 0) return FALSE; } paOffEnd = p->offEnd; Win4Assert ( paOffEnd >= paOffBeg); return TRUE; } int Layout::LastPara() const { // at most this number return _paraFirst + _cLine; } int Layout::LineNumber (int para, int paLine) const { if (para == _paraFirst) { return paLine - _paLineFirst; } int curPara = _paraFirst + 1; int curLine = LinesInPara(_paraFirst) - _paLineFirst; while (curPara < para) { curLine += LinesInPara(curPara); curPara++; } return curLine + paLine; } int Layout::LinesInPara (int para) const { Win4Assert(para < _cParas); int line = 1; for (ParaLine const * p = _aParaLine[para].next; p != 0; p = p->next) line++; return line; } void EnableHilite( HDC hdc ) { SetBkColor( hdc, GetSysColor(COLOR_HIGHLIGHT) ); SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT) ); } void EnableHitHilite( HDC hdc ) { // SetBkColor( hdc, GetSysColor(COLOR_ACTIVECAPTION) ); // SetTextColor( hdc, GetSysColor(COLOR_CAPTIONTEXT) ); // SetBkColor( hdc, GetSysColor(COLOR_INACTIVECAPTION) ); // SetTextColor( hdc, GetSysColor(COLOR_INACTIVECAPTIONTEXT) ); // SetBkColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT) ); // SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHT) ); SetBkColor( hdc, GetSysColor(COLOR_WINDOWTEXT) ); SetTextColor( hdc, GetSysColor(COLOR_WINDOW) ); // SetBkColor( hdc, GetSysColor(COLOR_HIGHLIGHT) ); // SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT) ); } void EnableNonCurrentHitHilite( HDC hdc ) { SetBkColor ( hdc, GetSysColor(COLOR_WINDOW) ); SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHT) ); } void DisableHilite( HDC hdc ) { SetBkColor ( hdc, GetSysColor(COLOR_WINDOW) ); SetTextColor ( hdc, GetSysColor(COLOR_WINDOWTEXT) ); } void PaintText::PrintLines () { int para = _layout.FirstPara(); int paLine = _layout.FirstLineInPara(); // line within paragraph int paOffBeg; // line beginning offset within paragraph int paOffEnd; // line end offset within paragraph int line = 0; // line # counting from top of window int left = cpLeftMargin - _layout.XBegin(); while (_layout.GetLineOffsets ( para, paLine, paOffBeg, paOffEnd )) { // print paragraph do { // clip to the update rect int top = _layout.Y ( line ); int bottom = top + _layout.CyChar(); if ( top <= rcPaint.bottom && bottom >= rcPaint.top) { int cwcLine = __min ( BUFLEN, paOffEnd - paOffBeg ); if (!TheModel.GetLine( para, paOffBeg, cwcLine, LineBuffer )) return; cwcLine = TrimEOL( LineBuffer, cwcLine ); if ( 0 == cwcLine ) { // to make selections look better... wcscpy(LineBuffer,L" "); cwcLine = 1; } Win4Assert( cwcLine >= 0 ); if ( _Selection.IsInSelection( para ) ) { if ( ( para > _Selection.ParaStart() ) && ( para < _Selection.ParaEnd() ) ) { EnableHilite( hdc ); TabbedTextOut( hdc, left, top, LineBuffer, cwcLine, 0, 0, left ); DisableHilite( hdc ); } else { int l = left; for ( int c = 0; c < cwcLine; c++ ) { if ( _Selection.IsInSelection( para, c + paOffBeg ) ) EnableHilite( hdc ); LONG dim = TabbedTextOut( hdc, l, top, LineBuffer + c, 1, 0, 0, left ); DisableHilite( hdc ); l += LOWORD(dim); } } } else { TabbedTextOut( hdc, left, top, LineBuffer, cwcLine, 0, 0, left ); } } line++; if (line >= _layout.MaxLines()) return; paLine++; } while (_layout.GetLineOffsets( para, paLine, paOffBeg, paOffEnd )); // next paragraph para++; paLine = 0; } } //PrintLines void PaintText::HiliteHits () { TheModel.HiliteAll( TRUE ); if ( TheModel.FirstHit() ) { do { if ( !TheModel.isSavedCurrent() ) PrintCurrentHit( FALSE ); } while( TheModel.NextHit() ); TheModel.RestoreHilite(); } TheModel.HiliteAll( FALSE ); PrintCurrentHit( TRUE ); } //HiliteHits const int WORDBUFLEN = 80; static WCHAR WordBuffer [WORDBUFLEN]; void PaintText::PrintCurrentHit( BOOL fCurrent ) { if ( fCurrent ) EnableHitHilite( hdc ); else EnableNonCurrentHitHilite( hdc ); int cPos = TheModel.GetPositionCount(); int iPos = 0; Position pos = TheModel.GetPosition(iPos); int left = cpLeftMargin - _layout.XBegin(); while ( iPos < cPos ) { int curPara = pos.Para(); if ( curPara > _layout.LastPara() ) break; if (curPara >= _layout.FirstPara()) { int paLine; // line within paragraph int paOffBeg; // line beginning offset within paragraph int paOffEnd; // line end offset within paragraph _layout.Locate ( curPara, pos.BegOff(), paLine, paOffBeg, paOffEnd ); int line = _layout.LineNumber ( curPara, paLine ); // Output the line with highlights int cwcLine = __min ( BUFLEN, paOffEnd - paOffBeg ); if (!TheModel.GetLine (curPara, paOffBeg, cwcLine, LineBuffer )) break; cwcLine = TrimEOL( LineBuffer, cwcLine ); int top = _layout.Y (line); do { int cwc = __min( pos.Len(), WORDBUFLEN); TheModel.GetWord( curPara, pos.BegOff(), cwc, WordBuffer ); Win4Assert ( cwc >= 0 ); // Find out how much space it takes before the highlight DWORD dwExt = GetTabbedTextExtent ( hdc, LineBuffer, pos.BegOff() - paOffBeg, 0, 0 ); // Print hilighted text TabbedTextOut ( hdc, left + LOWORD(dwExt), top, WordBuffer, cwc, 0, 0, left ); iPos++; if (iPos >= cPos) break; pos = TheModel.GetPosition(iPos); } while ( pos.Para() == curPara ); } else { iPos++; } } DisableHilite( hdc ); } //PrintCurrentHit