///////////////////////////////////////////////////////////////////////////// // // COverEditView - 1995 Wolfgang Rolke // // COverEditView erweitert die Klasse CEditView um einen Überschreibmodus. // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "overedit.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif #ifdef WIN32 #define _fmemcpy memcpy #endif ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNCREATE(COverEditView, CEditView) BEGIN_MESSAGE_MAP(COverEditView, CEditView) //{{AFX_MSG_MAP(COverEditView) ON_WM_KEYDOWN() ON_UPDATE_COMMAND_UI(ID_INDICATOR_OVR, OnUpdateIndicatorOvr) ON_MESSAGE(OWM_SETOVERWRITE, OnSetOverwrite) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// BOOL COverEditView::m_bOverwrite = FALSE; BOOL COverEditView::m_bOverwriteOld = FALSE; static char BASED_CODE szSettings[] = "Settings"; static char BASED_CODE szOverType[] = "OverType"; ///////////////////////////////////////////////////////////////////////////// // Konstruktor COverEditView::COverEditView() { // Nichts zu tun } ///////////////////////////////////////////////////////////////////////////// WNDPROC* COverEditView::GetSuperWndProcAddr() { static WNDPROC NEAR pfnSuper; return &pfnSuper; } ///////////////////////////////////////////////////////////////////////////// // Initialisierung und Speicherung des Überschreibmodus void COverEditView::Initialize() { m_bOverwrite = AfxGetApp()->GetProfileInt(szSettings, szOverType, 0); m_bOverwriteOld = m_bOverwrite; } void COverEditView::Terminate() { if (m_bOverwrite != m_bOverwriteOld) AfxGetApp()->WriteProfileInt(szSettings, szOverType, m_bOverwrite); } ///////////////////////////////////////////////////////////////////////////// // Liefert den Text zwischen zwei Zeichenpositionen void COverEditView::GetSubText(CString& strSubText, int nStartPos, int nEndPos) const { ASSERT_VALID(this); // Endposition darf kleiner sein als Anfangsposition UINT uIndex = min((UINT)nStartPos, (UINT)nEndPos); UINT uIndexEnd = max((UINT)nStartPos, (UINT)nEndPos); ASSERT(uIndexEnd <= GetBufferLength()); // Anzahl der zu kopierenden Zeichen UINT uLen = uIndexEnd - uIndex; // Zeiger auf den Textanfang LPCSTR lpszText = ((COverEditView*)this)->LockBuffer(); // Den gewünschten Textausschnitt kopieren _fmemcpy(strSubText.GetBuffer(uLen), lpszText+uIndex, uLen); strSubText.ReleaseBuffer(uLen); UnlockBuffer(); ASSERT_VALID(this); } ///////////////////////////////////////////////////////////////////////////// // Diese Methode prüft, ob ein Bereich im Textfeld ausgewählt ist. // Ist kein Bereich markiert, wird das aktuelle Wort (in dem sich // die Einfügemarke befindet) ausgewählt. Die Funktion liefert als // Ergebnis die Anzahl der selektierten Zeichen zurück. int COverEditView::SelectWord() const { ASSERT_VALID(this); if (GetBufferLength() == 0) return 0; int iStartChar, iEndChar; GetEditCtrl().GetSel(iStartChar, iEndChar); int nSelLen = iEndChar - iStartChar; BOOL bIsOvrSel = (nSelLen == 1) && m_bOverwrite; if (nSelLen && !bIsOvrSel) return nSelLen; if (bIsOvrSel) GetEditCtrl().SetSel(iStartChar, iStartChar); int iLine = GetEditCtrl().LineFromChar(); int nLineLen = GetEditCtrl().LineLength(); if (nLineLen > 1024) nLineLen = 1024; CString strLine; nLineLen = GetEditCtrl().GetLine(iLine, strLine.GetBuffer(nLineLen), nLineLen); strLine.ReleaseBuffer(nLineLen); if (nLineLen == 0) return 0; int iChar = GetEditCtrl().LineIndex(iLine); int iCharInLine = iStartChar - iChar; CString strLeftLine = strLine.Left(iCharInLine); CString strRightLine = strLine.Right(nLineLen-iCharInLine); const char* pszCutOffChars = " ,.:;!?'\"=+-*/^\\<>()[]{}&|~#@ "; strLeftLine.MakeReverse(); int iLeftChar = strLeftLine.FindOneOf(pszCutOffChars); if (iLeftChar == -1) iStartChar = iChar; else iStartChar = iChar + iCharInLine - iLeftChar; int iRightChar = strRightLine.FindOneOf(pszCutOffChars); if (iRightChar == -1) iEndChar = iChar + nLineLen; else iEndChar = iChar + iCharInLine + iRightChar; nSelLen = iEndChar - iStartChar; if (nSelLen) GetEditCtrl().SetSel(iStartChar, iEndChar); ASSERT_VALID(this); return nSelLen; } ///////////////////////////////////////////////////////////////////////////// // Ermittelt die Position der Schreibmarke BOOL COverEditView::GetCaretIndex(int& nLine, int& nColumn) const { int nSelBeg, nSelEnd; GetEditCtrl().GetSel(nSelBeg, nSelEnd); if ((nSelEnd == nSelBeg) || ((nSelEnd - nSelBeg == 1) && m_bOverwrite)) { nLine = 1 + GetEditCtrl().LineFromChar(); // Zeile nColumn = 1 + nSelBeg - GetEditCtrl().LineIndex(); // Spalte return TRUE; } else { nLine = nSelEnd - nSelBeg; // Anzahl markierter Zeichen nColumn = GetBufferLength(); // Gesamtzahl der Zeichen return FALSE; } } ///////////////////////////////////////////////////////////////////////////// // Setzt im Überschreibmodus die korrekte Zeichenmarkierung void COverEditView::CheckSelection(UINT message, WPARAM wParam, LPARAM) { if (message == WM_KEYDOWN || message == WM_CHAR || message == WM_LBUTTONUP || message == WM_SETFOCUS) { int nStartPos, nEndPos; // Nur wenn keine Markierung vorliegt, ein Zeichen selektieren GetEditCtrl().GetSel(nStartPos, nEndPos); if (nStartPos == nEndPos) { if ((UINT)nStartPos == GetBufferLength()) return; int iStart = 1; // Schreibmarke links der Markierung setzen // Sonderfall: Markierungserweiterung nach rechts if (message == WM_KEYDOWN && wParam == VK_RIGHT && GetKeyState(VK_SHIFT) >> 15 && nStartPos) // Das vorherige Zeichen selektieren und die // Schreibmarke rechts der Markierung setzen iStart = -1; GetEditCtrl().SetSel(nStartPos + iStart, nStartPos); CString strSelText; GetSubText(strSelText, nStartPos, nStartPos + iStart); if (strSelText == '\r') /* CR */ // Wagenrücklauf darf nicht selektiert werden GetEditCtrl().SetSel(nStartPos, nStartPos); } } } ///////////////////////////////////////////////////////////////////////////// // Aktualisiert im Überschreibmodus die Zeichenmarkierung LRESULT COverEditView::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { LRESULT lResult = CEditView::DefWindowProc(message, wParam, lParam); if (m_bOverwrite) CheckSelection(message, wParam, lParam); return lResult; } ///////////////////////////////////////////////////////////////////////////// // Setzt den Schreibmodus BOOL COverEditView::SetOverwriteMode(BOOL bOverwrite /*=TRUE*/) { // Sicherstellen, daß bOverwrite == TRUE || bOverwrite == FALSE bOverwrite = !!bOverwrite; if (m_bOverwrite == bOverwrite) return FALSE; // Neuen Schreibmodus setzen m_bOverwrite = bOverwrite; if (m_bOverwrite) // Markierung setzen CheckSelection(WM_KEYDOWN, 0, 0L); else { int nStartPos, nEndPos; // Wenn ein Zeichen selektiert ist, Markierung aufheben GetEditCtrl().GetSel(nStartPos, nEndPos); if (nEndPos - nStartPos == 1) GetEditCtrl().SetSel(nStartPos, nStartPos); } #if !defined(NOPARENTNOTIFY) // Das Mutterfenster über den neuen Schreibmodus benachrichtigen #if defined(WIN32) GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), m_bOverwrite ? OWN_OVERWRITE : OWN_INSERT), (LPARAM)m_hWnd); #else GetParent()->SendMessage(WM_COMMAND, GetDlgCtrlID(), MAKELPARAM(m_hWnd, m_bOverwrite ? OWN_OVERWRITE : OWN_INSERT)); #endif #endif return TRUE; } ///////////////////////////////////////////////////////////////////////////// // Schaltet bei Betätigen der Einfügen-Taste den Schreibmodus um und // sorgt im Überschreibmodus für die korrekte Behandlung der Zurück-Taste void COverEditView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { int nStartPos, nEndPos; if ((nChar == VK_INSERT) && !(GetKeyState(VK_CONTROL) >> 15) && !(GetKeyState(VK_SHIFT) >> 15)) { // Schreibmodus umschalten m_bOverwrite = !m_bOverwrite; if (m_bOverwrite) // Markierung setzen CheckSelection(WM_KEYDOWN, nChar, MAKELPARAM(nRepCnt, nFlags)); else { // Wenn ein Zeichen selektiert ist, Markierung aufheben GetEditCtrl().GetSel(nStartPos, nEndPos); if (nEndPos - nStartPos == 1) GetEditCtrl().SetSel(nStartPos, nStartPos); } #if !defined(NOPARENTNOTIFY) // Das Mutterfenster über den neuen Schreibmodus benachrichtigen #if defined(WIN32) GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), m_bOverwrite ? OWN_OVERWRITE : OWN_INSERT), (LPARAM)m_hWnd); #else GetParent()->SendMessage(WM_COMMAND, GetDlgCtrlID(), MAKELPARAM(m_hWnd, m_bOverwrite ? OWN_OVERWRITE : OWN_INSERT)); #endif #endif } if (m_bOverwrite) { if (nChar == VK_BACK) { // Bei Betätigen der Rücktaste nicht das selektierte Zeichen löschen, // sondern das Zeichen davor! GetEditCtrl().GetSel(nStartPos, nEndPos); if (nEndPos - nStartPos == 1) { if (nStartPos) { CString strSelText; GetSubText(strSelText, nStartPos - 1, nStartPos); if (strSelText == '\n') /* LF */ // CR und LF müssen zusammen selektiert werden GetEditCtrl().SetSel(nStartPos - 2, nStartPos); else GetEditCtrl().SetSel(nStartPos - 1, nStartPos); } else { // Am Textanfang gibt es nichts zu löschen GetEditCtrl().SetSel(nStartPos, nStartPos); return; } } } if (GetKeyState(VK_SHIFT) >> 15 && (nChar == VK_END || nChar == VK_DOWN || nChar == VK_NEXT || (nChar == VK_RIGHT && GetKeyState(VK_CONTROL) >> 15))) { GetEditCtrl().GetSel(nStartPos, nEndPos); if (nEndPos - nStartPos == 1) GetEditCtrl().SetSel(nStartPos, nStartPos); } } CEditView::OnKeyDown(nChar, nRepCnt, nFlags); if (m_bOverwrite) CheckSelection(WM_KEYDOWN, nChar, MAKELPARAM(nRepCnt, nFlags)); } ///////////////////////////////////////////////////////////////////////////// // Setzt den Schreibmodus LRESULT COverEditView::OnSetOverwrite(WPARAM Overwrite, LPARAM) { return (LRESULT)SetOverwriteMode((BOOL)Overwrite); } ///////////////////////////////////////////////////////////////////////////// // Aktualisierung der Statuszeile bei Wechsel des Überschreibmodus void COverEditView::OnUpdateIndicatorOvr(CCmdUI* pCmdUI) { pCmdUI->Enable(m_bOverwrite); } ///////////////////////////////////////////////////////////////////////////// // COverEditView diagnostics #ifdef _DEBUG void COverEditView::AssertValid() const { CEditView::AssertValid(); } void COverEditView::Dump(CDumpContext& dc) const { CEditView::Dump(dc); dc << "\nm_bOverwrite = " << m_bOverwrite << "\n"; } #endif //_DEBUG /////////////////////////////////////////////////////////////////////////////