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
10 // SPDX-License-Identifier: GPL-2.0-or-later
11 /////////////////////////////////////////////////////////////////////////////
15 #include "GhostTextView.h"
16 #include "GhostTextBuffer.h"
23 IMPLEMENT_DYNCREATE (CGhostTextView, CCrystalEditViewEx)
26 * @brief Constructor, initializes members.
28 CGhostTextView::CGhostTextView()
29 : m_pGhostTextBuffer(nullptr)
30 , m_ptCursorPosPushed{}
31 , m_ptSelStartPushed{}
34 , m_ptDraggedTextBeginPushed{}
35 , m_ptDraggedTextEndPushed{}
36 , m_ptSavedCaretPosPushed{}
37 , m_ptSavedSelStartPushed{}
38 , m_ptSavedSelEndPushed{}
39 , m_ptLastChangePushed{}
40 , m_nTopSubLinePushed(0)
41 , m_nOffsetCharPushed(0)
46 ReAttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
50 pBuf = LocateTextBuffer ();
53 m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
54 CCrystalEditViewEx::ReAttachToBuffer(pBuf);
58 AttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
62 pBuf = LocateTextBuffer ();
65 m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
66 CCrystalEditViewEx::AttachToBuffer(pBuf);
72 m_pGhostTextBuffer = nullptr;
73 CCrystalEditViewEx::DetachFromBuffer();
76 void CGhostTextView::popPosition(SCursorPushed Ssrc, CPoint & pt)
79 pt.y = m_pGhostTextBuffer->ComputeApparentLine(Ssrc.y, Ssrc.nToFirstReal);
80 // if the cursor was in a trailing ghost line, and this disappeared,
81 // got at the end of the last line
82 if (pt.y >= GetLineCount())
84 pt.y = GetLineCount()-1;
85 pt.x = GetLineLength(pt.y);
91 void CGhostTextView::pushPosition(SCursorPushed & Sdest, CPoint pt)
94 if (m_pGhostTextBuffer)
95 Sdest.y = m_pGhostTextBuffer->ComputeRealLineAndGhostAdjustment(pt.y, Sdest.nToFirstReal);
100 void CGhostTextView::PopCursors ()
102 CPoint ptCursorLast = m_ptCursorLast;
103 popPosition(m_ptCursorPosPushed, ptCursorLast);
105 ASSERT_VALIDTEXTPOS (ptCursorLast);
106 SetCursorPos (ptCursorLast);
108 popPosition(m_ptSelStartPushed, m_ptSelStart);
109 ASSERT_VALIDTEXTPOS (m_ptSelStart);
110 popPosition(m_ptSelEndPushed, m_ptSelEnd);
111 ASSERT_VALIDTEXTPOS (m_ptSelEnd);
112 popPosition(m_ptAnchorPushed, m_ptAnchor);
113 ASSERT_VALIDTEXTPOS (m_ptAnchor);
115 // here is what we did before, maybe we have to do it, but test with pushed positions
116 // SetSelection (ptCursorLast, ptCursorLast);
117 // SetAnchor (ptCursorLast);
121 popPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
122 ASSERT_VALIDTEXTPOS(m_ptDraggedTextBegin);
123 popPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
124 ASSERT_VALIDTEXTPOS(m_ptDraggedTextEnd);
126 if (m_bDropPosVisible)
128 popPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
129 ASSERT_VALIDTEXTPOS(m_ptSavedCaretPos);
131 if (m_bSelectionPushed)
133 popPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
134 ASSERT_VALIDTEXTPOS(m_ptSavedSelStart);
135 popPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
136 ASSERT_VALIDTEXTPOS(m_ptSavedSelEnd);
140 if (m_ptLastChangePushed.y == 0 && m_ptLastChangePushed.nToFirstReal > 0)
141 ptLastChange = CPoint(-1,-1);
144 popPosition(m_ptLastChangePushed, ptLastChange);
145 ASSERT_VALIDTEXTPOS(ptLastChange);
147 m_pGhostTextBuffer->RestoreLastChangePos(ptLastChange);
149 // restore the scrolling position
150 m_nTopSubLine = m_nTopSubLinePushed;
151 if (m_nTopSubLine >= GetSubLineCount())
152 m_nTopSubLine = GetSubLineCount() - 1;
153 if (m_nTopSubLine < 0)
156 GetLineBySubLine( m_nTopSubLine, m_nTopLine, nDummy );
157 const int nMaxLineLength = GetMaxLineLength(m_nTopLine, GetScreenLines());
158 m_nOffsetChar = (m_nOffsetCharPushed < nMaxLineLength) ? m_nOffsetCharPushed : nMaxLineLength;
159 RecalcVertScrollBar(true);
160 InvalidateHorzScrollBar();
163 void CGhostTextView::PushCursors ()
165 pushPosition(m_ptCursorPosPushed, m_ptCursorPos);
166 pushPosition(m_ptSelStartPushed, m_ptSelStart);
167 pushPosition(m_ptSelEndPushed, m_ptSelEnd);
168 pushPosition(m_ptAnchorPushed, m_ptAnchor);
171 pushPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
172 pushPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
174 if (m_bDropPosVisible)
176 pushPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
178 if (m_bSelectionPushed)
180 pushPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
181 pushPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
184 pushPosition(m_ptLastChangePushed, m_pGhostTextBuffer ? m_pGhostTextBuffer->GetLastChangePos() : CPoint{0, 0});
186 // and top line positions
187 m_nTopSubLinePushed = m_nTopSubLine;
188 m_nOffsetCharPushed = m_nOffsetChar;
194 int CGhostTextView::ComputeRealLine (int nApparentLine) const
196 if (m_pGhostTextBuffer == nullptr)
198 return m_pGhostTextBuffer->ComputeRealLine(nApparentLine);
201 int CGhostTextView::ComputeApparentLine (int nRealLine) const
203 return m_pGhostTextBuffer->ComputeApparentLine(nRealLine);
206 void CGhostTextView::GetTextWithoutEmptys (int nStartLine, int nStartChar,
207 int nEndLine, int nEndChar, CString &text,
208 CRLFSTYLE nCrlfStyle /*= CRLFSTYLE::AUTOMATIC*/,
209 bool bExcludeInvisibleLines /*= true*/)
211 if (m_pGhostTextBuffer != nullptr)
212 m_pGhostTextBuffer->GetTextWithoutEmptys (nStartLine, nStartChar, nEndLine, nEndChar, text, nCrlfStyle, bExcludeInvisibleLines);
217 void CGhostTextView::GetTextWithoutEmptysInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/)
219 if (m_pGhostTextBuffer == nullptr)
227 CString sEol = m_pGhostTextBuffer->GetStringEol (CRLFSTYLE::DOS);
230 for (int L = m_ptDrawSelStart.y; L <= m_ptDrawSelEnd.y; L++)
231 nBufSize += GetLineLength (L) + sEol.GetLength ();
232 LPTSTR pszBuf = text.GetBuffer (nBufSize);
234 for (int I = m_ptDrawSelStart.y; I <= m_ptDrawSelEnd.y; I++)
236 // exclude ghost lines
237 if ((GetLineFlags(I) & LF_GHOST) || (bExcludeInvisibleLines && (GetLineFlags(I) & LF_INVISIBLE)))
240 int nSelLeft, nSelRight;
241 GetColumnSelection (I, nSelLeft, nSelRight);
242 memcpy (pszBuf, GetLineChars (I) + nSelLeft, sizeof (TCHAR) * (nSelRight - nSelLeft));
243 pszBuf += (nSelRight - nSelLeft);
244 memcpy (pszBuf, sEol, sizeof (TCHAR) * sEol.GetLength ());
245 pszBuf += sEol.GetLength ();
248 text.ReleaseBuffer ();
252 HGLOBAL CGhostTextView::PrepareDragData ()
255 if (m_ptDrawSelStart == m_ptDrawSelEnd)
259 GetTextWithoutEmptys (m_ptDrawSelStart.y, m_ptDrawSelStart.x, m_ptDrawSelEnd.y, m_ptDrawSelEnd.x, text);
260 int cchText = text.GetLength();
261 SIZE_T cbData = (cchText + 1) * sizeof(TCHAR);
262 HGLOBAL hData =::GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, cbData);
263 if (hData == nullptr)
266 LPTSTR pszData = (LPTSTR)::GlobalLock (hData);
267 if (pszData != nullptr)
268 memcpy (pszData, text, cbData);
269 ::GlobalUnlock (hData);
271 m_ptDraggedTextBegin = m_ptDrawSelStart;
272 m_ptDraggedTextEnd = m_ptDrawSelEnd;
277 * @brief Draw selection margin.
278 * @param [in] pdc Pointer to draw context.
279 * @param [in] rect The rectangle to draw.
280 * @param [in] nLineIndex Index of line in view.
281 * @param [in] nLineNumber Line number to display. if -1, it's not displayed.
283 void CGhostTextView::DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
286 if (nLineIndex < 0 || GetLineFlags(nLineIndex) & LF_GHOST)
287 nRealLineNumber = -1;
289 nRealLineNumber = ComputeRealLine(nLineIndex) + 1;
290 CCrystalTextView::DrawMargin(rect, nLineIndex, nRealLineNumber);