|
1 // TextView.cpp |
|
2 // |
|
3 // Copyright (c) 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 #include "Misc.h" |
|
13 #include "TextView.h" |
|
14 #include "Window.h" |
|
15 |
|
16 |
|
17 const int KCursorHeight = 2; |
|
18 |
|
19 |
|
20 CTextView* CTextView::New(CWindow& aWindow, CTextBuffer& aTextBuffer, int aWidthInChars, int aHeightInChars) |
|
21 { |
|
22 std::auto_ptr<CTextView> self(new(EThrow) CTextView(aWindow, aTextBuffer)); |
|
23 self->Construct(aWidthInChars, aHeightInChars); |
|
24 return self.release(); |
|
25 } |
|
26 |
|
27 CTextView::~CTextView() |
|
28 { |
|
29 } |
|
30 |
|
31 CTextView::CTextView(CWindow& aWindow, CTextBuffer& aTextBuffer) |
|
32 : iWindow(aWindow), iTextBuffer(aTextBuffer), iViewWidth(0), iViewHeight(0), iNumOverflowLines(aTextBuffer.NumOverflowLines()), iCursorEnabled(TRUE), iUpdating(FALSE), iCursorHidden(FALSE), iFocused(FALSE), iSelectionX1(-1), iSelectionY1(-1), iSelectionX2(-1), iSelectionY2(-1), iSelecting(FALSE), iDimmed(FALSE) |
|
33 { |
|
34 } |
|
35 |
|
36 void CTextView::Construct(int aWidthInChars, int aHeightInChars) |
|
37 { |
|
38 iFont = (HFONT)GetStockObject(ANSI_FIXED_FONT); |
|
39 LOGFONT logFont; |
|
40 if (GetObject(iFont, sizeof(LOGFONT), &logFont) == 0) |
|
41 { |
|
42 throw KExceptionConsoleWindowConstructFailed; |
|
43 } |
|
44 |
|
45 // ToDo - Figure out why logFont appears to be out by 1. |
|
46 iCharWidth = 8;//logFont.lfWidth; |
|
47 iCharHeight = 13;//logFont.lfHeight; |
|
48 iViewWidth = aWidthInChars * iCharWidth; |
|
49 iViewHeight = aHeightInChars * iCharHeight; |
|
50 |
|
51 ResetBufferPos(); |
|
52 ConfigureScrollBars(TRUE); |
|
53 iTextBuffer.SetObserver(this); |
|
54 } |
|
55 |
|
56 void CTextView::EnableCursor() |
|
57 { |
|
58 if (!iCursorEnabled) |
|
59 { |
|
60 iCursorEnabled = TRUE; |
|
61 SetCursorVisibility(); |
|
62 } |
|
63 } |
|
64 |
|
65 void CTextView::DisableCursor() |
|
66 { |
|
67 if (iCursorEnabled) |
|
68 { |
|
69 iCursorEnabled = FALSE; |
|
70 SetCursorVisibility(); |
|
71 } |
|
72 } |
|
73 |
|
74 void CTextView::BeginUpdate() |
|
75 { |
|
76 ASSERT(!iUpdating); |
|
77 iUpdating = TRUE; |
|
78 SetCursorVisibility(); |
|
79 } |
|
80 |
|
81 void CTextView::EndUpdate() |
|
82 { |
|
83 ASSERT(iUpdating); |
|
84 iUpdating = FALSE; |
|
85 SetCursorVisibility(); |
|
86 } |
|
87 |
|
88 void CTextView::Draw() const |
|
89 { |
|
90 PAINTSTRUCT ps; |
|
91 HDC hdc = BeginPaint(iWindow.Handle(), &ps); |
|
92 HRGN undrawnRegion = CreateRectRgn(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); |
|
93 --ps.rcPaint.right; |
|
94 --ps.rcPaint.bottom; |
|
95 SetMapMode(hdc, MM_TEXT); |
|
96 HFONT oldFont = (HFONT)SelectObject(hdc, iFont); |
|
97 int bufferWidth; |
|
98 int bufferHeight; |
|
99 iTextBuffer.GetSize(bufferWidth, bufferHeight); |
|
100 int firstLineToDraw; |
|
101 int lastLineToDraw; |
|
102 GetVisibleLines(ps.rcPaint, firstLineToDraw, lastLineToDraw); |
|
103 RECT selectionRect; |
|
104 GetSelectionRect(selectionRect); |
|
105 |
|
106 for (int i = firstLineToDraw; i <= lastLineToDraw; ++i) |
|
107 { |
|
108 RECT lineRect; |
|
109 GetViewRect(0, i, bufferWidth, lineRect); |
|
110 RECT selectionIntersection; |
|
111 IntersectRect(&selectionIntersection, &selectionRect, &lineRect); |
|
112 if (IsRectEmpty(&selectionIntersection)) |
|
113 { |
|
114 COLORREF origTextColor; |
|
115 if (iDimmed) |
|
116 { |
|
117 origTextColor = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); |
|
118 } |
|
119 TextOut(hdc, lineRect.left, lineRect.top, iTextBuffer.GetLine(i), bufferWidth); |
|
120 if (iDimmed) |
|
121 { |
|
122 SetTextColor(hdc, origTextColor); |
|
123 } |
|
124 } |
|
125 else |
|
126 { |
|
127 LPCTSTR lineText = iTextBuffer.GetLine(i); |
|
128 RECT drawRect; |
|
129 drawRect.left = lineRect.left; |
|
130 drawRect.top = lineRect.top; |
|
131 drawRect.right = selectionIntersection.left; |
|
132 drawRect.bottom = selectionIntersection.bottom; |
|
133 COLORREF origTextColor; |
|
134 if (iDimmed) |
|
135 { |
|
136 origTextColor = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); |
|
137 } |
|
138 ExtTextOut(hdc, lineRect.left, lineRect.top, ETO_CLIPPED, &drawRect, lineText, bufferWidth, NULL); |
|
139 if (iDimmed) |
|
140 { |
|
141 SetTextColor(hdc, origTextColor); |
|
142 } |
|
143 drawRect.left = drawRect.right; |
|
144 drawRect.right = selectionIntersection.right; |
|
145 origTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); |
|
146 COLORREF origBackgroundColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); |
|
147 ExtTextOut(hdc, lineRect.left, lineRect.top, ETO_CLIPPED, &drawRect, lineText, bufferWidth, NULL); |
|
148 drawRect.left = drawRect.right; |
|
149 drawRect.right = lineRect.right; |
|
150 SetTextColor(hdc, origTextColor); |
|
151 SetBkColor(hdc, origBackgroundColor); |
|
152 if (iDimmed) |
|
153 { |
|
154 origTextColor = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); |
|
155 } |
|
156 ExtTextOut(hdc, lineRect.left, lineRect.top, ETO_CLIPPED, &drawRect, lineText, bufferWidth, NULL); |
|
157 if (iDimmed) |
|
158 { |
|
159 SetTextColor(hdc, origTextColor); |
|
160 } |
|
161 } |
|
162 HRGN lineRegion = CreateRectRgn(lineRect.left, lineRect.top, lineRect.right, lineRect.bottom); |
|
163 CombineRgn(undrawnRegion, undrawnRegion, lineRegion, RGN_DIFF); |
|
164 DeleteObject(lineRegion); |
|
165 } |
|
166 |
|
167 HBRUSH brush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); |
|
168 FillRgn(hdc, undrawnRegion, brush); |
|
169 DeleteObject(brush); |
|
170 DeleteObject(undrawnRegion); |
|
171 SelectObject(hdc, oldFont); |
|
172 EndPaint(iWindow.Handle(), &ps); |
|
173 } |
|
174 |
|
175 void CTextView::HandleFocusGained() |
|
176 { |
|
177 iFocused = TRUE; |
|
178 CreateCaret(iWindow.Handle(), (HBITMAP) NULL, iCharWidth, 2); |
|
179 iCursorHidden = TRUE; |
|
180 SetCursorPos(); |
|
181 SetCursorVisibility(); |
|
182 } |
|
183 |
|
184 void CTextView::HandleFocusLost() |
|
185 { |
|
186 iFocused = FALSE; |
|
187 DestroyCaret(); |
|
188 } |
|
189 |
|
190 void CTextView::SetSize(int aWidth, int aHeight) |
|
191 { |
|
192 iViewWidth = aWidth; |
|
193 iViewHeight = aHeight; |
|
194 ResetBufferPos(); |
|
195 SetCursorPos(); |
|
196 ConfigureScrollBars(TRUE); |
|
197 ReDraw(); |
|
198 } |
|
199 |
|
200 void CTextView::GetSize(int& aWidth, int& aHeight) const |
|
201 { |
|
202 aWidth = iViewWidth; |
|
203 aHeight = iViewHeight; |
|
204 } |
|
205 |
|
206 void CTextView::SetHorzScrollPosition(int aPosX) |
|
207 { |
|
208 int newBufferPosX; |
|
209 int newBufferPosY; |
|
210 MapScrollPosToBufPix(aPosX, 0, newBufferPosX, newBufferPosY); |
|
211 int dX = newBufferPosX - iBufferPosX; |
|
212 SetBufferPos(newBufferPosX, iBufferPosY); |
|
213 SetCursorPos(); |
|
214 ScrollWindowEx(iWindow.Handle(), dX, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE); |
|
215 UpdateWindow(iWindow.Handle()); |
|
216 } |
|
217 |
|
218 void CTextView::SetVertScrollPosition(int aPosY) |
|
219 { |
|
220 int newBufferPosX; |
|
221 int newBufferPosY; |
|
222 MapScrollPosToBufPix(0, aPosY, newBufferPosX, newBufferPosY); |
|
223 int dY = newBufferPosY - iBufferPosY; |
|
224 SetBufferPos(iBufferPosX, newBufferPosY); |
|
225 SetCursorPos(); |
|
226 ScrollWindowEx(iWindow.Handle(), 0, dY, NULL, NULL, NULL, NULL, SW_INVALIDATE); |
|
227 UpdateWindow(iWindow.Handle()); |
|
228 } |
|
229 |
|
230 void CTextView::StartSelection(int aPosX, int aPosY) |
|
231 { |
|
232 ASSERT(!iSelecting); |
|
233 iSelecting = TRUE; |
|
234 RECT invalidRect; |
|
235 GetSelectionRect(invalidRect); |
|
236 if (!IsRectEmpty(&invalidRect)) |
|
237 { |
|
238 InvalidateRect(iWindow.Handle(), &invalidRect, FALSE); |
|
239 } |
|
240 MapViewPixToBufPix(aPosX, aPosY, aPosX, aPosY); |
|
241 MapBufPixToBufChar(aPosX, aPosY, iSelectionX1, iSelectionY1); |
|
242 iSelectionX2 = iSelectionX1; |
|
243 iSelectionY2 = iSelectionY1; |
|
244 GetSelectionRect(invalidRect); |
|
245 InvalidateRect(iWindow.Handle(), &invalidRect, FALSE); |
|
246 UpdateWindow(iWindow.Handle()); |
|
247 } |
|
248 |
|
249 void CTextView::AdjustSelection(int aPosX, int aPosY) |
|
250 { |
|
251 if (iSelecting) |
|
252 { |
|
253 RECT previousSelectionRect; |
|
254 GetSelectionRect(previousSelectionRect); |
|
255 MapViewPixToBufPix(aPosX, aPosY, aPosX, aPosY); |
|
256 MapBufPixToBufChar(aPosX, aPosY, iSelectionX2, iSelectionY2); |
|
257 int bufferWidth; |
|
258 int bufferHeight; |
|
259 iTextBuffer.GetSize(bufferWidth, bufferHeight); |
|
260 if (iSelectionX2 < 0) |
|
261 { |
|
262 iSelectionX2 = 0; |
|
263 } |
|
264 if (iSelectionX2 >= bufferWidth) |
|
265 { |
|
266 iSelectionX2 = bufferWidth - 1; |
|
267 } |
|
268 if (iSelectionY2 < -iNumOverflowLines) |
|
269 { |
|
270 iSelectionY2 = -iNumOverflowLines; |
|
271 } |
|
272 if (iSelectionY2 >= bufferHeight) |
|
273 { |
|
274 iSelectionY2 = bufferHeight - 1; |
|
275 } |
|
276 RECT newSelectionRect; |
|
277 GetSelectionRect(newSelectionRect); |
|
278 |
|
279 HRGN previousSelectionRegion = CreateRectRgn(previousSelectionRect.left, previousSelectionRect.top, previousSelectionRect.right, previousSelectionRect.bottom); |
|
280 HRGN region = CreateRectRgn(newSelectionRect.left, newSelectionRect.top, newSelectionRect.right, newSelectionRect.bottom); |
|
281 CombineRgn(region, region, previousSelectionRegion, RGN_XOR); |
|
282 DeleteObject(previousSelectionRegion); |
|
283 |
|
284 RECT regionBox; |
|
285 if (GetRgnBox(region, ®ionBox) != NULLREGION) |
|
286 { |
|
287 InvalidateRgn(iWindow.Handle(), region, FALSE); |
|
288 UpdateWindow(iWindow.Handle()); |
|
289 } |
|
290 DeleteObject(region); |
|
291 } |
|
292 } |
|
293 |
|
294 void CTextView::EndSelection(int aPosX, int aPosY) |
|
295 { |
|
296 if (iSelecting) |
|
297 { |
|
298 AdjustSelection(aPosX, aPosY); |
|
299 } |
|
300 iSelecting = FALSE; |
|
301 } |
|
302 |
|
303 void CTextView::SelectWord(int aPosX, int aPosY) |
|
304 { |
|
305 iSelecting = FALSE; |
|
306 RECT invalidRect; |
|
307 GetSelectionRect(invalidRect); |
|
308 if (!IsRectEmpty(&invalidRect)) |
|
309 { |
|
310 InvalidateRect(iWindow.Handle(), &invalidRect, FALSE); |
|
311 } |
|
312 |
|
313 MapViewPixToBufPix(aPosX, aPosY, aPosX, aPosY); |
|
314 MapBufPixToBufChar(aPosX, aPosY, iSelectionX1, iSelectionY1); |
|
315 iSelectionX2 = iSelectionX1; |
|
316 iSelectionY2 = iSelectionY1; |
|
317 LPCTSTR linePtr = iTextBuffer.GetLine(iSelectionY1); |
|
318 |
|
319 if (*(linePtr + iSelectionX1) != TCHAR(' ')) |
|
320 { |
|
321 // Find the beginning of the word. |
|
322 while ((*(linePtr + iSelectionX1) != TCHAR(' ')) && (iSelectionX1 > 0)) |
|
323 { |
|
324 --iSelectionX1; |
|
325 } |
|
326 if (*(linePtr + iSelectionX1) == TCHAR(' ')) |
|
327 { |
|
328 ++iSelectionX1; |
|
329 } |
|
330 int bufferWidth; |
|
331 int bufferHeight; |
|
332 iTextBuffer.GetSize(bufferWidth, bufferHeight); |
|
333 |
|
334 // Find the end of the word. |
|
335 while ((*(linePtr + iSelectionX2) != TCHAR(' ')) && (iSelectionX2 < bufferWidth)) |
|
336 { |
|
337 ++iSelectionX2; |
|
338 } |
|
339 if (*(linePtr + iSelectionX2) == TCHAR(' ')) |
|
340 { |
|
341 --iSelectionX2; |
|
342 } |
|
343 } |
|
344 |
|
345 GetSelectionRect(invalidRect); |
|
346 InvalidateRect(iWindow.Handle(), &invalidRect, FALSE); |
|
347 } |
|
348 |
|
349 int CTextView::CharHeight() const |
|
350 { |
|
351 return iCharHeight; |
|
352 } |
|
353 |
|
354 int CTextView::CharWidth() const |
|
355 { |
|
356 return iCharWidth; |
|
357 } |
|
358 |
|
359 bool CTextView::SelectionAvailable() const |
|
360 { |
|
361 if (iSelectionX1 == -1) |
|
362 { |
|
363 ASSERT(iSelectionY1 == -1); |
|
364 ASSERT(iSelectionX2 == -1); |
|
365 ASSERT(iSelectionY2 == -1); |
|
366 return FALSE; |
|
367 } |
|
368 return TRUE; |
|
369 } |
|
370 |
|
371 LPTSTR CTextView::Selection() const |
|
372 { |
|
373 ASSERT(iSelectionX1 != -1); |
|
374 ASSERT(iSelectionY1 != -1); |
|
375 ASSERT(iSelectionX2 != -1); |
|
376 ASSERT(iSelectionY2 != -1); |
|
377 int tlX = min(iSelectionX1, iSelectionX2); |
|
378 int tlY = min(iSelectionY1, iSelectionY2); |
|
379 int brX = max(iSelectionX1, iSelectionX2); |
|
380 int brY = max(iSelectionY1, iSelectionY2); |
|
381 TCHAR* buf = new TCHAR[((brX - tlX + 3) * (brY - tlY + 1)) + 1]; |
|
382 if (buf) |
|
383 { |
|
384 TCHAR* bufPtr = buf; |
|
385 for (int y = tlY; y <= brY; ++y) |
|
386 { |
|
387 LPCTSTR lineText = iTextBuffer.GetLine(y); |
|
388 int x; |
|
389 for (x = tlX; x <= brX; ++x) |
|
390 { |
|
391 *bufPtr++ = lineText[x]; |
|
392 } |
|
393 while ((*(bufPtr - 1) == TCHAR(' ')) && (x > tlX)) |
|
394 { // Remove trailing spaces from line. |
|
395 --bufPtr; |
|
396 --x; |
|
397 } |
|
398 if (y < brY) |
|
399 { |
|
400 *bufPtr++ = TCHAR('\r'); |
|
401 *bufPtr++ = TCHAR('\n'); |
|
402 } |
|
403 } |
|
404 *bufPtr = TCHAR('\0'); |
|
405 } |
|
406 return buf; |
|
407 } |
|
408 |
|
409 void CTextView::ClearSelection() |
|
410 { |
|
411 RECT invalidRect; |
|
412 GetSelectionRect(invalidRect); |
|
413 iSelectionX1 = iSelectionY1 = iSelectionX2 = iSelectionY2 = -1; |
|
414 if (!IsRectEmpty(&invalidRect)) |
|
415 { |
|
416 InvalidateRect(iWindow.Handle(), &invalidRect, FALSE); |
|
417 UpdateWindow(iWindow.Handle()); |
|
418 } |
|
419 } |
|
420 |
|
421 void CTextView::SetDimmed(bool aDimmed) |
|
422 { |
|
423 if (!aDimmed != !iDimmed) |
|
424 { |
|
425 iDimmed = aDimmed; |
|
426 if (iDimmed) |
|
427 { |
|
428 DisableCursor(); |
|
429 } |
|
430 else |
|
431 { |
|
432 EnableCursor(); |
|
433 } |
|
434 iWindow.Redraw(); |
|
435 } |
|
436 } |
|
437 |
|
438 void CTextView::HandleTextBufferChange(int aPosX, int aPosY, PTCHAR aPtr, int aLength) |
|
439 { |
|
440 RECT viewRect; |
|
441 GetViewRect(aPosX, aPosY, aLength, viewRect); |
|
442 RECT clientRect = {0, 0, iViewWidth, iViewHeight}; |
|
443 RECT intersection; |
|
444 IntersectRect(&intersection, &clientRect, &viewRect); |
|
445 if (!IsRectEmpty(&intersection)) |
|
446 { |
|
447 InvalidateRect(iWindow.Handle(), &intersection, FALSE); |
|
448 UpdateWindow(iWindow.Handle()); |
|
449 } |
|
450 } |
|
451 |
|
452 void CTextView::HandleTextBufferScroll() |
|
453 { |
|
454 bool doScroll(FALSE); |
|
455 ASSERT((iNumOverflowLines == iTextBuffer.NumOverflowLines()) || (iNumOverflowLines + 1 == iTextBuffer.NumOverflowLines())); |
|
456 bool newOverflowLine(iNumOverflowLines != iTextBuffer.NumOverflowLines()); |
|
457 int moveBufferBy(0); |
|
458 |
|
459 if (BottomLineVisible()) |
|
460 { |
|
461 if (newOverflowLine) |
|
462 { |
|
463 moveBufferBy = -iCharHeight; |
|
464 } |
|
465 doScroll = TRUE; |
|
466 } |
|
467 else if (TopLineVisible() && !newOverflowLine) |
|
468 { |
|
469 doScroll = TRUE; |
|
470 } |
|
471 else if (!newOverflowLine) |
|
472 { |
|
473 moveBufferBy = iCharHeight; |
|
474 } |
|
475 |
|
476 if (newOverflowLine) |
|
477 { |
|
478 ++iNumOverflowLines; |
|
479 } |
|
480 |
|
481 ScrollSelection(); |
|
482 |
|
483 if (moveBufferBy) |
|
484 { |
|
485 MoveBuffer(moveBufferBy); |
|
486 } |
|
487 |
|
488 if (doScroll) |
|
489 { |
|
490 ScrollWindowEx(iWindow.Handle(), 0, -iCharHeight, NULL, NULL, NULL, NULL, SW_INVALIDATE); |
|
491 UpdateWindow(iWindow.Handle()); |
|
492 } |
|
493 |
|
494 SetCursorPos(); |
|
495 ConfigureScrollBars(FALSE); |
|
496 } |
|
497 |
|
498 void CTextView::HandleTextBufferCursorChange() |
|
499 { |
|
500 SetCursorPos(); |
|
501 } |
|
502 |
|
503 void CTextView::HandleTextBufferCleared() |
|
504 { |
|
505 iNumOverflowLines = 0; |
|
506 ResetBufferPos(); |
|
507 ConfigureScrollBars(TRUE); |
|
508 ReDraw(); |
|
509 } |
|
510 |
|
511 void CTextView::SetCursorVisibility() |
|
512 { |
|
513 if (iCursorEnabled && !iUpdating && CursorInView()) |
|
514 { |
|
515 if (iCursorHidden) |
|
516 { |
|
517 ShowCaret(iWindow.Handle()); |
|
518 iCursorHidden = FALSE; |
|
519 } |
|
520 } |
|
521 else if (!iCursorHidden) |
|
522 { |
|
523 HideCaret(iWindow.Handle()); |
|
524 iCursorHidden = TRUE; |
|
525 } |
|
526 } |
|
527 |
|
528 bool CTextView::CursorInView() const |
|
529 { |
|
530 int cursorX; |
|
531 int cursorY; |
|
532 GetCursorPixelPos(cursorX, cursorY); |
|
533 RECT cursorRect = {cursorX, cursorY, cursorX + iCharWidth, cursorY + KCursorHeight}; |
|
534 return RectVisible(cursorRect); |
|
535 } |
|
536 |
|
537 void CTextView::GetCursorPixelPos(int& aX, int& aY) const |
|
538 { |
|
539 iTextBuffer.GetCursorPos(aX, aY); |
|
540 MapBufCharToBufPix(aX, aY, aX, aY); |
|
541 aY += (iCharHeight - KCursorHeight); |
|
542 MapBufPixToViewPix(aX, aY, aX, aY); |
|
543 } |
|
544 |
|
545 void CTextView::SetCursorPos() |
|
546 { |
|
547 if (iFocused) |
|
548 { |
|
549 int cursorX; |
|
550 int cursorY; |
|
551 GetCursorPixelPos(cursorX, cursorY); |
|
552 SetCaretPos(cursorX, cursorY); |
|
553 } |
|
554 } |
|
555 |
|
556 void CTextView::ResetBufferPos() |
|
557 { |
|
558 SetBufferPos(0, MinBufferPosY()); |
|
559 } |
|
560 |
|
561 void CTextView::SetBufferPos(int aPosX, int aPosY) |
|
562 { |
|
563 iBufferPosX = aPosX; |
|
564 iBufferPosY = aPosY; |
|
565 SetCursorVisibility(); |
|
566 } |
|
567 |
|
568 void CTextView::MoveBuffer(int aDiffY) |
|
569 { |
|
570 iBufferPosY += aDiffY; |
|
571 ASSERT(iBufferPosY <= MaxBufferPosY()); |
|
572 int min = MinBufferPosY(); |
|
573 if (iBufferPosY < min) |
|
574 { |
|
575 iBufferPosY = min; |
|
576 } |
|
577 } |
|
578 |
|
579 void CTextView::ConfigureScrollBars(bool aReset) |
|
580 { |
|
581 int bufferWidth; |
|
582 int bufferHeight; |
|
583 iTextBuffer.GetSize(bufferWidth, bufferHeight); |
|
584 bufferHeight += iNumOverflowLines; |
|
585 |
|
586 int vertMax = (bufferHeight * iCharHeight) - 1; |
|
587 int horzMax = (bufferWidth * iCharWidth) - 1; |
|
588 |
|
589 SCROLLINFO scrollInfo; |
|
590 scrollInfo.cbSize = sizeof(scrollInfo); |
|
591 scrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; |
|
592 scrollInfo.nMin = 0; |
|
593 scrollInfo.nMax = vertMax; |
|
594 scrollInfo.nPage = iViewHeight; |
|
595 if (aReset) |
|
596 { |
|
597 scrollInfo.nPos = vertMax; |
|
598 } |
|
599 else |
|
600 { |
|
601 scrollInfo.nPos = -iBufferPosY; |
|
602 } |
|
603 SetScrollInfo(iWindow.Handle(), SB_VERT, &scrollInfo, TRUE); |
|
604 |
|
605 scrollInfo.fMask = aReset ? SIF_RANGE | SIF_PAGE | SIF_POS : SIF_RANGE | SIF_PAGE; |
|
606 scrollInfo.nMax = horzMax; |
|
607 scrollInfo.nPage = iViewWidth; |
|
608 if (aReset) |
|
609 { |
|
610 scrollInfo.nPos = 0; |
|
611 } |
|
612 SetScrollInfo(iWindow.Handle(), SB_HORZ, &scrollInfo, TRUE); |
|
613 } |
|
614 |
|
615 void CTextView::ReDraw() const |
|
616 { |
|
617 InvalidateRect(iWindow.Handle(), NULL, FALSE); |
|
618 } |
|
619 |
|
620 void CTextView::GetViewRect(int aCharPosX, int aCharPosY, int aNumChars, RECT& aRect) const |
|
621 { |
|
622 int x; |
|
623 int y; |
|
624 MapBufCharToBufPix(aCharPosX, aCharPosY, x, y); |
|
625 MapBufPixToViewPix(x, y, x, y); |
|
626 aRect.left = x; |
|
627 aRect.top = y; |
|
628 aRect.right = aRect.left + (aNumChars * iCharWidth); |
|
629 aRect.bottom = aRect.top + iCharHeight; |
|
630 } |
|
631 |
|
632 void CTextView::GetViewRect(int aCharPosX1, int aCharPosY1, int aCharPosX2, int aCharPosY2, RECT& aRect) const |
|
633 { |
|
634 int tlX = min(aCharPosX1, aCharPosX2); |
|
635 int tlY = min(aCharPosY1, aCharPosY2); |
|
636 int brX = max(aCharPosX1, aCharPosX2); |
|
637 int brY = max(aCharPosY1, aCharPosY2); |
|
638 MapBufCharToBufPix(tlX, tlY, tlX, tlY); |
|
639 MapBufPixToViewPix(tlX, tlY, tlX, tlY); |
|
640 MapBufCharToBufPix(brX, brY, brX, brY); |
|
641 MapBufPixToViewPix(brX, brY, brX, brY); |
|
642 brX += iCharWidth; |
|
643 brY += iCharHeight; |
|
644 aRect.left = tlX; |
|
645 aRect.top = tlY; |
|
646 aRect.right = brX; |
|
647 aRect.bottom = brY; |
|
648 } |
|
649 |
|
650 bool CTextView::RectVisible(const RECT& aRect) const |
|
651 { |
|
652 RECT clientRect = {0, 0, iViewWidth, iViewHeight}; |
|
653 RECT intersection; |
|
654 IntersectRect(&intersection, &clientRect, &aRect); |
|
655 return !IsRectEmpty(&intersection); |
|
656 } |
|
657 |
|
658 bool CTextView::LineVisible(int aLinePos) const |
|
659 { |
|
660 int bufWidth; |
|
661 int bufHeight; |
|
662 iTextBuffer.GetSize(bufWidth, bufHeight); |
|
663 RECT rect; |
|
664 GetViewRect(0, aLinePos, bufWidth, rect); |
|
665 return RectVisible(rect); |
|
666 } |
|
667 |
|
668 bool CTextView::TopLineVisible() const |
|
669 { |
|
670 return LineVisible(-iNumOverflowLines); |
|
671 } |
|
672 |
|
673 bool CTextView::BottomLineVisible() const |
|
674 { |
|
675 int bufWidth; |
|
676 int bufHeight; |
|
677 iTextBuffer.GetSize(bufWidth, bufHeight); |
|
678 return LineVisible(bufHeight - 1); |
|
679 } |
|
680 |
|
681 int CTextView::TotalBufferHeight() const |
|
682 { |
|
683 int bufferWidth; |
|
684 int bufferHeight; |
|
685 iTextBuffer.GetSize(bufferWidth, bufferHeight); |
|
686 return (bufferHeight + iNumOverflowLines) * iCharHeight; |
|
687 } |
|
688 |
|
689 int CTextView::MinBufferPosY() const |
|
690 { |
|
691 return iViewHeight - TotalBufferHeight(); |
|
692 } |
|
693 |
|
694 int CTextView::MaxBufferPosY() const |
|
695 { |
|
696 int minBufferPosY = MinBufferPosY(); |
|
697 if (minBufferPosY <= 0) |
|
698 { |
|
699 return 0; |
|
700 } |
|
701 return minBufferPosY; |
|
702 } |
|
703 |
|
704 void CTextView::GetVisibleLines(const RECT& aRect, int& aFrom, int& aTo) const |
|
705 { |
|
706 int x; |
|
707 int y; |
|
708 MapViewPixToBufPix(aRect.left, aRect.top, x, y); |
|
709 MapBufPixToBufChar(x, y, x, aFrom); |
|
710 MapViewPixToBufPix(aRect.right, aRect.bottom, x, y); |
|
711 MapBufPixToBufChar(x, y, x, aTo); |
|
712 int bufWidth; |
|
713 int bufHeight; |
|
714 iTextBuffer.GetSize(bufWidth, bufHeight); |
|
715 if (aFrom < -iNumOverflowLines) |
|
716 { |
|
717 aFrom = -iNumOverflowLines; |
|
718 } |
|
719 if (aFrom >= bufHeight) |
|
720 { |
|
721 aFrom = bufHeight - 1; |
|
722 } |
|
723 if (aTo >= bufHeight) |
|
724 { |
|
725 aTo = bufHeight - 1; |
|
726 } |
|
727 } |
|
728 |
|
729 void CTextView::MapBufCharToBufPix(int aBufCharPosX, int aBufCharPosY, int& aBufPixPosX, int& aBufPixPosY) const |
|
730 { |
|
731 aBufPixPosX = aBufCharPosX * iCharWidth; |
|
732 aBufPixPosY = (iNumOverflowLines + aBufCharPosY) * iCharHeight; |
|
733 } |
|
734 |
|
735 void CTextView::MapBufPixToViewPix(int aBufPixPosX, int aBufPixPosY, int& aViewPixPosX, int& aViewPixPosY) const |
|
736 { |
|
737 aViewPixPosX = aBufPixPosX + iBufferPosX; |
|
738 aViewPixPosY = aBufPixPosY + iBufferPosY; |
|
739 } |
|
740 |
|
741 void CTextView::MapBufPixToBufChar(int aBufPixPosX, int aBufPixPosY, int& aBufCharPosX, int& aBufCharPosY) const |
|
742 { |
|
743 aBufCharPosX = aBufPixPosX / iCharWidth; |
|
744 aBufCharPosY = (aBufPixPosY / iCharHeight) - iNumOverflowLines; |
|
745 } |
|
746 |
|
747 void CTextView::MapViewPixToBufPix(int aViewPixPosX, int aViewPixPosY, int& aBufPixPosX, int& aBufPixPosY) const |
|
748 { |
|
749 aBufPixPosX = aViewPixPosX - iBufferPosX; |
|
750 aBufPixPosY = aViewPixPosY - iBufferPosY; |
|
751 } |
|
752 |
|
753 void CTextView::MapScrollPosToBufPix(int aScrollPosX, int aScrollPosY, int& aBufPixPosX, int& aBufPixPosY) const |
|
754 { |
|
755 aBufPixPosX = -aScrollPosX; |
|
756 aBufPixPosY = -aScrollPosY; |
|
757 } |
|
758 |
|
759 void CTextView::GetSelectionRect(RECT& aRect) const |
|
760 { |
|
761 if (iSelectionX1 == -1) |
|
762 { |
|
763 ASSERT(iSelectionY1 == -1); |
|
764 ASSERT(iSelectionX2 == -1); |
|
765 ASSERT(iSelectionY2 == -1); |
|
766 aRect.bottom = aRect.left = aRect.right = aRect.top = 0; |
|
767 } |
|
768 else |
|
769 { |
|
770 GetViewRect(iSelectionX1, iSelectionY1, iSelectionX2, iSelectionY2, aRect); |
|
771 } |
|
772 } |
|
773 |
|
774 void CTextView::ScrollSelection() |
|
775 { |
|
776 if (iSelectionX1 == -1) |
|
777 { |
|
778 ASSERT(iSelectionY1 == -1); |
|
779 ASSERT(iSelectionX2 == -1); |
|
780 ASSERT(iSelectionY2 == -1); |
|
781 } |
|
782 else |
|
783 { |
|
784 if ((iSelectionY1 == -iNumOverflowLines) && (iSelectionY2 == -iNumOverflowLines)) |
|
785 { |
|
786 iSelectionX1 = iSelectionY1 = iSelectionX2 = iSelectionY2 = -1; |
|
787 } |
|
788 else |
|
789 { |
|
790 --iSelectionY1; |
|
791 --iSelectionY2; |
|
792 if (iSelectionY1 < -iNumOverflowLines) |
|
793 { |
|
794 iSelectionY1 = -iNumOverflowLines; |
|
795 } |
|
796 if (iSelectionY2 < -iNumOverflowLines) |
|
797 { |
|
798 iSelectionY2 = -iNumOverflowLines; |
|
799 } |
|
800 } |
|
801 } |
|
802 } |
|
803 |
|
804 void CTextView::ScrollToEndIfNeeded() |
|
805 { |
|
806 if (!BottomLineVisible()) |
|
807 { |
|
808 SetVertScrollPosition(TotalBufferHeight()-iViewHeight); |
|
809 ConfigureScrollBars(FALSE); |
|
810 } |
|
811 } |