1 ////////////////////////////////////////////////////////////////////////////
2 // File: GhostTextView.h
4 // Created: 31-Jul-2003
6 /////////////////////////////////////////////////////////////////////////////
7 // WinMerge: an interactive diff/merge utility
8 // Copyright (C) 1997-2000 Thingamahoochie Software
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /////////////////////////////////////////////////////////////////////////////
29 #include "GhostTextView.h"
30 #include "GhostTextBuffer.h"
37 IMPLEMENT_DYNCREATE (CGhostTextView, CCrystalEditViewEx)
40 * @brief Constructor, initializes members.
42 CGhostTextView::CGhostTextView()
43 : m_pGhostTextBuffer(nullptr)
44 , m_ptCursorPosPushed{}
45 , m_ptSelStartPushed{}
48 , m_ptDraggedTextBeginPushed{}
49 , m_ptDraggedTextEndPushed{}
50 , m_ptSavedCaretPosPushed{}
51 , m_ptSavedSelStartPushed{}
52 , m_ptSavedSelEndPushed{}
53 , m_ptLastChangePushed{}
54 , m_nTopSubLinePushed(0)
59 ReAttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
63 pBuf = LocateTextBuffer ();
66 m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
67 CCrystalEditViewEx::ReAttachToBuffer(pBuf);
71 AttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
75 pBuf = LocateTextBuffer ();
78 m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
79 CCrystalEditViewEx::AttachToBuffer(pBuf);
85 m_pGhostTextBuffer = nullptr;
86 CCrystalEditViewEx::DetachFromBuffer();
89 void CGhostTextView::popPosition(SCursorPushed Ssrc, CPoint & pt)
92 pt.y = m_pGhostTextBuffer->ComputeApparentLine(Ssrc.y, Ssrc.nToFirstReal);
93 // if the cursor was in a trailing ghost line, and this disappeared,
94 // got at the end of the last line
95 if (pt.y >= GetLineCount())
97 pt.y = GetLineCount()-1;
98 pt.x = GetLineLength(pt.y);
104 void CGhostTextView::pushPosition(SCursorPushed & Sdest, CPoint pt)
107 if (m_pGhostTextBuffer)
108 Sdest.y = m_pGhostTextBuffer->ComputeRealLineAndGhostAdjustment(pt.y, Sdest.nToFirstReal);
113 void CGhostTextView::PopCursors ()
115 CPoint ptCursorLast = m_ptCursorLast;
116 popPosition(m_ptCursorPosPushed, ptCursorLast);
118 ASSERT_VALIDTEXTPOS (ptCursorLast);
119 SetCursorPos (ptCursorLast);
121 popPosition(m_ptSelStartPushed, m_ptSelStart);
122 ASSERT_VALIDTEXTPOS (m_ptSelStart);
123 popPosition(m_ptSelEndPushed, m_ptSelEnd);
124 ASSERT_VALIDTEXTPOS (m_ptSelEnd);
125 popPosition(m_ptAnchorPushed, m_ptAnchor);
126 ASSERT_VALIDTEXTPOS (m_ptAnchor);
128 // here is what we did before, maybe we have to do it, but test with pushed positions
129 // SetSelection (ptCursorLast, ptCursorLast);
130 // SetAnchor (ptCursorLast);
134 popPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
135 ASSERT_VALIDTEXTPOS(m_ptDraggedTextBegin);
136 popPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
137 ASSERT_VALIDTEXTPOS(m_ptDraggedTextEnd);
139 if (m_bDropPosVisible)
141 popPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
142 ASSERT_VALIDTEXTPOS(m_ptSavedCaretPos);
144 if (m_bSelectionPushed)
146 popPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
147 ASSERT_VALIDTEXTPOS(m_ptSavedSelStart);
148 popPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
149 ASSERT_VALIDTEXTPOS(m_ptSavedSelEnd);
153 if (m_ptLastChangePushed.y == 0 && m_ptLastChangePushed.nToFirstReal > 0)
154 ptLastChange = CPoint(-1,-1);
157 popPosition(m_ptLastChangePushed, ptLastChange);
158 ASSERT_VALIDTEXTPOS(ptLastChange);
160 m_pGhostTextBuffer->RestoreLastChangePos(ptLastChange);
162 // restore the scrolling position
163 m_nTopSubLine = m_nTopSubLinePushed;
164 if (m_nTopSubLine >= GetSubLineCount())
165 m_nTopSubLine = GetSubLineCount() - 1;
166 if (m_nTopSubLine < 0)
169 GetLineBySubLine( m_nTopSubLine, m_nTopLine, nDummy );
170 RecalcVertScrollBar(true);
171 RecalcHorzScrollBar();
174 void CGhostTextView::PushCursors ()
176 pushPosition(m_ptCursorPosPushed, m_ptCursorPos);
177 pushPosition(m_ptSelStartPushed, m_ptSelStart);
178 pushPosition(m_ptSelEndPushed, m_ptSelEnd);
179 pushPosition(m_ptAnchorPushed, m_ptAnchor);
182 pushPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
183 pushPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
185 if (m_bDropPosVisible)
187 pushPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
189 if (m_bSelectionPushed)
191 pushPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
192 pushPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
195 pushPosition(m_ptLastChangePushed, m_pGhostTextBuffer ? m_pGhostTextBuffer->GetLastChangePos() : CPoint{0, 0});
197 // and top line positions
198 m_nTopSubLinePushed = m_nTopSubLine;
204 int CGhostTextView::ComputeRealLine (int nApparentLine) const
206 if (m_pGhostTextBuffer == nullptr)
208 return m_pGhostTextBuffer->ComputeRealLine(nApparentLine);
211 int CGhostTextView::ComputeApparentLine (int nRealLine) const
213 return m_pGhostTextBuffer->ComputeApparentLine(nRealLine);
216 void CGhostTextView::GetTextWithoutEmptys (int nStartLine, int nStartChar,
217 int nEndLine, int nEndChar, CString &text,
218 CRLFSTYLE nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/,
219 bool bExcludeInvisibleLines /*= true*/)
221 if (m_pGhostTextBuffer != nullptr)
222 m_pGhostTextBuffer->GetTextWithoutEmptys (nStartLine, nStartChar, nEndLine, nEndChar, text, nCrlfStyle, bExcludeInvisibleLines);
227 void CGhostTextView::GetTextWithoutEmptysInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/)
229 if (m_pGhostTextBuffer == nullptr)
237 CString sEol = m_pGhostTextBuffer->GetStringEol (CRLF_STYLE_DOS);
240 for (int L = m_ptDrawSelStart.y; L <= m_ptDrawSelEnd.y; L++)
241 nBufSize += GetLineLength (L) + sEol.GetLength ();
242 LPTSTR pszBuf = text.GetBuffer (nBufSize);
244 for (int I = m_ptDrawSelStart.y; I <= m_ptDrawSelEnd.y; I++)
246 // exclude ghost lines
247 if ((GetLineFlags(I) & LF_GHOST) || (bExcludeInvisibleLines && (GetLineFlags(I) & LF_INVISIBLE)))
250 int nSelLeft, nSelRight;
251 GetColumnSelection (I, nSelLeft, nSelRight);
252 memcpy (pszBuf, GetLineChars (I) + nSelLeft, sizeof (TCHAR) * (nSelRight - nSelLeft));
253 pszBuf += (nSelRight - nSelLeft);
254 memcpy (pszBuf, sEol, sizeof (TCHAR) * sEol.GetLength ());
255 pszBuf += sEol.GetLength ();
258 text.ReleaseBuffer ();
262 HGLOBAL CGhostTextView::PrepareDragData ()
265 if (m_ptDrawSelStart == m_ptDrawSelEnd)
269 GetTextWithoutEmptys (m_ptDrawSelStart.y, m_ptDrawSelStart.x, m_ptDrawSelEnd.y, m_ptDrawSelEnd.x, text);
270 int cchText = text.GetLength();
271 SIZE_T cbData = (cchText + 1) * sizeof(TCHAR);
272 HGLOBAL hData =::GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, cbData);
273 if (hData == nullptr)
276 LPTSTR pszData = (LPTSTR)::GlobalLock (hData);
277 if (pszData != nullptr)
278 memcpy (pszData, text, cbData);
279 ::GlobalUnlock (hData);
281 m_ptDraggedTextBegin = m_ptDrawSelStart;
282 m_ptDraggedTextEnd = m_ptDrawSelEnd;
287 * @brief Draw selection margin.
288 * @param [in] pdc Pointer to draw context.
289 * @param [in] rect The rectangle to draw.
290 * @param [in] nLineIndex Index of line in view.
291 * @param [in] nLineNumber Line number to display. if -1, it's not displayed.
293 void CGhostTextView::DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
296 if (nLineIndex < 0 || GetLineFlags(nLineIndex) & LF_GHOST)
297 nRealLineNumber = -1;
299 nRealLineNumber = ComputeRealLine(nLineIndex) + 1;
300 CCrystalTextView::DrawMargin(rect, nLineIndex, nRealLineNumber);