// Class Semantics for TextView windows // Created 5 August 1992 by Ron Murray #include "stdafx.h" #include "FTSrch.h" #include "TxDBase.h" #include "TextView.h" #include "usermsgs.h" #include "ftslex.h" //rmk #include "CSHelp.h" extern HINSTANCE hinstDLL; BOOL CTextView::RegisterWndClass(HINSTANCE hInstance) { PSZ szName = "TextViewer"; WNDCLASS wndcls; // see if the class already exists if (::GetClassInfo(hInstance, szName, &wndcls)) return TRUE; // otherwise we need to register a new class wndcls.style = CS_DBLCLKS; wndcls.lpfnWndProc = &CTextView::WindowProc; wndcls.cbClsExtra = 0; wndcls.cbWndExtra = 4; wndcls.hInstance = hInstance; wndcls.hIcon = NULL; wndcls.hCursor = hcurArrow; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; wndcls.lpszClassName = szName; return ::RegisterClass(&wndcls); } HWND CTextView::OpenWindow(PSZ pszWindowName, RECT *prc, HINSTANCE hinst, HWND hwndParent) { ASSERT(!m_hwnd); HWND hwnd= CreateWindow("TextViewer", pszWindowName, WS_CHILD | WS_TABSTOP | WS_VISIBLE, prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top, hwndParent, NULL, hinst, this ); ASSERT(hwnd); m_hwnd= hwnd; return hwnd; } LRESULT CALLBACK CTextView::WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { CTextView *ptv= (CTextView *) GetWindowLong(hwnd, GWL_USERDATA); if (!ptv) return ::DefWindowProc(hwnd, msg, wparam, lparam); switch (msg) { case WM_HELP: case WM_CONTEXTMENU: return SendMessage(GetParent(hwnd), msg, wparam, lparam); case WM_GETDLGCODE: return DLGC_WANTARROWS; case WM_ERASEBKGND: return ptv->OnEraseBkgnd(HDC(wparam)); case WM_PAINT: ptv->OnPaint(); return 0; case WM_SIZE: ptv->OnSize(wparam, LOWORD(lparam), HIWORD(lparam)); return 0; case WM_WINDOWPOSCHANGED: ptv->OnWindowPosChanged((WINDOWPOS *) lparam); return 0; case WM_SETFOCUS: ptv->OnSetFocus((HWND) wparam); return 0; case WM_KILLFOCUS: ptv->OnKillFocus((HWND) wparam); return 0; case WM_LBUTTONDOWN: ptv->OnLButtonDown(wparam, MAKEPOINTS(lparam)); return 0; case WM_LBUTTONDBLCLK: ptv->OnLButtonDblClk(wparam, MAKEPOINTS(lparam)); return 0; case WM_LBUTTONUP: ptv->OnLButtonUp(wparam, MAKEPOINTS(lparam)); return 0; case WM_MOUSEMOVE: ptv->OnMouseMove(wparam, MAKEPOINTS(lparam)); return 0; case WM_MOUSEACTIVATE: return ptv->OnMouseActivate((HWND) wparam, LOWORD(lparam), HIWORD(lparam)); case WM_NCHITTEST: return ptv->OnNcHitTest(MAKEPOINTS(lparam)); case WM_SETCURSOR: return ptv->OnSetCursor((HWND) wparam, LOWORD(lparam), HIWORD(lparam)); case WM_TIMER: ptv->OnTimer(wparam); return 0; case WM_KEYDOWN: ptv->OnKeyDown(wparam, LOWORD(lparam), HIWORD(lparam)); return 0; case WM_KEYUP: ptv->OnKeyUp(wparam, LOWORD(lparam), HIWORD(lparam)); return 0; default: return ::DefWindowProc(hwnd, msg, wparam, lparam); } } // CTextView constructor: // Create the text view window with the appropriate style, size, menu, etc. CTextView::CTextView() { m_hwnd = NULL; m_ptdm = NULL; m_pbText = NULL; m_cbText = 0; m_fGotFocus = FALSE; m_fMouseCaptured = FALSE; m_fSwallowMouseActivate = FALSE; m_fMarquee = FALSE; m_fMarqueeActive = FALSE; m_fMarqueePhase = FALSE; m_fMarqueeTimerOn = FALSE; m_fTimerActive = FALSE; m_hTimer = 0; m_idTimer = 0; m_cImageFullRows = 0; m_cImageFullCols = 0; m_cImageRows = 0; m_cImageCols = 0; m_lTopLine = 0; m_iLeftCol = 0; m_nCxChar = 0; m_nCyChar = 0; m_clrfg = 0; m_clrbg = 0xFFFFFF; m_iCharsetAlternate = 0xFFFFFF; m_iCharset = 0; m_iHeight = 0; m_rowFocus = 0; m_colFocus = 0; m_cRowsFocus = 1; m_cColsFocus = 1; m_cHighlightsAllocated = 0; m_cHighlightsActive = 0; m_clFileRows = 0; m_clFileCols = 0; m_cLinesScrollContext = 0; m_cCharsets = 0; m_pHighlights = NULL; m_fpOldWndProc = NULL; m_pba = NULL; m_hFontDefault = NULL; m_hFontAlternate = NULL; m_hFont = NULL; m_pCharsets = NULL; m_hCheck = NULL; m_hNoCheck = NULL; m_iCheckHeight = 0; m_iCheckWidth = 0; m_bUseCheck = FALSE; m_pba = NULL; } CTextView *CTextView::NewTextView() { CTextView *ptv= NULL; __try { ptv= New CTextView; ptv->Init(); } __finally { if (_abnormal_termination() && ptv) { delete ptv; ptv= NULL; } } return ptv; } CTextView *CTextView::NewTextView(PSZ pszWindowName, RECT *prc, HINSTANCE hinst, HWND hwndParent) { CTextView *ptv= NULL; __try { ptv= New CTextView; ptv->Init(); ptv->OpenWindow(pszWindowName, prc, hinst, hwndParent); } __finally { if (_abnormal_termination() && ptv) { delete ptv; ptv= NULL; } } return ptv; } static UINT iCharsetDefault = UINT(-1); UINT DefaultCharacterSet() { if (iCharsetDefault != UINT(-1)) return iCharsetDefault; TEXTMETRIC tm; HDC hdc; iCharsetDefault= ANSI_CHARSET; hdc= GetDC(NULL); if (!hdc) return iCharsetDefault; if (GetTextMetrics(hdc, &tm)) iCharsetDefault= tm.tmCharSet; return iCharsetDefault; } void CTextView::Init() { AttachRef(m_pba, New CByteVector); } // SetFont for drawing the list boxes void CTextView::SetFont(HFONT hFont) { ASSERT( hFont); // Dont call me with a bogus font please ASSERT(!m_hFont); // Must not have a font installed already m_hFont = hFont; HDC hdc= GetDC(m_hwnd); HGDIOBJ hsavFont= ::SelectObject(hdc, hFont); ::GetTextMetrics(hdc, &m_FontMetrics); ::SelectObject(hdc, hsavFont); m_nCxChar = m_FontMetrics.tmMaxCharWidth; m_nCyChar = m_FontMetrics.tmHeight + m_FontMetrics.tmExternalLeading; m_LeftMargin = m_nCxChar >> 1; RECT rc; GetWindowRect(m_hwnd, &rc); OnSize(SIZENORMAL, rc.right - rc.left, rc.bottom - rc.top); LOGFONT lf; ::GetObject(hFont, sizeof(lf), &lf); m_iCharset= lf.lfCharSet; ::ReleaseDC(m_hwnd, hdc); Invalidate(); } // Release the drawing font and go back to the default font HGDIOBJ CTextView::ReleaseFont() { ASSERT(m_hFont); // Don't call me if the font has not be set first! HGDIOBJ hTemp = m_hFont; m_hFont = NULL; return hTemp; } CTextView *CTextView::NewTextView(CTextMatrix * ptdm) { CTextView *ptv= NULL; __try { ptv= New CTextView; ptv->Init(ptdm); } __finally { if (_abnormal_termination() && ptv) { delete ptv; ptv= NULL; } } return ptv; } void CTextView::Init(CTextMatrix * ptdm) { Init(); if (ptdm) { AttachRef(m_ptdm, ptdm); ptdm->Connect(this); m_clFileRows= ptdm->RowCount(); m_clFileCols= ptdm->ColCount(); } m_cLinesScrollContext = 0; } CTextView *CTextView::NewTextView(CTextMatrix * ptdm, PSZ pszWindowName, RECT *prc, HINSTANCE hinst, HWND hwndParent) { CTextView *ptv= NULL; __try { ptv= New CTextView; ptv->Init(ptdm); ptv->OpenWindow(pszWindowName, prc, hinst, hwndParent); } __finally { if (_abnormal_termination() && ptv) { delete ptv; ptv= NULL; } } return ptv; } void CTextView::SetTextDatabase(CTextMatrix * ptdm) { if (m_ptdm) { m_ptdm->Disconnect(this); DetachRef(m_ptdm); if (m_cHighlightsAllocated) { m_cHighlightsAllocated = 0; m_cHighlightsActive = 0; delete [] m_pHighlights; m_pHighlights= NULL; } } if (ptdm) { AttachRef(m_ptdm, ptdm); ptdm->Connect(this); } if (ptdm) { m_clFileRows= ptdm->RowCount(); m_clFileCols= ptdm->ColCount(); FillBuff(); } else { m_clFileRows= 0; m_clFileCols= 0; } InvalidateRect(m_hwnd, NULL, TRUE); } void CTextView::RawDataEvent(UINT uEventType) { BOOL fOriginChange = FALSE; BOOL fMarquee = m_fMarquee; BOOL fMarqueeActive = m_fMarqueeActive; switch(uEventType) { case CTextMatrix::SelectionChange: break; case CTextMatrix::FocusChange: if (fMarquee) RemoveMarquee(); if (m_ptdm->GetFocusRect(&m_rowFocus , &m_colFocus, &m_cRowsFocus, &m_cColsFocus ) ) { ScrollTo(m_rowFocus, m_colFocus, 1, 1); if(m_fGotFocus) SetupMarquee(); } if (m_fGotFocus) if (m_fMarqueeActive && !fMarqueeActive) { m_idTimer= ::SetTimer(m_hwnd, MARQUEE_TIMER_ID, MARQUEE_TIMER_SPAN, NULL); m_fMarqueeTimerOn= m_idTimer? TRUE : FALSE; } else if (fMarqueeActive && !m_fMarqueeActive) ::KillTimer(m_hwnd, m_idTimer); ::UpdateWindow(m_hwnd); break; case CTextMatrix::ShapeChange: m_clFileRows= m_ptdm->RowCount(); m_clFileCols= m_ptdm->ColCount(); MatchBuffToWindow(); if (m_lTopLine && m_lTopLine > m_clFileRows - m_cImageFullRows - 1) { m_lTopLine = m_clFileRows - m_cImageFullRows - 1; if (m_lTopLine < 0) m_lTopLine= 0; fOriginChange= TRUE; } if (m_iLeftCol && m_iLeftCol > m_clFileCols - m_cImageFullCols - 1) { m_iLeftCol = m_clFileCols - m_cImageFullCols - 1; if (m_iLeftCol < 0) m_iLeftCol= 0; fOriginChange= TRUE; } m_fMarquee = FALSE; m_fMarqueeActive = FALSE; if (m_ptdm->GetFocusRect(&m_rowFocus , &m_colFocus, &m_cRowsFocus, &m_cColsFocus ) ) { ScrollTo(m_rowFocus, m_colFocus, 1, 1); if (m_fGotFocus) SetupMarquee(); } if (m_fGotFocus) if (m_fMarqueeActive && !fMarqueeActive) { m_idTimer= ::SetTimer(m_hwnd, MARQUEE_TIMER_ID, MARQUEE_TIMER_SPAN, NULL); m_fMarqueeTimerOn= m_idTimer? TRUE : FALSE; } else if (fMarqueeActive && !m_fMarqueeActive) ::KillTimer(m_hwnd, m_idTimer); ::UpdateWindow(m_hwnd); break; case CTextMatrix::DataDeath: break; } if (fOriginChange) NotifyInterface(OriginChange); } CTextView::~CTextView() { if (m_hFontDefault) { DeleteObject(m_hFontDefault); m_hFontDefault = NULL; } if (m_hFontAlternate) { DeleteObject(m_hFontAlternate); m_hFontAlternate = NULL; } if (m_hCheck) { DeleteObject(m_hCheck); m_hCheck = NULL; } if (m_hNoCheck) { DeleteObject(m_hNoCheck); m_hNoCheck = NULL; } if (m_ptdm) { m_ptdm->Disconnect(this); DetachRef(m_ptdm); } if (m_pHighlights) delete m_pHighlights; if (m_pba) DetachRef(m_pba); if (m_pCharsets) delete m_pCharsets; if (m_pbText) delete m_pbText; } BOOL CTextView::SubclassDlgItem(UINT nId, HWND hwndParent) { ASSERT(!m_hwnd); HWND hwndCtrl= ::GetDlgItem(hwndParent, nId); ASSERT(hwndCtrl); Attach(hwndCtrl); m_hwnd= hwndCtrl; m_fpOldWndProc = (WNDPROC)::GetWindowLong(hwndCtrl, GWL_USERDATA); ::SetWindowLong(hwndCtrl, GWL_USERDATA, long(this)); InitState(); return(TRUE); } void CTextView::InitState() { // Assumption: We assume that all member variables are initialed with // zero! m_cImageFullRows = 0; m_cImageFullCols = 0; m_cImageRows = 0; m_cImageCols = 0; m_lTopLine = 0; m_iLeftCol = 0; m_clFileRows = 0; m_clFileCols = 0; m_iHeight = 0; m_iCharset = 0; m_cCharsets = 0; m_pCharsets = NULL; m_iCharsetAlternate = 0xFFFFFF; char acName[128]; ::LoadString(hinstDLL,IDS_LISTBOX_FONT,acName,79); char *pcPointSize; char c; for (pcPointSize= acName; (c= *pcPointSize) && c != ','; ++pcPointSize); m_iHeight= 8; if (c == ',') { *pcPointSize++ = 0; int iHeight= atoi(pcPointSize); if (iHeight) m_iHeight= iHeight; } m_iCharset = 0; m_iFamily = 3; m_iPitch = 2; HDC hdc= GetDC(m_hwnd); // Create a font for the list box for default; m_iHeight = 72 / ((m_iHeight < 8) ? 8 : (m_iHeight > 37) ? 36 : m_iHeight); // Make sure it is reasonable sized m_iHeight = (hdc) ? GetDeviceCaps(hdc,LOGPIXELSY) / m_iHeight : 8; // convert to point size if (strlen(acName)) m_hFontDefault = CreateFont(-m_iHeight,0,0,0,0,0,0,0,m_iCharset,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,m_iPitch | m_iFamily, acName); if (!m_hFontDefault) // Assume this means they gave me a bad name use my own { m_iCharset = ANSI_CHARSET; m_iFamily = FF_MODERN; m_iPitch = VARIABLE_PITCH; m_hFontDefault = CreateFont(-m_iHeight,0,0,0,0,0,0,0,m_iCharset,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,m_iPitch | m_iFamily, "MS Sans Serif"); } HGDIOBJ hsavFont= ::SelectObject(hdc, m_hFontDefault); ::GetTextMetrics(hdc, &m_FontMetrics); ::SelectObject(hdc, hsavFont); m_nCxChar = m_FontMetrics.tmMaxCharWidth; m_nCyChar = m_FontMetrics.tmHeight + m_FontMetrics.tmExternalLeading; m_LeftMargin = m_nCxChar >> 1; ::ReleaseDC(m_hwnd, hdc); m_hCheck = LoadBitmap(hinstDLL,MAKEINTRESOURCE(IDB_CHECK)); m_hNoCheck = LoadBitmap(hinstDLL,MAKEINTRESOURCE(IDB_NOCHECK)); BITMAP bmp; GetObject(m_hCheck,sizeof(bmp),&bmp); m_iCheckHeight = bmp.bmHeight; m_iCheckWidth = bmp.bmWidth; } void CTextView::MatchBuffToWindow() { if (!m_ptdm) return; if (IsIconic(m_hwnd)) return; RECT rectClient; GetClientRect(m_hwnd, &rectClient); OnSize(SIZENORMAL, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top); } void CTextView::RedrawFocusBar() { RECT rc; ::GetClientRect(m_hwnd, &rc); ::InvalidateRect(m_hwnd, &rc, TRUE); ::UpdateWindow(m_hwnd); } void CTextView::SetupMarquee() { ASSERT(!m_fMarquee); long rowTop, colLeft, cRows, cCols, rowLimit, colLimit; long rowLimitImage= m_lTopLine + m_cImageRows; long colLimitImage= m_iLeftCol + m_cImageCols; cRows = 1; rowTop = m_rowFocus; rowLimit= rowTop+ cRows; if (m_cColsFocus < 0) { colLeft = m_colFocus + 1 + m_cColsFocus; cCols = -m_cColsFocus; } else { colLeft = m_colFocus; cCols = m_cColsFocus; } colLimit= colLeft+cCols; #if 0 if ( rowLimit <= m_lTopLine || rowTop >= rowLimitImage || colLimit <= m_iLeftCol || colLeft >= colLimitImage ) { m_rcMarquee.top = 0; m_rcMarquee.bottom = 0; m_rcMarquee.left = 0; m_rcMarquee.right = 0; return; } #endif if (rowTop < m_lTopLine ) rowTop = m_lTopLine - 2; if (colLeft < m_iLeftCol ) colLeft = m_iLeftCol - 2; if (rowLimit > rowLimitImage) rowLimit = rowLimitImage + 2; if (colLimit > colLimitImage) colLimit = colLimitImage + 2; RECT rc; // RonM -- To make marquees and focus rectangles // go across the complete display width. GetWindowRect(m_hwnd, &rc); m_rcMarquee.top = TopMargin + (rowTop - m_lTopLine) * m_nCyChar; m_rcMarquee.left = 0; // (colLeft - m_iLeftCol) * m_nCxChar; m_rcMarquee.bottom = m_rcMarquee.top + (rowLimit - rowTop )* m_nCyChar; m_rcMarquee.right = rc.right - rc.left; // m_rcMarquee.left + (colLimit - colLeft)* m_nCxChar; m_fMarquee= TRUE ; InvalidateMarquee(); } void CTextView::StartMarquee(HDC hdc) { ASSERT(m_fMarquee); HDC hdcWnd= hdc; if (!hdcWnd) hdcWnd= GetDC(m_hwnd); COLORREF clrTextSave = ::SetTextColor(hdcWnd, RGB( 0, 0, 0)); COLORREF clrBkSave = ::SetBkColor (hdcWnd, RGB(256,256,256)); HBRUSH hbrFrame= CreatePatternBrush(m_fMarqueeActive? hbmCheckered : hbmGray50pc); long xOffset= (m_iLeftCol * (m_nCxChar % 8)) % 8; long yOffset= (m_lTopLine * (m_nCyChar % 8)) % 8; ::SetBrushOrgEx(hdcWnd, m_LeftMargin - int(xOffset), TopMargin - int(yOffset), NULL); HBRUSH hbrSave= (HBRUSH)::SelectObject(hdcWnd, HGDIOBJ(hbrFrame)); DrawMarquee(hdcWnd, PATCOPY); ::SetTextColor(hdcWnd, clrTextSave); ::SetBkColor (hdcWnd, clrBkSave ); m_fMarqueePhase = FALSE; ::SelectObject(hdcWnd, hbrSave); DeleteObject(hbrFrame); if (!hdc) ReleaseDC(m_hwnd, hdcWnd); } void CTextView::DrawMarquee(HDC hdcWnd, DWORD dwRop) { if ( m_rcMarquee.top >= m_rcMarquee.bottom || m_rcMarquee.left >= m_rcMarquee.right ) return; RECT rcClip; ::GetClientRect(m_hwnd, &rcClip); rcClip.top = TopMargin; rcClip.left = 0; ::IntersectClipRect(hdcWnd, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom); int cx= m_rcMarquee.right - m_rcMarquee.left; int cy= m_rcMarquee.bottom - m_rcMarquee.top; ::PatBlt(hdcWnd, m_rcMarquee.left, m_rcMarquee.top , cx, 1, dwRop); ::PatBlt(hdcWnd, m_rcMarquee.left, m_rcMarquee.bottom-1, cx, 1, dwRop); ::PatBlt(hdcWnd, m_rcMarquee.left , m_rcMarquee.top+1, 1, cy-2, dwRop); ::PatBlt(hdcWnd, m_rcMarquee.right-1, m_rcMarquee.top+1, 1, cy-2, dwRop); } void CTextView::CycleMarquee(HDC hdc) { HDC hdcWnd= hdc; if (!hdcWnd) hdcWnd= GetDC(m_hwnd); DrawMarquee(hdcWnd, DSTINVERT); m_fMarqueePhase= !m_fMarqueePhase; if (!hdc) ReleaseDC(m_hwnd, hdcWnd); } void CTextView::RemoveMarquee(HDC hdc) { ASSERT(m_fMarquee); // bugbug: Need to turn off the marquee timer here. // bugbug: also need an OnTimer message handler. InvalidateMarquee(); m_fMarquee = FALSE; m_fMarqueeActive = FALSE; } void CTextView::InvalidateMarquee() { RECT rc= m_rcMarquee; rc.bottom= rc.top+1; ::InvalidateRect(m_hwnd, &rc, TRUE); rc.bottom= m_rcMarquee.bottom; rc.top = rc .bottom-1; InvalidateRect(m_hwnd, &rc, TRUE); rc.top = m_rcMarquee.top; rc.right = rc .left+1; InvalidateRect(m_hwnd, &rc, TRUE); rc.right = m_rcMarquee.right; rc.left = rc .right-1; InvalidateRect(m_hwnd, &rc, TRUE); } void CTextView::RepaintMarquee(HDC hdc) { ASSERT(m_fMarquee); BOOL fCycle= m_fMarqueePhase; StartMarquee(hdc); if (fCycle) CycleMarquee(hdc); } void CTextView::OnSetFocus(HWND hwndOld) { m_fGotFocus= TRUE; SetupMarquee(); RedrawFocusBar(); if (m_fMarqueeActive) { m_idTimer= ::SetTimer(m_hwnd, MARQUEE_TIMER_ID, MARQUEE_TIMER_SPAN, NULL); m_fMarqueeTimerOn= m_idTimer? TRUE : FALSE; } } void CTextView::OnKillFocus(HWND hwndNew) { m_fGotFocus= FALSE; if (m_fMarquee) RemoveMarquee(); RedrawFocusBar(); if (m_fMarqueeActive && m_fMarqueeTimerOn) { ::KillTimer(m_hwnd, m_idTimer); m_idTimer= 0; m_fMarqueeTimerOn= FALSE; } } void CTextView::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos ) { OnSize(SIZENORMAL, lpwndpos->cx, lpwndpos->cy); } void CTextView::OnSize(UINT nType, int cx, int cy) { if (nType != SIZEFULLSCREEN && nType != SIZENORMAL) return; short cColsFull = (short) m_ptdm->ColCount(); short cRowsFull = (cy- TopMargin)/m_nCyChar; m_cImageFullCols = (cColsFull > 0)? cColsFull : 0; m_cImageFullRows = (cRowsFull > 0)? cRowsFull : 0; int cRowsClient = (cy+m_nCyChar-1- TopMargin)/m_nCyChar; int cColsClient = m_ptdm->ColCount(); if (cRowsClient < 0) cRowsClient= 0; if (cColsClient < 0) cColsClient= 0; if (cRowsClient != m_cImageRows || cColsClient != m_cImageCols) { m_cImageRows= cRowsClient; m_cImageCols= cColsClient; if (m_cImageRows > m_cCharsets) { if (m_pCharsets) { delete m_pCharsets; m_pCharsets = NULL; m_cCharsets = 0; } if (m_pCharsets = New UINT[m_cImageRows]) m_cCharsets = m_cImageRows; } m_pba->SetSize(cRowsClient*cColsClient); } if (m_ptdm) FillBuff(); InvalidateRect(m_hwnd, NULL, TRUE); } void CTextView::OnSizeChar(int cx,int cy) { short cColsFull = cx; short cRowsFull = cy; m_cImageFullCols = (cColsFull > 0)? cColsFull : 0; m_cImageFullRows = (cRowsFull > 0)? cRowsFull : 0; int cColsClient = cx; int cRowsClient = cy; if (cColsClient < 0) cColsClient= 0; if (cRowsClient < 0) cRowsClient= 0; if (cColsClient != m_cImageCols || cRowsClient != m_cImageRows) { m_cImageCols= cColsClient; m_cImageRows= cRowsClient; if (m_cImageRows > m_cCharsets) { if (m_pCharsets) { delete m_pCharsets; m_pCharsets = NULL; m_cCharsets = 0; } if (m_pCharsets = New UINT[m_cImageRows]) m_cCharsets = m_cImageRows; } m_pba->SetSize(m_cImageRows * m_cImageCols); } if (m_ptdm) FillBuff(); InvalidateRect(m_hwnd, NULL, TRUE); } void CTextView::FillBuff() { m_ptdm->GetTextMatrixImage (m_lTopLine, m_iLeftCol, m_cImageRows, m_cImageCols, m_pba->ElementAt(0), m_pCharsets); //rmk UINT iCharsetDef= DefaultCharacterSet(); for (int c= m_cImageRows; c--; ) if (m_pCharsets[c] == DEFAULT_CHARSET) m_pCharsets[c] = iCharsetDef; UINT cHighlights= m_ptdm->GetHighlights(m_lTopLine, m_iLeftCol, m_cImageRows, m_cImageCols, 0, NULL ); if (cHighlights) { if (cHighlights > m_cHighlightsAllocated) { if (m_cHighlightsAllocated) delete [] m_pHighlights; m_cHighlightsAllocated=cHighlights; m_pHighlights= New CHighlight[m_cHighlightsAllocated]; } m_ptdm->GetHighlights(m_lTopLine, m_iLeftCol, m_cImageRows, m_cImageCols, cHighlights, m_pHighlights ); // The highlight data is initially relative to the full data image. // For convenience during repainting we make it relative to the buffer // image. // Bug: C 7.00 won't accept the declaration for phl within the // init phrase of the for statement! PCHighlight phl= m_pHighlights; for (UINT c= cHighlights; c--; phl++ ) { phl->m_row -= m_lTopLine; phl->m_col -= m_iLeftCol; } } m_cHighlightsActive= cHighlights; } BOOL CTextView::OnEraseBkgnd(HDC hdc) { RECT rect; UINT wLM= m_LeftMargin; ::GetClientRect(m_hwnd, &rect ); #if 0 // #ifndef CHICAGO HBRUSH hbrushSave; if (m_fGotFocus) { HBRUSH hbrFocus= ::CreateSolidBrush(::GetSysColor(COLOR_ACTIVECAPTION)); hbrushSave= ::SelectObject(hdc, hbrFocus); ::BitBlt(hdc, rect.left, rect.top, FocusMargin, rect.bottom - rect.top, NULL, 0, 0, PATCOPY); SelectObject(hdc, hbrushSave); DeleteObject(hbrFocus); rect.left += FocusMargin; wLM -= FocusMargin; } #endif // 0 #if 0 HBRUSH hbrTextBG= (HBRUSH) ::SendMessage(GetParent(m_hwnd), WM_CTLCOLORDLG, (WPARAM) hdc, (LPARAM) GetParent(m_hwnd)); hbrushSave= ::SelectObject(hdc, hbrTextBG); if (m_ptdm) { ::BitBlt(hdc, rect.left, rect.top, wLM, rect.bottom - rect.top, NULL, 0, 0, PATCOPY); ::BitBlt(hdc, rect.left+wLM, rect.top, (rect.right - rect.left)-wLM, TopMargin, NULL, 0, 0, PATCOPY); } else ::BitBlt(hdc, rect.left, rect.top, (rect.right - rect.left), rect.bottom - rect.top, NULL, 0, 0, PATCOPY); ::SelectObject(hdc, hbrushSave); DeleteObject(hbrTextBG); #endif // 0 return TRUE; } void CTextView::ColorTextOut(HDC hdc, int x, int y, PWCHAR lpChar, int row, int cChar, //rmk COLORREF clrfg, COLORREF clrbg ) { if (m_clrfg != clrfg) ::SetTextColor(hdc, m_clrfg= clrfg); if (m_clrbg != clrbg) ::SetBkColor (hdc, m_clrbg= clrbg); RECT rcClip; ::GetClientRect(m_hwnd, &rcClip); rcClip.top = y; if (rcClip.bottom > y + m_nCyChar) rcClip.bottom = y + m_nCyChar; //rmk--> cChar <<= 1; // each WC can generate two MB characters if (cChar > m_cbText) { m_cbText = 0; if (m_pbText) { delete m_pbText; m_pbText= NULL; } m_pbText = New char[cChar]; m_cbText = cChar; } if (!m_pbText) return; int cText = WideCharToMultiByte(GetCPFromCharset(m_pCharsets[row]), 0, lpChar, cChar>>1, m_pbText, m_cbText, NULL, NULL); //rmk //rmk<-- ExtTextOut(hdc, x, y, ETO_OPAQUE, &rcClip, m_pbText, cText, NULL); //rmk } // OnPaint // #ifdef _DEBUG static UINT cRepaints= 0; #endif // _DEBUG void CTextView::OnPaint() { PAINTSTRUCT ps; int iLastHilite = -1; HDC hdc= ::BeginPaint(m_hwnd, &ps); if (! m_ptdm ) { EndPaint(m_hwnd, &ps); return; } #ifdef _DEBUG ++cRepaints; #endif // _DEBUG // if we are using the 3d drawing stuff we need to setup the // background manually HBRUSH hbrTextBG= (HBRUSH) ::SendMessage(GetParent(m_hwnd), WM_CTLCOLORDLG, (WPARAM) hdc, (LPARAM) GetParent(m_hwnd)); LOGBRUSH lb; ::GetObject(hbrTextBG, sizeof(LOGBRUSH),&lb); ::SetBkColor(hdc, lb.lbColor); ::SetTextAlign(hdc, TA_LEFT); HFONT hfontDefault= m_hFont? m_hFont : m_hFontDefault; HGDIOBJ hSaveFont= ::SelectObject(hdc, hfontDefault); m_clrfg= ::GetTextColor(hdc); // Set up to use ColorTextOut routine... m_clrbg= ::GetBkColor (hdc); COLORREF clrfgText = ::GetSysColor(COLOR_WINDOWTEXT ); COLORREF clrbgText = ::GetSysColor(COLOR_WINDOW );// m_clrbg; COLORREF clrfgTextHighlight = ::GetSysColor(COLOR_HIGHLIGHTTEXT); COLORREF clrbgTextHighlight = ::GetSysColor(COLOR_HIGHLIGHT ); HBRUSH hbrFrame = ::CreateSolidBrush(clrbgTextHighlight); HBRUSH hbrDotBox = ::CreatePatternBrush(hbmGray50pc ); HBRUSH hbrDashBox = ::CreatePatternBrush(hbmCheckered); RECT rcFrame; HBRUSH hbrSave= (HBRUSH)::SelectObject(hdc, HGDIOBJ(hbrFrame)); UINT cHighlightsLeft = m_cHighlightsActive; CHighlight *pHighlight = m_pHighlights; RECT rect, rect2; int y; PWCHAR lpb; //rmk ::GetClientRect(m_hwnd, &rect); RECT rectUpdate= rect; int yOff= TopMargin; int xOff= m_LeftMargin; if (rectUpdate.top < (int) yOff) rectUpdate.top = yOff; int rowFirst= (rectUpdate.top - yOff)/m_nCyChar; int rowLimit= (rectUpdate.bottom + m_nCyChar - 1 - yOff) / m_nCyChar; if (rectUpdate.left < (int) xOff) rectUpdate.left= xOff; int colFirst= 0; int colLimit= m_cImageCols; int cols= colLimit - colFirst; rect2.left = xOff + colFirst*m_nCxChar; rect2.right = rect.right; y = yOff + m_nCyChar * rowFirst; int row= rowFirst; for ( lpb= m_pba->ElementAt(colFirst + rowFirst * m_cImageCols); row < rowLimit; // y < rectUpdate.bottom; y += m_nCyChar, lpb+= m_cImageCols, ++row ) { rect2.top = y; rect2.bottom = y + m_nCyChar; for (; cHighlightsLeft && ( pHighlight->m_iType != CHighlight::HIGHLIGHT_TEXT || pHighlight->m_row < row ); cHighlightsLeft--, pHighlight++ ); UINT colsDrawn = 0; int col = colFirst; int left = rect2.left; PWCHAR lpchar = lpb; //rmk for (int cChar= cols; cChar; cChar -= colsDrawn, col += colsDrawn, left += colsDrawn*m_nCxChar, lpchar += colsDrawn ) { for (; cHighlightsLeft && ( pHighlight->m_iType != CHighlight::HIGHLIGHT_TEXT || ( pHighlight->m_row == row && (pHighlight->m_col + pHighlight->m_cChars) <= col ) ); cHighlightsLeft--, pHighlight++ ); if (m_pCharsets[row] == m_iCharset) ::SelectObject(hdc, hfontDefault); else if (m_pCharsets[row] == m_iCharsetAlternate) ::SelectObject(hdc, m_hFontAlternate); else { if (m_hFontAlternate) DeleteObject(m_hFontAlternate); m_hFontAlternate = NULL; m_iCharsetAlternate = m_pCharsets[row]; LOGFONT lf; GetObject(hfontDefault, sizeof(lf), &lf); lf.lfCharSet= m_iCharsetAlternate; if (m_iCharsetAlternate == SYMBOL_CHARSET) strcpy(lf.lfFaceName, "SYMBOL"); m_hFontAlternate = CreateFontIndirect(&lf); // m_hFontAlternate = CreateFont(-m_iHeight,0,0,0,0,0,0,0,m_iCharsetAlternate,OUT_DEFAULT_PRECIS, // CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,m_iPitch | m_iFamily, NULL); if (m_hFontAlternate) { ::SelectObject(hdc, m_hFontAlternate); TEXTMETRIC tm; if (GetTextMetrics(hdc, &tm)) //ASSERT(tm.tmCharSet == m_iCharsetAlternate); ; else { ::SelectObject(hdc, hfontDefault); ::DeleteObject(m_hFontAlternate); m_pCharsets[row] = m_iCharset; m_iCharsetAlternate = 0xFFFFFF; m_hFontAlternate = NULL; } } else { m_pCharsets[row] = m_iCharset; m_iCharsetAlternate = 0xFFFFFF; ::SelectObject(hdc, hfontDefault); } } if (cHighlightsLeft && pHighlight->m_row == row && pHighlight->m_col < colFirst+cols ) { if (pHighlight->m_col > col) { colsDrawn= pHighlight->m_col-col; ColorTextOut(hdc, left, rect2.top, lpchar, row, colsDrawn, clrfgText, clrbgText); } cChar -= colsDrawn; lpchar += colsDrawn; col += colsDrawn; left += colsDrawn*m_nCxChar; int colHL= pHighlight->m_col; int cbHL= m_cImageCols - colHL; // pHighlight->m_cChars; if (colHL < col) { cbHL -= col-colHL; colHL = col; } if (cbHL > cChar) cbHL= cChar; ColorTextOut(hdc, left, rect2.top, lpchar, row, colsDrawn= cbHL, clrfgTextHighlight, clrbgTextHighlight); iLastHilite = row; ++pHighlight; --cHighlightsLeft; } else { ColorTextOut(hdc, left, rect2.top, lpchar, row, cChar, clrfgText, clrbgText); break; } } } cHighlightsLeft = m_cHighlightsActive; pHighlight = m_pHighlights; for (row= rowFirst; row < rowLimit; ++row) { for (; cHighlightsLeft && (pHighlight->m_iType == CHighlight::HIGHLIGHT_TEXT || pHighlight->m_row < row); cHighlightsLeft--, pHighlight++ ); if (!cHighlightsLeft) break; int col; for (row= pHighlight->m_row, col= colFirst; col < colLimit; ) { for (; cHighlightsLeft && ( pHighlight->m_iType == CHighlight::HIGHLIGHT_TEXT || (pHighlight->m_row == row && (pHighlight->m_col + pHighlight->m_cChars)<= col) ); cHighlightsLeft--, pHighlight++ ); if (!cHighlightsLeft) break; for (; cHighlightsLeft && pHighlight->m_iType != CHighlight::HIGHLIGHT_TEXT && pHighlight->m_row == row && pHighlight->m_col < colLimit; col= pHighlight->m_col + pHighlight->m_cChars, cHighlightsLeft--, pHighlight++ ) { RECT rcBounds; rcBounds.top = yOff + pHighlight->m_row * m_nCyChar; rcBounds.left = xOff + pHighlight->m_col * m_nCxChar; rcBounds.bottom = rcBounds.top + m_nCyChar; rcBounds.right = rcBounds.left + pHighlight->m_cChars * m_nCxChar; switch (pHighlight->m_iType) { case CHighlight::CHECK_MARK: case CHighlight::NOCHECK_MARK: { if (m_bUseCheck) { HDC hSrcDC = CreateCompatibleDC(hdc); COLORREF crBkg, crText; crText = SetTextColor(hdc,(iLastHilite == row) ? clrfgTextHighlight : clrfgText); crBkg = SetBkColor(hdc,(iLastHilite == row) ? clrbgTextHighlight : clrbgText); HBITMAP hbmpSave = (HBITMAP) SelectObject(hSrcDC,(pHighlight->m_iType == CHighlight::CHECK_MARK) ? m_hCheck : m_hNoCheck); RECT rcClip; ::GetClientRect(m_hwnd, &rcClip); if (rcBounds.bottom <= rcClip.bottom) { BitBlt(hdc,(m_LeftMargin - m_iCheckWidth) / 2,rcBounds.top + ((m_nCyChar - m_iCheckHeight) / 2), m_iCheckWidth,m_iCheckHeight,hSrcDC,0,0,SRCCOPY); } SetBkColor(hSrcDC,crBkg); SetTextColor(hSrcDC,crText); SelectObject(hSrcDC,hbmpSave); DeleteDC(hSrcDC); } break; } case CHighlight::DOT_BOX_TEXT: ::FrameRect(hdc, &rcBounds, hbrDotBox); break; case CHighlight::DASH_BOX_TEXT: ::FrameRect(hdc, &rcBounds, hbrDashBox); break; case CHighlight::UNDERSCORE_TEXT: ::PatBlt(hdc, rcBounds.left, rcBounds.bottom-1, rcBounds.right - rcBounds.left, 1, PATCOPY); break; case CHighlight::OVERSCORE_TEXT: ::PatBlt(hdc, rcBounds.left, rcBounds.top, rcBounds.right - rcBounds.left, 1, PATCOPY); break; case CHighlight::BOX_TEXT: FrameRect(hdc, &rcFrame, hbrFrame); break; } } } } ::SelectObject(hdc, hbrSave ); ::SelectObject(hdc, hSaveFont); if (m_fMarquee) RepaintMarquee(hdc); ::DeleteObject(hbrFrame ); ::DeleteObject(hbrDotBox ); ::DeleteObject(hbrDashBox); ::EndPaint(m_hwnd, &ps); } void CTextView::InvalidateImage(long row, long col, long cRows, long cCols) { long rowLimit= row+cRows; long colLimit= col+cCols; // Undone: When row is -1, the data object has changed its shape. // In that case cRows and cCols give the new data shape. // // For that situation we must notify our owner that the // scroll bar range must be modified. if (row < m_lTopLine ) row= m_lTopLine; if (col < long(m_iLeftCol)) col= long(m_iLeftCol); long rowLimitImage= m_lTopLine + m_cImageRows; long colLimitImage= long(m_iLeftCol) + m_cImageCols; if (rowLimit > rowLimitImage) rowLimit= rowLimitImage; if (colLimit > colLimitImage) colLimit= colLimitImage; // if (row >= rowLimit || col >= colLimit) return; FillBuff(); RECT rc; GetClientRect(m_hwnd,&rc); rc.top = TopMargin + m_nCyChar * UINT(row - m_lTopLine); // This causes the bottom to not be emptied // rc.bottom = rc.top + m_nCyChar * UINT(rowLimit - row ); InvalidateRect(m_hwnd, &rc, TRUE); } // // MoveToRow: void CTextView::MoveToRow(long row, BOOL fForceUpdate, BOOL fNotify) { if ( m_ptdm == NULL ) return; LONG oldLine= m_lTopLine; if (row > m_clFileRows - long(m_cImageFullRows)) row = m_clFileRows - long(m_cImageFullRows); if (row < 0) row= 0; long distance= oldLine - row; if (!distance) return; BOOL fMarquee= m_fMarquee; if (fMarquee) RemoveMarquee(); m_lTopLine= row; FillBuff(); if (fMarquee) SetupMarquee(); int udistance= (distance < 0)? - distance : distance; if (udistance > m_cImageFullRows) InvalidateRect(m_hwnd, NULL, FALSE); else { HDC hdc= ::GetWindowDC(m_hwnd); RECT rectText, rectUpdate,rectClip; ::GetClientRect(m_hwnd, &rectText); ::GetClientRect(m_hwnd, &rectClip); // rectClip.bottom = ((rectText.bottom - rectText.top) / m_nCyChar) * m_nCyChar; rectText.top += TopMargin; ::ScrollDC(hdc, 0, m_nCyChar * (int) distance, &rectText, &rectClip, NULL, &rectUpdate); rectUpdate.top -= (rectUpdate.top >= m_nCyChar) ? m_nCyChar : rectUpdate.top; ::InvalidateRect(m_hwnd, &rectUpdate, TRUE); ReleaseDC(m_hwnd, hdc); } if (fForceUpdate) UpdateWindow(); if (fNotify) NotifyInterface(OriginChange); } void CTextView::RepaintFrom(long row, long col) { m_lTopLine= row; m_iLeftCol= int(col); BOOL fMarquee= m_fMarquee; if (fMarquee) RemoveMarquee(); m_lTopLine= row; FillBuff(); if (fMarquee) SetupMarquee(); ::InvalidateRect(m_hwnd, NULL, TRUE); ::UpdateWindow(m_hwnd); } // MoveToCol: // void CTextView::MoveToCol(long col, BOOL fForceUpdate, BOOL fNotify) { if ( m_ptdm == NULL ) return; int oldLeftCol = m_iLeftCol; if (col > m_clFileCols - long(m_cImageFullCols)) col = m_clFileCols - long(m_cImageFullCols); if (col < 0) col= 0; long distance= oldLeftCol - int(col); if (!distance) return; BOOL fMarquee= m_fMarquee; if (fMarquee) RemoveMarquee(); m_iLeftCol= int(col); FillBuff(); if (fMarquee) SetupMarquee(); int udistance= (distance < 0)? - distance : distance; if (udistance > m_cImageFullCols) { InvalidateRect(m_hwnd, NULL, FALSE); return; } HDC hdcClient= GetWindowDC(m_hwnd); RECT rectText, rectUpdate,rectClip; GetClientRect(m_hwnd, &rectText); GetClientRect(m_hwnd, &rectClip); rectClip.bottom = ((rectText.bottom - rectText.top) / m_nCyChar) * m_nCyChar; rectText.top += TopMargin; ::ScrollDC(hdcClient, m_nCxChar * int(distance), 0, &rectText, &rectClip, NULL, &rectUpdate); ::ReleaseDC(m_hwnd, hdcClient); rectUpdate.top -= (rectUpdate.top >= m_nCyChar) ? m_nCyChar : rectUpdate.top; ::InvalidateRect(m_hwnd, &rectUpdate, TRUE); if (fForceUpdate) ::UpdateWindow(m_hwnd); if (fNotify) NotifyInterface(OriginChange); } void CTextView::MoveTo(long rowTop, long colLeft, BOOL fNotify) { if (rowTop == m_lTopLine && colLeft == m_iLeftCol) return; UpdateWindow(); MoveToRow(rowTop , FALSE, FALSE); MoveToCol(colLeft, FALSE, FALSE); if (fNotify) NotifyInterface(OriginChange); } void CTextView::PaddedScrollTo(long rowTop, long colLeft, unsigned short cRows, unsigned short cCols ) { if (m_cImageFullRows > cRows) { int cLinesExtra= m_cImageFullRows - cRows; if (cLinesExtra > m_cLinesScrollContext) cLinesExtra = m_cLinesScrollContext; cRows += cLinesExtra; rowTop -= cLinesExtra/2; if (rowTop < 0) rowTop= 0; } ScrollTo(rowTop, colLeft, cRows, cCols); } void CTextView::ScrollTo(int rowTop, int colLeft, int cRows, int cCols ) { int rowNew= m_lTopLine; if (rowTop <= m_lTopLine) rowNew= rowTop; else if (rowTop + cRows >= m_lTopLine+m_cImageFullRows) { rowNew= rowTop + cRows - m_cImageFullRows; if (rowNew > rowTop) rowNew= rowTop; } int colNew= m_iLeftCol; if (colLeft <= m_iLeftCol) colNew= colLeft; else if (colLeft + cCols > m_iLeftCol+m_cImageFullCols) { colNew= colLeft + cCols - m_cImageFullCols; if (colNew > colLeft) colNew= colLeft; } MoveTo(rowNew, colNew); } UINT CTextView::OnNcHitTest(POINTS point) { return HTCLIENT; } BOOL CTextView::OnSetCursor(HWND hWnd, UINT nHitTest, UINT message) { SetCursor((HCURSOR)hcurArrow); return TRUE; } void CTextView::CharacterMouseEvent(UINT nFlags, POINTS point, long& row, long& col ) { long x= point.x - long(m_LeftMargin); long y= point.y - long( TopMargin); if (y >= 0) row= y/m_nCyChar; else row= -((m_nCyChar-1-y)/m_nCyChar); if (x >= 0) col= x/m_nCxChar; else col= -((m_nCxChar-1-x)/m_nCxChar); row+= m_lTopLine; col+= m_iLeftCol; if (row < 0) row= 0; else if (row >= m_clFileRows) row= m_clFileRows-1; if (col < 0) col= 0; else if (col >= m_clFileCols) col= m_clFileCols-1; if ( row >= m_lTopLine && row < m_lTopLine + m_cImageFullRows && col >= m_iLeftCol && col < m_iLeftCol + m_cImageFullCols ) { if (m_fTimerActive) { m_fTimerActive= FALSE; ::KillTimer(m_hwnd, m_hTimer); } return; } if (row < m_lTopLine) MoveToRow(row); else if (row >= m_lTopLine+m_cImageFullRows) MoveToRow(row+1-m_cImageFullRows); if (col < long(m_iLeftCol)) MoveToCol(col); else if (col >= long(m_iLeftCol)+long(m_cImageFullCols)) MoveToCol(col+1-long(m_cImageFullCols)); if (m_fTimerActive) return; m_fTimerActive= TRUE; m_hTimer= SetTimer(m_hwnd, MOUSE_TIMER_ID, GetProfileInt("Windows", "KeyboardSpeed", 100), NULL); } void CTextView::OnLButtonDown(UINT nFlags, POINTS point) { if (::GetFocus() != m_hwnd) ::SetFocus(m_hwnd); if (!m_ptdm) return; if (GetCapture()) return; SetCapture(m_hwnd); m_fMouseCaptured = TRUE; m_fTimerActive = FALSE; long row, col; CharacterMouseEvent(nFlags, point, row, col); m_ptdm->OnLButtonDown(nFlags, row, col); } void CTextView::OnLButtonUp(UINT nFlags, POINTS point) { if (!m_fMouseCaptured) return; long row, col; CharacterMouseEvent(nFlags, point, row, col); int x = (m_LeftMargin - m_iCheckWidth) / 2; int y = (TopMargin + (row-m_lTopLine) * m_nCyChar) + ((m_nCyChar - m_iCheckHeight) / 2); int w = m_iCheckWidth; int h = m_iCheckHeight; m_ptdm->OnLButtonUp(nFlags, row, col, m_bUseCheck ? (point.x >= x && point.y >= y && point.x <= x+w && point.y <= y+h) : FALSE ); if (m_fTimerActive) { KillTimer(m_hwnd, m_hTimer); m_fTimerActive= FALSE; } m_fMouseCaptured= FALSE; ::ReleaseCapture(); } void CTextView::OnLButtonDblClk(UINT nFlags, POINTS point) { long row, col; CharacterMouseEvent(nFlags, point, row, col); int x = (m_LeftMargin - m_iCheckWidth) / 2; int y = (TopMargin + (row-m_lTopLine) * m_nCyChar) + ((m_nCyChar - m_iCheckHeight) / 2); int w = m_iCheckWidth; int h = m_iCheckHeight; if (!(m_bUseCheck ? (point.x >= x && point.y >= y && point.x <= x+w && point.y <= y+h) : FALSE)) m_ptdm->OnLButtonDblClk(nFlags, row, col); } void CTextView::OnMouseMove(UINT nFlags, POINTS point) { BOOL fStartedWithTimer= m_fTimerActive; long row, col; if (!m_fMouseCaptured) return; CharacterMouseEvent(nFlags, point, row, col); if (fStartedWithTimer && m_fTimerActive) return; m_ptdm->OnMouseMove(nFlags, row, col); } void CTextView::OnTimer(UINT nIDEvent) { if (m_fMarqueeTimerOn && nIDEvent == m_idTimer) { return; } if (nIDEvent != m_hTimer) return; long info= ::GetMessagePos(); POINT point; point.x = LOWORD(info), point.y = HIWORD(info); ScreenToClient(m_hwnd, &point); long row, col; POINTS points; points.x= short(point.x); points.y= short(point.y); CharacterMouseEvent(0, points, row, col); m_ptdm->OnMouseMove(0, row, col); } void CTextView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (!m_ptdm) return; m_ptdm->OnKeyDown(this, nChar, nRepCnt, nFlags); } void CTextView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { if (!m_ptdm) return; m_ptdm->OnKeyUp(this, nChar, nRepCnt, nFlags); }