OSDN Git Service

crystaledit: Use GetProfile*()/WriteProfile*() to read and write the registry wheneve...
[winmerge-jp/winmerge-jp.git] / Src / GhostTextView.cpp
1 ////////////////////////////////////////////////////////////////////////////
2 //  File:       GhostTextView.h
3 //  Version:    1.0.0.0
4 //  Created:    31-Jul-2003
5 //
6 /////////////////////////////////////////////////////////////////////////////
7 //    WinMerge:  an interactive diff/merge utility
8 //    Copyright (C) 1997-2000  Thingamahoochie Software
9 //    Author: Dean Grimm
10 //    SPDX-License-Identifier: GPL-2.0-or-later
11 /////////////////////////////////////////////////////////////////////////////
12
13
14 #include "stdafx.h"
15 #include "GhostTextView.h"
16 #include "GhostTextBuffer.h"
17
18 #ifdef _DEBUG
19 #define new DEBUG_NEW
20 #endif
21
22
23 IMPLEMENT_DYNCREATE (CGhostTextView, CCrystalEditViewEx)
24
25 /** 
26  * @brief Constructor, initializes members.
27  */
28 CGhostTextView::CGhostTextView()
29 : m_pGhostTextBuffer(nullptr)
30 , m_ptCursorPosPushed{}
31 , m_ptSelStartPushed{}
32 , m_ptSelEndPushed{}
33 , m_ptAnchorPushed{}
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)
42 {
43 }
44
45 void CGhostTextView::
46 ReAttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
47 {
48         if (pBuf == nullptr)
49         {
50                 pBuf = LocateTextBuffer ();
51                 // ...
52         }
53         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
54         CCrystalEditViewEx::ReAttachToBuffer(pBuf);
55 }
56
57 void CGhostTextView::
58 AttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
59 {
60         if (pBuf == nullptr)
61         {
62                 pBuf = LocateTextBuffer ();
63                 // ...
64         }
65         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
66         CCrystalEditViewEx::AttachToBuffer(pBuf);
67 }
68
69 void CGhostTextView::
70 DetachFromBuffer ()
71 {
72         m_pGhostTextBuffer = nullptr;
73         CCrystalEditViewEx::DetachFromBuffer();
74 }
75
76 void CGhostTextView::popPosition(SCursorPushed Ssrc, CPoint & pt)
77 {
78         pt.x = Ssrc.x;
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())
83         {
84                 pt.y = GetLineCount()-1;
85                 pt.x = GetLineLength(pt.y);
86         }
87         if (pt.y < 0)
88                 pt.y = 0;
89 }
90
91 void CGhostTextView::pushPosition(SCursorPushed & Sdest, CPoint pt)
92 {
93         Sdest.x = pt.x;
94         if (m_pGhostTextBuffer)
95                 Sdest.y = m_pGhostTextBuffer->ComputeRealLineAndGhostAdjustment(pt.y, Sdest.nToFirstReal);
96         else
97                 Sdest.y = pt.y;
98 }
99
100 void CGhostTextView::PopCursors ()
101 {
102         CPoint ptCursorLast = m_ptCursorLast;
103         popPosition(m_ptCursorPosPushed, ptCursorLast);
104
105         ASSERT_VALIDTEXTPOS (ptCursorLast);
106         SetCursorPos (ptCursorLast);
107
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);
114         // laoran 2003/09/03
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);
118
119         if (m_bDraggingText)
120         {
121                 popPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
122                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextBegin);
123                 popPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
124                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextEnd);
125         }
126         if (m_bDropPosVisible)
127         {
128                 popPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
129                 ASSERT_VALIDTEXTPOS(m_ptSavedCaretPos);
130         }
131         if (m_bSelectionPushed)
132         {
133                 popPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
134                 ASSERT_VALIDTEXTPOS(m_ptSavedSelStart);
135                 popPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
136                 ASSERT_VALIDTEXTPOS(m_ptSavedSelEnd);
137         }
138
139         CPoint ptLastChange;
140         if (m_ptLastChangePushed.y == 0 && m_ptLastChangePushed.nToFirstReal > 0)
141                 ptLastChange = CPoint(-1,-1);
142         else 
143         {
144                 popPosition(m_ptLastChangePushed, ptLastChange);
145                 ASSERT_VALIDTEXTPOS(ptLastChange);
146         }
147         m_pGhostTextBuffer->RestoreLastChangePos(ptLastChange);
148
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)
154                 m_nTopSubLine = 0;
155         int nDummy;
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     RecalcHorzScrollBar();
161 }
162
163 void CGhostTextView::PushCursors ()
164 {
165         pushPosition(m_ptCursorPosPushed, m_ptCursorPos);
166         pushPosition(m_ptSelStartPushed, m_ptSelStart);
167         pushPosition(m_ptSelEndPushed, m_ptSelEnd);
168         pushPosition(m_ptAnchorPushed, m_ptAnchor);
169         if (m_bDraggingText)
170         {
171                 pushPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
172                 pushPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
173         }
174         if (m_bDropPosVisible)
175         {
176                 pushPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
177         }
178         if (m_bSelectionPushed)
179         {
180                 pushPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
181                 pushPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
182         }
183
184         pushPosition(m_ptLastChangePushed, m_pGhostTextBuffer ? m_pGhostTextBuffer->GetLastChangePos() : CPoint{0, 0});
185
186         // and top line positions
187         m_nTopSubLinePushed = m_nTopSubLine;
188         m_nOffsetCharPushed = m_nOffsetChar;
189 }
190
191
192
193
194 int CGhostTextView::ComputeRealLine (int nApparentLine) const
195 {
196         if (m_pGhostTextBuffer == nullptr)
197                 return 0;
198         return m_pGhostTextBuffer->ComputeRealLine(nApparentLine);
199 }
200
201 int CGhostTextView::ComputeApparentLine (int nRealLine) const
202 {
203         return m_pGhostTextBuffer->ComputeApparentLine(nRealLine);
204 }
205
206 void CGhostTextView::GetTextWithoutEmptys (int nStartLine, int nStartChar,
207                 int nEndLine, int nEndChar, CString &text,
208                 CRLFSTYLE nCrlfStyle /*= CRLFSTYLE::AUTOMATIC*/,
209                 bool bExcludeInvisibleLines /*= true*/)
210 {
211   if (m_pGhostTextBuffer != nullptr)
212     m_pGhostTextBuffer->GetTextWithoutEmptys (nStartLine, nStartChar, nEndLine, nEndChar, text, nCrlfStyle, bExcludeInvisibleLines);
213   else
214     text = _T ("");
215 }
216
217 void CGhostTextView::GetTextWithoutEmptysInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/)
218 {
219         if (m_pGhostTextBuffer == nullptr)
220         {
221                 text = _T ("");
222                 return;
223         }
224
225         PrepareSelBounds ();
226
227         CString sEol = m_pGhostTextBuffer->GetStringEol (CRLFSTYLE::DOS);
228
229         int nBufSize = 1;
230         for (int L = m_ptDrawSelStart.y; L <= m_ptDrawSelEnd.y; L++)
231                 nBufSize += GetLineLength (L) + sEol.GetLength ();
232         LPTSTR pszBuf = text.GetBuffer (nBufSize);
233
234         for (int I = m_ptDrawSelStart.y; I <= m_ptDrawSelEnd.y; I++)
235         {
236                 // exclude ghost lines
237                 if ((GetLineFlags(I) & LF_GHOST) || (bExcludeInvisibleLines && (GetLineFlags(I) & LF_INVISIBLE)))
238                         continue;
239
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 ();
246         }
247         pszBuf[0] = 0;
248         text.ReleaseBuffer ();
249         text.FreeExtra ();
250 }
251
252 HGLOBAL CGhostTextView::PrepareDragData ()
253 {
254         PrepareSelBounds ();
255         if (m_ptDrawSelStart == m_ptDrawSelEnd)
256                 return nullptr;
257
258         CString text;
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)
264                 return nullptr;
265
266         LPTSTR pszData = (LPTSTR)::GlobalLock (hData);
267         if (pszData != nullptr)
268                 memcpy (pszData, text, cbData);
269         ::GlobalUnlock (hData);
270
271         m_ptDraggedTextBegin = m_ptDrawSelStart;
272         m_ptDraggedTextEnd = m_ptDrawSelEnd;
273         return hData;
274 }
275
276 /**
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.
282  */
283 void CGhostTextView::DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
284 {
285         int nRealLineNumber;
286         if (nLineIndex < 0 || GetLineFlags(nLineIndex) & LF_GHOST)
287                 nRealLineNumber = -1;
288         else
289                 nRealLineNumber = ComputeRealLine(nLineIndex) + 1;
290         CCrystalTextView::DrawMargin(rect, nLineIndex, nRealLineNumber);
291 }