comparison anagram/vaclgui/agview.cpp @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13d2b8934445
1 /*
2 * AnaGram, A System for Syntax Directed Programming
3 * Copyright 1997-2002 Parsifal Software. All Rights Reserved.
4 * See the file COPYING for license and usage terms.
5 *
6 * agview.cpp
7 */
8
9 #include <icoordsy.hpp>
10 #include <windows.h>
11
12 #include "agstring.h"
13 #include "agview.hpp"
14 #include "arrays.h"
15 #include "config.h"
16 #include "ctrlpanel.hpp"
17 #include "dspar.hpp"
18 #include "frame.hpp"
19 #include "minmax.h"
20 #include "vaclgui.hpp"
21
22 //#define INCLUDE_LOGGING
23 #include "log.h"
24
25
26 int focusWindowId;
27
28 const int AgView::defaultWindowHeight = 12;
29
30
31 Boolean AgFocusHandler::dispatchHandlerEvent(IEvent &event) {
32 //LOGSECTION("AgFocusHandler::dispatchHandlerEvent", Log::off);
33 LOGSECTION_OFF("AgFocusHandler::dispatchHandlerEvent");
34 static int focusHandlerCalls = 0;
35 focusHandlerCalls++;
36 LOGV(event.eventId());
37 if (event.eventId() == WM_SETFOCUS) {
38 LOGS("WM_SETFOCUS") LCV((int) event.controlWindow());
39 int flag;
40 flag = gotFocus(event);
41 if (flag) {
42 event.setResult(flag);
43 }
44 return flag;
45 }
46 if (event.eventId() == WM_KILLFOCUS) {
47 LOGS("WM_KILLFOCUS") LCV((int) event.controlWindow());
48 int flag = lostFocus(event);
49 event.setResult(flag);
50 return flag;
51 }
52 return false;
53 }
54
55 AgColumnHead::AgColumnHead(int id, IWindow* parent)
56 : IStaticText(id, parent, parent)
57 , title()
58 , nCols(0)
59 , tabs(0)
60 , xPos(0)
61 , color(&ColorSpec::inactiveTitle)
62 , dataColorChange(this, onColorChange)
63 {
64 LOGSECTION("AgColumnHead constructor");
65 IPaintHandler::handleEventsFor(this);
66 /*
67 yBias =
68 ICoordinateSystem::isConversionNeeded()
69 ? font().maxSize().height() - font().maxDescender()
70 : 0;
71 LOGV(yBias);
72 */
73 dataColorChange.attach(&ColorSpec::data);
74 dataColorChange.attach(&ColorSpec::inactiveTitle);
75 dataColorChange.attach(&ColorSpec::activeTitle);
76 setText("Column headers");
77 show();
78 }
79
80
81 AgColumnHead::~AgColumnHead() {
82 IPaintHandler::stopHandlingEventsFor(this);
83 }
84
85 void AgColumnHead::setTitles(int nCols_, AgString title_) {
86 LOGSECTION("AgColumnHead::setTitles");
87 nCols = nCols_;
88 title = title_;
89
90 setText(title.pointer());
91 LOGV(title.pointer());
92 LOGV(size().asString());
93 }
94
95 void AgColumnHead::setMargin(int margin_) {
96 margin = margin_;
97 }
98
99 void AgColumnHead::setPos(int pos_) {
100 xPos = pos_;
101 }
102
103 void AgColumnHead::setTabs(int *tabs_) {
104 tabs = tabs_;
105 }
106
107 Boolean AgColumnHead::paintWindow(IPaintEvent &event) {
108 int i = 0;
109
110 if (event.rect().area() == 0) {
111 return true;
112 }
113 LOGSECTION("AgColumnHead::paintWindow");
114 LOGV(title.pointer());
115 IPresSpaceHandle handle = event.presSpaceHandle(); //cookie
116 SetBkMode(handle, TRANSPARENT);
117 event.clearBackground(color->bg());
118 font().beginUsingFont(handle);
119 int textHeight = font().maxSize().height();
120 int verticalMargin = (size().height() - textHeight)/2;
121
122 LOGV(textHeight);
123 LOGV(verticalMargin);
124 //LOGV(yBias);
125 LOGV(margin);
126 LOGV(xPos);
127 int yBias =
128 ICoordinateSystem::isConversionNeeded()
129 ? font().maxSize().height() - font().maxDescender()
130 : 0;
131 IPoint trueWhere(margin - xPos, verticalMargin + yBias);
132 IPoint where =
133 ICoordinateSystem::isConversionNeeded()
134 ? ICoordinateSystem::convertToNative(trueWhere, size())
135 : trueWhere;
136
137 LOGV(trueWhere.asString());
138 LOGV(where.asString());
139 AgString temp(title.pointer());
140 FindTabs tabsKluge(temp.pointer());
141 char *p = tabsKluge.getField();
142 LOGV(rect().asString());
143 while (i < nCols) {
144 LOGV(i);
145 LOGV(p);
146 LOGV(where.asString());
147 LOGV(color->fg().asString());
148 LOGV(p) LCV(where.asString());
149 event.drawText(p,where, color->fg());
150 where += IPoint(tabs[i], 0);
151 p = tabsKluge.getField();
152 i++;
153 }
154 font().endUsingFont(handle);
155 return true;
156 }
157
158 AgStaticText &AgStaticText::scrollWindow(IPoint distance) {
159 IRectangle clipRect(size());
160
161 //LOGSECTION("AgStaticText::scrollWindow", Log::off);
162 LOGSECTION_OFF("AgStaticText::scrollWindow");
163 LOGV(distance.asString());
164 LOGV(clipRect.asString());
165
166 RECTL rct = clipRect.asRECTL();
167 ScrollWindowEx(handle(), distance.x(), distance.y(), 0, (RECT *) &rct,
168 0,0,SW_INVALIDATE);
169 return *this;
170 }
171
172 AgView &AgView::hideCursor() {
173 if (!cursorEnabled) {
174 return *this;
175 }
176 //LOGSECTION("AgView::hideCursor", Log::off);
177 LOGSECTION_OFF("AgView::hideCursor");
178 cursorHideCount++;
179 LOGV(cursorHideCount);
180 IFLOG(int flag = ) HideCaret(dataArea.handle());
181 LOGV(flag);
182 return *this;
183 }
184
185 AgView &AgView::showCursor() {
186 if (!cursorEnabled) {
187 return *this;
188 }
189 //LOGSECTION("AgView::showCursor", Log::off);
190 LOGSECTION_OFF("AgView::showCursor");
191 cursorHideCount--;
192 LOGV(cursorHideCount);
193 IFLOG(int flag = ) ShowCaret(dataArea.handle());
194 LOGV(flag);
195 return *this;
196 }
197
198
199
200 AgView::AgView(IWindow *ownerWindow_)
201 : ICanvas(nextChildId(), ownerWindow_, ownerWindow_)
202 , ownerWindow(ownerWindow_)
203 , horizontalScrollBar(nextChildId(), this, this, IRectangle(),
204 IScrollBar::horizontal
205 | IWindow::visible)
206 , verticalScrollBar(nextChildId(), this, this, IRectangle(),
207 IScrollBar::vertical
208 | IWindow::visible)
209 , dataHole(nextChildId(), this, this)
210 , dataArea(nextChildId(), &dataHole, &dataHole)
211 , vsbShowing(false)
212 , hsbShowing(false)
213 , columnHeadTitle(nextChildId(), this)
214 , columnHeadsPresent(0)
215 , cursorLine(0)
216 , mouseDown(0)
217 , tabArray(0)
218 , tableWidth(0)
219 , tableHeight(0)
220 , cursorEnabled(0)
221 , cursorLocation(0,0)
222 , pixelCursor(font().avgCharWidth(),0)
223 , cursorLineHighlight(0)
224 , prevHorizontal(0)
225 , prevVertical(0)
226 , color(&ColorSpec::syntaxFile)
227 , cursorColor(&ColorSpec::activeCursor)
228 , rightButtonDown(0)
229 , layoutActive(0)
230 , retainCursor(cursorLineHighlight)
231 , frameWindow(0)
232 , dataColorChange(this, onColorChange)
233 {
234 LOGSECTION("AgView constructor");
235 LOGV(id()) LCV((int) this) LCV(handle().asDebugInfo());
236 LOGV(dataArea.id()) LCV((int) &dataArea)
237 LCV(dataArea.handle().asDebugInfo());
238 dataColorChange.attach(&ColorSpec::data);
239 dataColorChange.attach(&ColorSpec::inactiveCursor);
240 dataColorChange.attach(&ColorSpec::activeCursor);
241 for (int i = 0; i < 256; i++) {
242 charWidth[i] = font().charWidth(i);
243 }
244 IWindow *f;
245 for (f = ownerWindow; !f->isFrameWindow(); f=f->parent());
246 frameWindow = (AgFrame *) f;
247 windowId = id();
248 AgString title = columnTitleText();
249 LOGV(title.pointer());
250 if (title.exists()) {
251 columnHeadTitle.setTitles(nColumns(), title);
252 ISize size = columnHeadTitle.size();
253 columnHeadTitle.setMinimumSize(size);
254 LOGV(size.asString());
255 columnHeadTitle.setMargin(avgCharWidth());
256 columnHeadTitle.enableFillBackground();
257 columnHeadsPresent = 1;
258 }
259
260 horizontalScrollBar.setScrollableRange(IRange(0, 100));
261 horizontalScrollBar.moveScrollBoxTo(0);
262 verticalScrollBar.setScrollableRange(IRange(0, 100));
263 verticalScrollBar.moveScrollBoxTo(0);
264
265 IKeyboardHandler::handleEventsFor(&dataArea);
266 IMouseHandler ::handleEventsFor(&dataArea);
267 IMouseHandler ::handleEventsFor(&columnHeadTitle);
268 IMouseHandler ::handleEventsFor(&verticalScrollBar);
269 IMouseHandler ::handleEventsFor(&horizontalScrollBar);
270 IPaintHandler ::handleEventsFor(&dataArea);
271 IResizeHandler ::handleEventsFor(this);
272 IScrollHandler ::handleEventsFor(this);
273 show();
274 }
275
276 AgView::~AgView() {
277 delete [] tabArray;
278 if (cursorEnabled) {
279 AgFocusHandler::stopHandlingEventsFor(this);
280 AgFocusHandler::stopHandlingEventsFor(&dataArea);
281 }
282 IKeyboardHandler::stopHandlingEventsFor(&dataArea);
283 IMouseHandler ::stopHandlingEventsFor(&dataArea);
284 IMouseHandler ::stopHandlingEventsFor(&columnHeadTitle);
285 IMouseHandler ::stopHandlingEventsFor(&verticalScrollBar);
286 IMouseHandler ::stopHandlingEventsFor(&horizontalScrollBar);
287 IPaintHandler ::stopHandlingEventsFor(&dataArea);
288 IResizeHandler ::stopHandlingEventsFor(this);
289 IScrollHandler ::stopHandlingEventsFor(this);
290 }
291
292 AgView &AgView::enableCursorBar(int flag) {
293 flag = (flag != 0);
294 if (flag == cursorLineHighlight) {
295 return *this;
296 }
297 cursorLineHighlight = flag;
298 if (flag) {
299 retainCursor = 1;
300 AgFocusHandler::handleEventsFor(&dataArea);
301 AgFocusHandler::handleEventsFor(this);
302 LOGV(dataArea.hasFocus());
303 LOGV(hasFocus());
304 if (dataArea.hasFocus()) {
305 LOGV(dataArea.size().height());
306 cursorOn();
307 //setCursorPos(pixelCursor);
308 }
309 }
310 else {
311 if (dataArea.hasFocus()) {
312 //hideCursor();
313 cursorOff();
314 }
315 AgFocusHandler::stopHandlingEventsFor(&dataArea);
316 AgFocusHandler::stopHandlingEventsFor(this);
317 }
318 return *this;
319 }
320
321 AgView &AgView::enableCursor(int flag) {
322 LOGSECTION("AgView::enableCursor");
323 LOGV(cursorEnabled) LCV(flag);
324 flag = (flag != 0);
325 if (flag == cursorEnabled) {
326 return *this;
327 }
328 LOGS("changing cursor state");
329 cursorEnabled = flag;
330 LOGV(cursorEnabled);
331 if (flag) {
332 retainCursor = 0;
333 AgFocusHandler::handleEventsFor(&dataArea);
334 AgFocusHandler::handleEventsFor(this);
335 LOGV(dataArea.hasFocus());
336 LOGV(hasFocus());
337 if (dataArea.hasFocus()) {
338 LOGV(dataArea.size().height());
339 cursorOn();
340 //setCursorPos(pixelCursor);
341 }
342 }
343 else {
344 if (dataArea.hasFocus()) {
345 //hideCursor();
346 cursorOff();
347 }
348 AgFocusHandler::stopHandlingEventsFor(&dataArea);
349 AgFocusHandler::stopHandlingEventsFor(this);
350 }
351 return *this;
352 }
353
354 AgView &AgView::cursorOn() {
355 //LOGSECTION("AgView::cursorOn", Log::off);
356 LOGSECTION_OFF("AgView::cursorOn");
357 cint origin(horizontalScrollBar.scrollBoxPosition(),
358 lineHeight()*verticalScrollBar.scrollBoxPosition());
359 pixelCursor.y = lineHeight()*cursorLine;
360 pixelCursor.x = xPosition(cursorLocation.x, getLine(cursorLine));
361 cint relativeCursor = pixelCursor - origin;
362 LOGV(relativeCursor);
363 LOGV(cursorLine);
364 LOGV(pixelCursor);
365 LOGV(dataArea.rect().asString());
366 LOGV(dataArea.hasFocus());
367 IFLOG(int flag = ) CreateCaret(dataArea.handle(), NULL,0, lineHeight());
368 LOGV(flag);
369 SetCaretPos(relativeCursor.x, relativeCursor.y);
370 IFLOG(flag = ) ShowCaret(dataArea.handle());
371 LOGV(flag);
372 cursorHideCount = 0;
373 return *this;
374 }
375
376 AgView &AgView::setCursorPos(cint cursor) {
377 if (!cursorEnabled) {
378 return *this;
379 }
380 //LOGSECTION("AgView::setCursorPos", Log::off);
381 LOGSECTION("AgView::setCursorPos");
382 LOGSTACK;
383 cint origin(horizontalScrollBar.scrollBoxPosition(),
384 lineHeight()*verticalScrollBar.scrollBoxPosition());
385
386 //cint origin(0, lineHeight()*verticalScrollBar.scrollBoxPosition());
387 cint relativeCursor = cursor - origin;
388 LOGV(cursor) LCV(origin) LCV(relativeCursor);
389 hideCursor();
390 IFLOG(int flag = ) SetCaretPos(relativeCursor.x, relativeCursor.y);
391 LOGV(flag);
392 showCursor();
393 return *this;
394 }
395
396 AgView &AgView::cursorOff() {
397 //LOGSECTION("AgView::cursorOff", Log::off);
398 LOGSECTION_OFF("AgView::cursorOff");
399 IFLOG(int flag = ) DestroyCaret();
400 LOGV(flag);
401 return *this;
402 }
403
404 Boolean AgView::gotFocus(IEvent &) {
405 //LOGSECTION("AgView::gotFocus", Log::off);
406 LOGSECTION_OFF("AgView::gotFocus");
407 //LOGSTACK;
408 if (cursorEnabled) {
409 LOGV(pixelCursor);
410 LOGV(dataArea.size().height());
411 cursorOn();
412 //setCursorPos(pixelCursor);
413 }
414 columnHeadTitle.color = &ColorSpec::activeTitle;
415 columnHeadTitle.refresh();
416 if (cursorLineHighlight) {
417 cursorColor = &ColorSpec::activeCursor;
418 repaintLine(cursorLine);
419 }
420 focusWindowId = windowId;
421 return false;
422 //return true;
423 }
424
425 Boolean AgView::lostFocus(IEvent &) {
426 //LOGSECTION("AgView::lostFocus", Log::off);
427 LOGSECTION_OFF("AgView::lostFocus");
428 //LOGSTACK;
429 if (cursorEnabled) {
430 //hideCursor();
431 cursorOff();
432 }
433 columnHeadTitle.color = &ColorSpec::inactiveTitle;
434 columnHeadTitle.refresh();
435 if (cursorLineHighlight) {
436 cursorColor = &ColorSpec::inactiveCursor;
437 repaintLine(cursorLine);
438 }
439 return false;
440 }
441
442 int AgView::findMaxWidth() {
443 LOGSECTION("AgView::findMaxWidth");
444 int maxWidth = 0;
445 int nl = nLines();
446 int nCols = nColumns();
447 LOGV(nl) LCV(nCols);
448 char *columnTitles = columnTitleText().pointer();
449 int i;
450
451 if (tabArray == NULL) {
452 tabArray = new int[nCols + 1];
453 memset(tabArray, 0, (nCols+1)*sizeof(int));
454 }
455 IFont windowFont = font();
456
457 if (columnTitles) {
458 //char *titles = new char[1+strlen(columnTitles)];
459 //char *titles = local_array(1+strlen(columnTitles), char);
460 LocalArray<char> titles(1+strlen(columnTitles));
461 strcpy(titles, columnTitles);
462 FindTabs tabs(titles);
463 char *p = tabs.getField();
464 i = 0;
465 while(i < nCols && p) {
466 int width = windowFont.textWidth(p);
467 if (width > tabArray[i]) {
468 tabArray[i] = width;
469 }
470 if (++i >= nCols) {
471 break;
472 }
473 p = tabs.getField();
474 }
475 while (i < nCols) {
476 tabArray[i++] = 0;
477 }
478 //delete [] titles;
479 }
480 else {
481 for (i = 0; i < nCols; i++) {
482 tabArray[i] = 0;
483 }
484 }
485 columnHeadWidth = 0;
486 for (i = 0; i < nCols; i++) {
487 columnHeadWidth += tabArray[i] + 2*avgCharWidth();
488 }
489 //int *width = new int[nCols];
490 //int *width = local_array(nCols, int);
491 int *width = LocalArray<int>(nCols);
492 memset(width, 0, nCols*sizeof(int));
493 LOGV((int) width);
494 LOGV((int) tabArray);
495 int enWidth = avgCharWidth();
496 int columnWidth = enWidth*tab_spacing;
497 while (nl--) {
498 LOGV(nl);
499 AgString line = getLine(nl);
500 LOGV(line);
501 LOGV(nl);
502 FindTabs tabs(line.pointer());
503 char *p = tabs.getField();
504 LOGV(nl) LCV((int) p);
505 LOGV(p);
506 int whereX = 0;
507 if (nCols > 1) {
508 i = 0;
509 while (i < nCols && p) {
510 width[i] = windowFont.textWidth(p);
511 LOGV(width[i]);
512 if (++i >= nCols) {
513 break;
514 }
515 p = tabs.getField();
516 }
517 if (i < nCols) {
518 continue;
519 }
520 }
521 else {
522 while (p) {
523 width[0] = whereX + font().textWidth(p);
524 whereX = ((width[0] + columnWidth)/columnWidth) * columnWidth;
525 p = tabs.getField();
526 }
527 }
528 for (i = 0; i < nCols; i++) {
529 if (width[i] > tabArray[i]) {
530 tabArray[i] = width[i];
531 LOGS("***") LV(tabArray[i]);
532 }
533 LOGS("***") LV(tabArray[i]);
534 }
535 }
536 LOGS("width measured");
537 //delete [] width;
538 for (i = 0; i < nCols; i++) {
539 tabArray[i] += 2*avgCharWidth();
540 maxWidth += tabArray[i];
541 }
542 LOGV(maxWidth);
543 return maxWidth;
544 }
545
546 ICanvas &AgView::layout() {
547 LOGSECTION("AgView::layout");
548 if (layoutActive) {
549 return *this;
550 }
551 layoutActive++;
552 doLayout();
553 ICanvas::setLayoutDistorted(0, IWindow::layoutChanged);
554 ICanvas::layout();
555 layoutActive--;
556 return *this;
557 }
558
559 ICanvas &AgView::setLayoutDistorted(unsigned long i, unsigned long j) {
560 //LOGSECTION("AgView::setLayoutDistorted", Log::off);
561 LOGSECTION_OFF("AgView::setLayoutDistorted");
562 //i &= ~IWindow::fontChanged;
563 //j |= IWindow::fontChanged;
564 tableWidth = 0;
565 ICanvas::setLayoutDistorted(i, j);
566 return *this;
567 }
568
569 Boolean AgView::windowResize(IResizeEvent &){
570 LOGSECTION("AgView resize event");
571 setLayoutDistorted(IWindow::layoutChanged,0);
572 return false;
573 }
574
575 ISize AgView::suggestSize() {
576 LOGSECTION("AgView::suggestSize");
577 int width = findMaxWidth();
578 int minWidth = 40*font().avgCharWidth();
579 int maxWidth = 60*font().avgCharWidth();
580 if (width < minWidth) {
581 width = minWidth;
582 }
583 if (width > maxWidth) {
584 width = maxWidth;
585 }
586 int height = tableHeight;
587 if (nLines() > defaultWindowHeight) {
588 width += verticalScrollBar.minimumSize().width() + 1;
589 height = lineHeight() * defaultWindowHeight;
590 }
591 else if (nLines() < 5) {
592 height = lineHeight() * 5;
593 }
594 LOGV(width);
595 LOGV(height);
596 return ISize(width, height);
597 }
598
599 Boolean AgView::paintWindow(IPaintEvent &event) {
600 if (event.controlWindow() != &dataArea) {
601 return false;
602 }
603
604 int height = lineHeight();
605 LOGSECTION("AgView::paintWindow");
606
607 IPresSpaceHandle handle = event.presSpaceHandle(); //cookie
608 SetBkMode(handle, TRANSPARENT);
609
610 font().beginUsingFont(handle);
611 LOGV(event.rect().asString());
612 IRectangle invalidRect(
613 ICoordinateSystem::isConversionNeeded()
614 ? ICoordinateSystem::convertToApplication(event.rect(),dataArea.size())
615 : event.rect()
616 );
617 LOGV(invalidRect.asString());
618 LOGV(dataHole.rect().asString());
619 LOGV(dataArea.rect().asString());
620
621 int baseLine = verticalScrollBar.scrollBoxPosition();
622 int topY = baseLine*lineHeight();
623 int minY = topY + invalidRect.minY();
624 int maxY = topY + invalidRect.maxY();
625 int bottomY = topY + dataHole.size().height();
626 LOGV(minY) LCV(maxY);
627 LOGV(topY) LCV(bottomY);
628 if (minY < topY) {
629 minY = topY;
630 }
631 if (maxY > bottomY) {
632 maxY = bottomY;
633 }
634 invalidRect = IRectangle(IPoint(invalidRect.minX(), minY),
635 (IPoint(invalidRect.maxX(), maxY)));
636
637 LOGV(invalidRect.asString());
638 LOGV(dataHole.size().asString());
639 int firstLine = invalidRect.minY()/height;
640 int lastLine = (invalidRect.maxY()+height - 1)/height - 1;
641
642 if (firstLine < baseLine) {
643 firstLine = baseLine;
644 lastLine += baseLine;
645 }
646
647 int yBias =
648 ICoordinateSystem::isConversionNeeded()
649 ? height - maxDescender()
650 : 0;
651
652
653 int xMargin = avgCharWidth();
654
655 int whereX = -horizontalScrollBar.scrollBoxPosition();
656 int whereY = firstLine*height - topY; //baseline location
657
658 IColor textBgndColor=color->bg();
659 IColor textFgndColor=color->fg();
660 IColor cursorBgndColor=color->bg();
661 IColor cursorFgndColor=color->fg();
662 if (cursorLineHighlight) {
663 cursorBgndColor=cursorColor->bg();
664 cursorFgndColor=cursorColor->fg();
665 }
666
667 LOGV(baseLine);
668 LOGV(firstLine);
669 LOGV(lastLine);
670 LOGV(horizontalScrollBar.scrollBoxPosition());
671
672 int lastInvalidLine = lastLine;
673 if (lastLine >= nLines()) {
674 lastLine = nLines() - 1;
675 }
676 int windowHeight = dataArea.rect().size().height();
677 int dataAreaWidth = dataArea.rect().size().width() - whereX;
678 ISize lineSize(dataAreaWidth, height);
679 IPoint offset(xMargin, 0);
680 int k;
681
682 for (k = firstLine; k <= lastLine; k++, whereY += height) {
683 //LOGSECTION("AgDataView::paintWindow line loop", Log::off);
684 LOGSECTION_OFF("AgDataView::paintWindow line loop");
685 IPoint trueWhere(whereX, whereY + yBias);
686 IPoint where =
687 ICoordinateSystem::isConversionNeeded()
688 ? ICoordinateSystem::convertToNative(trueWhere, dataArea.size())
689 : trueWhere;
690 IRectangle trueLineRect(0, whereY, dataAreaWidth, whereY+height);
691 IRectangle lineRect =
692 ICoordinateSystem::isConversionNeeded()
693 ? ICoordinateSystem::convertToNative(trueLineRect, dataArea.size())
694 : trueLineRect;
695 IColor bgndColor = textBgndColor;
696 IColor fgndColor = textFgndColor;
697 if (k == cursorLine) {
698 bgndColor = cursorBgndColor;
699 fgndColor = cursorFgndColor;
700 }
701 LOGV(lineRect.asString());
702 LOGV(where.asString());
703 event.clearBackground(lineRect,bgndColor);
704 AgString line = getLine(k);
705 LOGV(line.pointer());
706 FindTabs tabs(line.pointer());
707 int enWidth = avgCharWidth();
708 int columnWidth = enWidth*tab_spacing;
709 char *p = tabs.getField();
710 int nCols = nColumns();
711 where += offset;
712 int i = 0;
713 if (nCols > 1) {
714 while (i < nCols && p) {
715 LOGV(p - line.pointer());
716 event.drawText(p, where, fgndColor);
717 where += IPoint(tabArray[i], 0);
718 if (++i >= nCols) {
719 break;
720 }
721 p = tabs.getField();
722 }
723 }
724 else {
725 while (p) {
726 event.drawText(p, where, fgndColor);
727 int whereX = where.x();
728 whereX += font().textWidth(p);
729 whereX += horizontalScrollBar.scrollBoxPosition() - enWidth;
730 whereX = ((whereX + columnWidth)/columnWidth) * columnWidth;
731 whereX -= horizontalScrollBar.scrollBoxPosition() - enWidth;
732 where.setX(whereX);
733 p = tabs.getField();
734 }
735 }
736 }
737 if (k <= lastInvalidLine) {
738 IRectangle trueRemainder(0,whereY,dataAreaWidth, windowHeight);
739 IRectangle remainder =
740 ICoordinateSystem::isConversionNeeded()
741 ? ICoordinateSystem::convertToNative(trueRemainder, dataArea.size())
742 : trueRemainder;
743 LOGV(remainder.asString());
744 event.clearBackground(remainder,textBgndColor);
745 }
746 font().endUsingFont(handle);
747 return true;
748 }
749
750 AgView &AgView::repaintLine(int line) {
751 LOGSECTION("AgView::repaintLine");
752 if (line < 0 || line >= nLines()) {
753 return *this;
754 }
755 int baseLine = verticalScrollBar.scrollBoxPosition();
756 int y = (line - baseLine) * lineHeight();
757 IRectangle rect(0, y, dataArea.rect().size().width(), y + lineHeight());
758 LOGV(line) LCV(baseLine) LCV(y) LCV(rect.asString());
759 dataArea.refresh(rect);
760 return *this;
761 }
762
763 AgView &AgView::updateCursor(int line) {
764 LOGSECTION_OFF("AgView::updateCursor");
765 LOGV(line) LCV(cursorLine);
766 if (retainCursor && line != cursorLine) {
767 int oldCursor = cursorLine;
768 if (cursorLine < line) {
769 cursorLocation.y = cursorLine = line;
770 }
771 int bottomLine = line + verticalScrollBar.visibleCount() - 1;
772 if (cursorLine > bottomLine) {
773 cursorLocation.y = cursorLine = bottomLine;
774 }
775 LOGV(line) LCV(cursorLine) LCV(bottomLine);
776 if (cursorLineHighlight && cursorLine != oldCursor) {
777 repaintLine(oldCursor);
778 repaintLine(cursorLine);
779 }
780 }
781 reposition();
782 cursorLocation.y = cursorLine;
783 pixelCursor.y = lineHeight() * cursorLine;
784 if (cursorEnabled && dataArea.hasFocus()) {
785 setCursorPos(pixelCursor);
786 }
787 return *this;
788 }
789
790 AgView &AgView::reposition() {
791 //LOGSECTION("AgView::reposition", Log::off);
792 LOGSECTION("AgView::reposition");
793
794 if (cursorEnabled) hideCursor();
795 int verticalOffset = verticalScrollBar.scrollBoxPosition()
796 - prevVertical;
797
798 int horizontalOffset = horizontalScrollBar.scrollBoxPosition()
799 - prevHorizontal;
800
801 IPoint displacement(-horizontalOffset, -lineHeight()*verticalOffset);
802
803 LOGV(displacement.asString());
804
805 dataArea.scrollWindow(displacement);
806 dataArea.refresh();
807 prevHorizontal = horizontalScrollBar.scrollBoxPosition();
808 prevVertical = verticalScrollBar.scrollBoxPosition();
809 cursorLocation.y = cursorLine;
810 pixelCursor.y = cursorLine*lineHeight();
811 if (cursorEnabled) {
812 setCursorPos(pixelCursor).showCursor();
813 }
814 return *this;
815 }
816
817 AgView &AgView::repaintCursor(int line) {
818 LOGSECTION("AgView::repaintCursor");
819 LOGV(line) LCV(cursorLine);
820 cursorLocation.y = cursorLine;
821 pixelCursor.y = cursorLine*lineHeight();
822 if (cursorLineHighlight && cursorLine != line) {
823 repaintLine(line);
824 repaintLine(cursorLine);
825 }
826 return *this;
827 }
828
829 AgView &AgView::updateCursor() {
830 LOGSECTION("AgView::updateCursor");
831 cursorLocation.y = cursorLine;
832 LOGV(cursorLocation);
833 pixelCursor.y = cursorLine*lineHeight();
834 LOGV(pixelCursor);
835 if (cursorEnabled) {
836 setCursorPos(pixelCursor);
837 }
838 return *this;
839 }
840
841 /*
842 *
843 * Layout considerations:
844 *
845 * The data view consists of up to four parts: two scroll bars, a heading
846 * and a data area.
847 *
848 * The presence or absence of the scroll bars depends on the relative size
849 * of the data area and the size of the table to be displayed.
850 */
851
852 AgView &AgView::doLayout() {
853 LOGSECTION("AgView::doLayout");
854 if (cursorEnabled && dataArea.hasFocus()) {
855 hideCursor();
856 }
857
858 if (tableWidth == 0) {
859 tableWidth = findMaxWidth();
860 }
861 tableHeight = lineHeight()*nLines();
862
863 LOGV(tableWidth);
864 LOGV(tableHeight);
865 columnHeadTitle.setTabs(tabArray);
866 ISize canvasSize = size();
867 int canvasWidth = canvasSize.width();
868 int canvasHeight = canvasSize.height();
869 if (canvasWidth == 0 && canvasHeight == 0) {
870 return *this;
871 }
872
873 LOGV(canvasWidth);
874 LOGV(canvasHeight);
875
876 int dataWidth = canvasWidth;
877 int dataHeight = canvasHeight;
878 int dataY = 0;
879 if (columnHeadsPresent) {
880 dataY = columnHeadTitle.minimumSize().height();
881 dataHeight -= dataY;
882 columnHeadTitle.moveTo(IPoint(0,0));
883 }
884
885 LOGV(dataWidth);
886 LOGV(dataHeight);
887
888 LOGV(tableWidth);
889 LOGV(tableHeight);
890
891
892 int vsbWidth = verticalScrollBar.minimumSize().width();
893 int hsbHeight = horizontalScrollBar.minimumSize().height();
894
895 int horizontalPosition = horizontalScrollBar.scrollBoxPosition();
896 int verticalPosition = verticalScrollBar.scrollBoxPosition();
897
898 Boolean vsb = true;
899 Boolean hsb = true;
900
901 if (tableHeight > canvasHeight
902 && tableWidth <= canvasWidth - vsbWidth - 1) {
903 // vertical scroll bar only
904 vsb = true;
905 hsb = false;
906 }
907 else if (tableWidth > canvasWidth
908 && tableHeight <= canvasHeight - hsbHeight - 1) {
909 // horizontal scroll bar only
910 vsb = false;
911 hsb = true;
912 }
913 else if (tableWidth <= canvasWidth && tableHeight <= canvasHeight) {
914 // no scroll bars
915 vsb = hsb = false;
916 }
917 LOGV(vsb) LCV(vsbShowing);
918 LOGV(hsb) LCV(hsbShowing);
919
920 if (vsb && !vsbShowing) {
921 verticalScrollBar.moveScrollBoxTo(0);
922 prevVertical = 0;
923 verticalScrollBar.show();
924 vsbShowing = true;
925 }
926 if (!vsb && vsbShowing) {
927 verticalScrollBar.hide();
928 vsbShowing = false;
929 verticalScrollBar.moveScrollBoxTo(0);
930 prevVertical = 0;
931 }
932
933 if (hsb && !hsbShowing) {
934 horizontalScrollBar.show();
935 hsbShowing = true;
936 horizontalScrollBar.moveScrollBoxTo(0);
937 prevHorizontal = 0;
938 }
939 if (!hsb && hsbShowing) {
940 horizontalScrollBar.hide();
941 hsbShowing = false;
942 horizontalScrollBar.moveScrollBoxTo(0);
943 prevHorizontal = 0;
944 }
945
946 if (vsbShowing) {
947 dataWidth -= vsbWidth + 1;
948 verticalScrollBar.moveTo(IPoint(dataWidth+1, 0));
949 verticalScrollBar.sizeTo(ISize(vsbWidth, canvasHeight));
950 }
951
952 if (hsbShowing) {
953 dataHeight -= hsbHeight + 1;
954 horizontalScrollBar.moveTo(IPoint(0, dataHeight+1));
955 horizontalScrollBar.sizeTo(ISize(dataWidth, hsbHeight));
956 }
957
958 dataHole.sizeTo(ISize(dataWidth, dataHeight));
959 dataHole.moveTo(IPoint(0, dataY));
960
961 LOGV(nLines());
962 LOGV(lineHeight());
963 LOGV(nLines()*lineHeight());
964
965 int desiredWidth = tableWidth;
966 if (tableWidth < dataWidth) {
967 desiredWidth = dataWidth;
968 }
969 ISize desiredSize(desiredWidth, dataHeight);
970
971 LOGV(desiredSize.asString());
972
973 dataArea.sizeTo(desiredSize);
974
975 LOGV(dataArea.size().asString());
976 LOGV(dataArea.parentSize().asString());
977
978 dataArea.moveTo(IPoint(0, 0));
979 LOGV(rect().asString());
980 LOGV(dataArea.rect().asString());
981 LOGV(horizontalScrollBar.rect().asString());
982 LOGV(verticalScrollBar.rect().asString());
983
984 horizontalScrollBar.setScrollableRange(IRange(0,tableWidth-1));
985 horizontalScrollBar.setVisibleCount(dataWidth);
986
987 verticalScrollBar.setVisibleCount(dataHeight/lineHeight());
988 verticalScrollBar.setScrollableRange(IRange(0, nLines() - 1));
989
990 horizontalPosition = min(
991 (int) horizontalScrollBar.scrollBoxRange().upperBound(),
992 horizontalPosition
993 );
994 verticalPosition = min(
995 (int) verticalScrollBar.scrollBoxRange().upperBound(),
996 verticalPosition
997 );
998
999 verticalPosition = max(
1000 (int)(cursorLine - verticalScrollBar.visibleCount() + 1),
1001 verticalPosition
1002 );
1003
1004 horizontalScrollBar.setMinScrollIncrement(maxCharWidth());
1005 verticalScrollBar.setMinScrollIncrement(1);
1006
1007 horizontalScrollBar.moveScrollBoxTo(horizontalPosition);
1008 prevHorizontal = horizontalPosition;
1009 verticalScrollBar.moveScrollBoxTo(verticalPosition);
1010 prevVertical = verticalPosition;
1011 if (columnHeadsPresent) {
1012 ISize headSize(dataWidth, columnHeadTitle.minimumSize().height());
1013 columnHeadTitle.sizeTo(headSize);
1014 columnHeadTitle.xPos = horizontalPosition;
1015 columnHeadTitle.refresh();
1016 }
1017 refresh();
1018 LOGV(dataArea.hasFocus());
1019 LOGV(vsb) LCV(vsbShowing);
1020 LOGV(hsb) LCV(hsbShowing);
1021 if (cursorEnabled && dataArea.hasFocus()) {
1022 setCursorPos(pixelCursor).showCursor();
1023 }
1024 return *this;
1025 }
1026
1027 int AgView::charPosition(int xPos, AgString line) {
1028 int i;
1029 int enWidth = avgCharWidth();
1030 int x = enWidth;
1031 int columnWidth = enWidth*tab_spacing;
1032 int spaceWidth = charWidth[' '];
1033 unsigned char *p = (unsigned char *) line.pointer();
1034
1035 //LOGSECTION("AgView::charPosition", Log::off);
1036 LOGSECTION_OFF("AgView::charPosition");
1037
1038 LOGV(p) LCV(xPos);
1039
1040 if (p == 0) {
1041 return 0;
1042 }
1043 for (i = 0; p[i]; i++) {
1044 int newX = x + charWidth[p[i]];
1045 if (p[i] == '\t') {
1046 LOGSECTION("AgView::charPosition::tab");
1047 LOGV(x) LCV(columnWidth);
1048 int j = 0;
1049 if (nColumns() > 1 && tabArray) {
1050 while (tabArray[j] && tabArray[j] <= x) {
1051 j++;
1052 }
1053 if (tabArray[j] > newX) {
1054 newX = tabArray[j];
1055 }
1056 }
1057 else {
1058 /*
1059 int hPos = horizontalScrollBar.scrollBoxPosition();
1060 newX = x + hPos - enWidth;
1061 newX = ((newX + columnWidth)/columnWidth)*columnWidth;
1062 newX -= hPos - enWidth;
1063 */
1064 newX = enWidth + ((x-enWidth + columnWidth)/columnWidth) * columnWidth;
1065 }
1066 LOGV(x);
1067 }
1068 if (p[i] == ' ') {
1069 LOGV(x);
1070 newX = x + spaceWidth;
1071 }
1072 //if (newX > xPos) {
1073 if (xPos <= (x+newX)/2) {
1074 LOGV(i) LCV(xPos) LCV(x) LCV(newX);
1075 return i;
1076 }
1077 x = newX;
1078 }
1079 return i ? i - 1 : 0;
1080 }
1081
1082 int AgView::xPosition(int charPos, AgString line) {
1083 //LOGSECTION("AgView::xPosition", Log::off);
1084 LOGSECTION_OFF("AgView::xPosition");
1085 int i;
1086 int enWidth = avgCharWidth();
1087 int x = enWidth;
1088 int columnWidth = enWidth*tab_spacing;
1089 int spaceWidth = charWidth[' '];
1090 unsigned char *p = (unsigned char *) line.pointer();
1091
1092 LOGV(p);
1093 LOGV(charPos);
1094 LOGV(line.pointer());
1095
1096 if (p == 0) {
1097 return x;
1098 }
1099 for (i = 0; p[i] && i < charPos; i++) {
1100 if (p[i] == '\t') {
1101 LOGSECTION("AgView::xPosition::tab");
1102 LOGV(x) LCV(columnWidth);
1103 int j = 0;
1104 if (nColumns() > 1 && tabArray) {
1105 while (tabArray[j] && tabArray[j] <= x) {
1106 j++;
1107 }
1108 if (tabArray[j] > x) {
1109 x = tabArray[j];
1110 }
1111 }
1112 else {
1113 x = enWidth + ((x-enWidth + columnWidth)/columnWidth) * columnWidth;
1114 }
1115 /*
1116 else {
1117 int hPos = horizontalScrollBar.scrollBoxPosition();
1118 x += hPos - enWidth;
1119 x = ((x + columnWidth)/columnWidth)*columnWidth;
1120 x -= hPos - enWidth;
1121 }
1122 */
1123 LOGV(x);
1124 continue;
1125 }
1126 if (p[i] == ' ') {
1127 LOGV(x);
1128 x += spaceWidth;
1129 continue;
1130 }
1131 x += charWidth[p[i]];
1132 }
1133 LOGV(x);
1134 LOGV(i);
1135 return x;
1136 }
1137
1138 void AgView::checkFocus(void) {
1139 #ifdef AG_WINDOWSX
1140 if (!dataArea.hasFocus()) {
1141 dataArea.setFocus();
1142 }
1143 #endif
1144 }
1145
1146 Boolean AgView::lineDown(IScrollEvent &event) {
1147 if (event.scrollBarWindow() != &verticalScrollBar) {
1148 return false;
1149 }
1150 //LOGSECTION("AgView::lineDown", Log::off);
1151 LOGSECTION_OFF("AgView::lineDown");
1152 LOGV(cursorLine);
1153 checkFocus();
1154 hideCursor();
1155 moveScrollBox(event);
1156 int line = verticalScrollBar.scrollBoxPosition();
1157 updateCursor(line);
1158 showCursor();
1159 return true;
1160 }
1161
1162 Boolean AgView::lineLeft(IScrollEvent &event) {
1163 if (event.scrollBarWindow() != &horizontalScrollBar) {
1164 return false;
1165 }
1166 //LOGSECTION("AgView::lineLeft", Log::off);
1167 LOGSECTION_OFF("AgView::lineLeft");
1168 if (cursorEnabled) {
1169 hideCursor();
1170 }
1171 checkFocus();
1172 moveScrollBox(event);
1173 reposition();
1174 if (cursorEnabled) {
1175 setCursorPos(pixelCursor).showCursor();
1176 }
1177 return true;
1178 }
1179
1180 Boolean AgView::lineRight(IScrollEvent &event) {
1181 if (event.scrollBarWindow() != &horizontalScrollBar) {
1182 return false;
1183 }
1184 //LOGSECTION("AgView::lineRight", Log::off);
1185 LOGSECTION_OFF("AgView::lineRight");
1186 checkFocus();
1187 if (cursorEnabled) {
1188 hideCursor();
1189 }
1190 moveScrollBox(event);
1191 reposition();
1192 if (cursorEnabled) {
1193 showCursor();
1194 }
1195 return true;
1196 }
1197
1198 Boolean AgView::lineUp(IScrollEvent &event) {
1199 if (event.scrollBarWindow() != &verticalScrollBar) {
1200 return false;
1201 }
1202 checkFocus();
1203 hideCursor();
1204 moveScrollBox(event);
1205 int line = verticalScrollBar.scrollBoxPosition();
1206 updateCursor(line);
1207 showCursor();
1208 return true;
1209 }
1210
1211 Boolean AgView::pageDown(IScrollEvent &event) {
1212 if (event.scrollBarWindow() != &verticalScrollBar) {
1213 return false;
1214 }
1215 checkFocus();
1216 hideCursor();
1217 moveScrollBox(event);
1218 int line = verticalScrollBar.scrollBoxPosition();
1219 updateCursor(line);
1220 showCursor();
1221 return true;
1222 }
1223
1224 Boolean AgView::pageLeft(IScrollEvent &event) {
1225 if (event.scrollBarWindow() != &horizontalScrollBar) {
1226 return false;
1227 }
1228 checkFocus();
1229 if (cursorEnabled) {
1230 hideCursor();
1231 }
1232 moveScrollBox(event);
1233 reposition();
1234 if (cursorEnabled) {
1235 showCursor();
1236 }
1237 return true;
1238 }
1239
1240 Boolean AgView::pageRight(IScrollEvent &event) {
1241 if (event.scrollBarWindow() != &horizontalScrollBar) {
1242 return false;
1243 }
1244 checkFocus();
1245 if (cursorEnabled) {
1246 hideCursor();
1247 }
1248 moveScrollBox(event);
1249 reposition();
1250 if (cursorEnabled) {
1251 showCursor();
1252 }
1253 return true;
1254 }
1255
1256 Boolean AgView::pageUp(IScrollEvent &event) {
1257 if (event.scrollBarWindow() != &verticalScrollBar) {
1258 return false;
1259 }
1260 checkFocus();
1261 hideCursor();
1262 moveScrollBox(event);
1263 int line = verticalScrollBar.scrollBoxPosition();
1264 updateCursor(line);
1265 showCursor();
1266 return true;
1267 }
1268
1269 Boolean AgView::scrollBoxTrack(IScrollEvent &event) {
1270 checkFocus();
1271 if (cursorEnabled) {
1272 hideCursor();
1273 }
1274 moveScrollBox(event);
1275 reposition();
1276 if (event.scrollBarWindow() == &verticalScrollBar) {
1277 int line = verticalScrollBar.scrollBoxPosition();
1278 updateCursor(line);
1279 if (cursorEnabled) {
1280 showCursor();
1281 }
1282 return true;
1283 }
1284 if (cursorEnabled) {
1285 showCursor();
1286 }
1287 //if (event.scrollBarWindow() != &horizontalScrollBar) return false;
1288 return true;
1289 }
1290
1291 AgView &AgView::setCursorLocation(cint loc) {
1292 //LOGSECTION("AgView::setCursorLocation", Log::off);
1293 LOGSECTION_OFF("AgView::setCursorLocation");
1294 //LOGSTACK;
1295 //hideCursor();
1296 if (loc.y < 0) {
1297 loc.y = 0;
1298 }
1299 if (loc.y >= nLines()) {
1300 loc.y = nLines() - 1;
1301 }
1302 LOGV(cursorLocation);
1303 LOGV(loc);
1304 cursorLocation = loc;
1305 unsigned oldCursor = cursorLine;
1306 cursorLine = loc.y;
1307 pixelCursor.x = xPosition(cursorLocation.x, getLine(cursorLine));
1308 pixelCursor.y = lineHeight()*cursorLine;
1309 int repositionFlag = 0;
1310 int vPos = verticalScrollBar.scrollBoxPosition();
1311 int vLimit = vPos + verticalScrollBar.visibleCount() - 1;
1312 int hPos = horizontalScrollBar.scrollBoxPosition();
1313 int hLimit = hPos + horizontalScrollBar.visibleCount() - 4;
1314 if (loc.y < vPos) {
1315 verticalScrollBar.moveScrollBoxTo(loc.y);
1316 repositionFlag = 1;
1317 }
1318 if (loc.y > vLimit) {
1319 verticalScrollBar.moveScrollBoxTo(vPos + loc.y - vLimit);
1320 repositionFlag = 1;
1321 }
1322 if (pixelCursor.x < hPos) {
1323 int x;
1324 int cursorX = cursorLocation.x - 5;
1325 if (cursorX <= 0) {
1326 x = 0;
1327 }
1328 else x = xPosition(cursorX, getLine(cursorLine));
1329 horizontalScrollBar.moveScrollBoxTo(x);
1330 repositionFlag = 1;
1331 }
1332 if (pixelCursor.x > hLimit) {
1333 int x = xPosition(cursorLocation.x+5, getLine(cursorLine));
1334 horizontalScrollBar.moveScrollBoxTo(hPos + x - hLimit);
1335 repositionFlag = 1;
1336 }
1337 LOGV(vPos);
1338 LOGV(vLimit);
1339 LOGV(repositionFlag);
1340 if (repositionFlag) reposition();
1341 if (cursorLineHighlight && cursorLine != oldCursor) {
1342 repaintLine(oldCursor);
1343 repaintLine(cursorLine);
1344 }
1345 setCursorPos(pixelCursor);
1346 //showCursor();
1347 return *this;
1348 }
1349
1350 AgView &AgView::scrollTo(cint loc) {
1351 //LOGSECTION("AgView::scrollTo", Log::on);
1352 LOGSECTION_ON("AgView::scrollTo");
1353 //LOGSTACK;
1354 //hideCursor();
1355 if (loc.y < 0) {
1356 loc.y = 0;
1357 }
1358 if (loc.y >=nLines()) {
1359 loc.y = nLines() - 1;
1360 }
1361 LOGV(cursorLocation);
1362 LOGV(loc);
1363 cint pixel;
1364 pixel.x = xPosition(loc.x, getLine(loc.y));
1365 pixel.y = lineHeight()*loc.y;
1366 int repositionFlag = 0;
1367 int vPos = verticalScrollBar.scrollBoxPosition();
1368 int vLimit = vPos + verticalScrollBar.visibleCount() - 1;
1369 int hPos = horizontalScrollBar.scrollBoxPosition();
1370 int hLimit = hPos + horizontalScrollBar.visibleCount() - 4;
1371 if (loc.y < vPos) {
1372 verticalScrollBar.moveScrollBoxTo(loc.y);
1373 repositionFlag = 1;
1374 }
1375 if (loc.y > vLimit) {
1376 verticalScrollBar.moveScrollBoxTo(vPos + loc.y - vLimit);
1377 repositionFlag = 1;
1378 }
1379 if (pixel.x < hPos) {
1380 int x;
1381 int cursorX = loc.x - 5;
1382 if (cursorX <= 0) {
1383 x = 0;
1384 }
1385 else {
1386 x = xPosition(cursorX, getLine(loc.y));
1387 }
1388 horizontalScrollBar.moveScrollBoxTo(x);
1389 repositionFlag = 1;
1390 }
1391 if (pixel.x > hLimit) {
1392 int x = xPosition(loc.x+5, getLine(loc.y));
1393 horizontalScrollBar.moveScrollBoxTo(hPos + x - hLimit);
1394 repositionFlag = 1;
1395 }
1396 LOGV(vPos);
1397 LOGV(vLimit);
1398 LOGV(repositionFlag);
1399 if (repositionFlag) {
1400 reposition();
1401 }
1402 return *this;
1403 }
1404
1405
1406
1407 Boolean AgView::virtualKeyPress(IKeyboardEvent &event) {
1408 //LOGSECTION("AgView::Virtual key press", Log::off);
1409 LOGSECTION_OFF("AgView::Virtual key press");
1410 switch (event.virtualKey()) {
1411 case IKeyboardEvent::up: {
1412 if (!cursorLineHighlight && !cursorEnabled) {
1413 int line = verticalScrollBar.scrollBoxPosition() - 1;
1414 verticalScrollBar.moveScrollBoxTo(line);
1415 line = verticalScrollBar.scrollBoxPosition();
1416 updateCursor(line);
1417 return true;
1418 }
1419 int line = cursorLine;
1420 if (cursorLine <= 0) {
1421 messageBeep();
1422 return true;
1423 }
1424 if (cursorEnabled) {
1425 hideCursor();
1426 }
1427 cursorLine--;
1428 LOGV(cursorLine) LCV(verticalScrollBar.scrollBoxPosition());
1429 if (cursorLine < verticalScrollBar.scrollBoxPosition()) {
1430 if (cursorLineHighlight) {
1431 repaintLine(line);
1432 }
1433 verticalScrollBar.moveScrollBoxTo(cursorLine);
1434 reposition();
1435 }
1436 else if (cursorLineHighlight) {
1437 repaintLine(line);
1438 repaintLine(cursorLine);
1439 }
1440 cursorLocation.y = cursorLine;
1441 pixelCursor.x = xPosition(cursorLocation.x, getLine(cursorLine));
1442 pixelCursor.y = lineHeight()*cursorLine;
1443 if (cursorEnabled) {
1444 setCursorPos(pixelCursor).showCursor();
1445 }
1446 return true;
1447 }
1448 case IKeyboardEvent::down: {
1449 LOGSECTION("Cursor down one line");
1450 if (!cursorLineHighlight && !cursorEnabled) {
1451 int line = verticalScrollBar.scrollBoxPosition() + 1;
1452 verticalScrollBar.moveScrollBoxTo(line);
1453 line = verticalScrollBar.scrollBoxPosition();
1454 updateCursor(line);
1455 return true;
1456 }
1457
1458 int line = cursorLine;
1459 if (cursorLine >= nLines() - 1) {
1460 messageBeep();
1461 return true;
1462 }
1463 if (cursorEnabled) {
1464 hideCursor();
1465 }
1466 cursorLine++;
1467 LOGV(cursorLine);
1468 int bottomLine =
1469 verticalScrollBar.scrollBoxPosition()
1470 + verticalScrollBar.visibleCount()
1471 - 1;
1472 LOGV(line);
1473 LOGV(cursorLine);
1474 LOGV(bottomLine);
1475 if (cursorLine > bottomLine) {
1476 if (cursorLineHighlight) {
1477 repaintLine(line);
1478 }
1479 int newLine = cursorLine - verticalScrollBar.visibleCount() + 1;
1480 verticalScrollBar.moveScrollBoxTo(newLine);
1481 reposition();
1482 }
1483 else if (cursorLineHighlight) {
1484 repaintLine(line);
1485 repaintLine(cursorLine);
1486 }
1487 cursorLocation.y = cursorLine;
1488 pixelCursor.x = xPosition(cursorLocation.x, getLine(cursorLine));
1489 pixelCursor.y = lineHeight()*cursorLine;
1490 if (cursorEnabled) {
1491 setCursorPos(pixelCursor).showCursor();
1492 }
1493 return true;
1494 }
1495 case IKeyboardEvent::pageUp: {
1496 LOGSECTION("AgView::pageUp");
1497 if (event.isCtrlDown()) {
1498 if (cursorLine == 0) {
1499 messageBeep();
1500 return true;
1501 }
1502 verticalScrollBar.moveScrollBoxTo(0);
1503 int oldCursor = cursorLine;
1504 cursorLine = 0;
1505 if (cursorLineHighlight) {
1506 repaintLine(oldCursor);
1507 repaintLine(cursorLine);
1508 }
1509 reposition();
1510 cursorLocation.y = pixelCursor.y = 0;
1511 if (cursorEnabled) {
1512 setCursorPos(pixelCursor).showCursor();
1513 }
1514 return true;
1515 }
1516 if (!cursorLineHighlight && !cursorEnabled) {
1517 int line = verticalScrollBar.scrollBoxPosition();
1518 line -= verticalScrollBar.visibleCount();
1519 verticalScrollBar.moveScrollBoxTo(line);
1520 line = verticalScrollBar.scrollBoxPosition();
1521 updateCursor(line);
1522 return true;
1523 }
1524 int line = cursorLine;
1525 if (cursorLine <= 0) {
1526 return true;
1527 }
1528 if (cursorEnabled) {
1529 hideCursor();
1530 }
1531 cursorLine -= verticalScrollBar.visibleCount();
1532 if (cursorLine < 0) {
1533 cursorLine = 0;
1534 }
1535 if (cursorLine < verticalScrollBar.scrollBoxPosition()) {
1536 verticalScrollBar.moveScrollBoxTo(cursorLine);
1537 reposition();
1538 }
1539 else if (cursorLineHighlight) {
1540 repaintLine(line);
1541 }
1542 cursorLocation.y = cursorLine;
1543 pixelCursor.y = lineHeight()*cursorLine;
1544 pixelCursor.x = xPosition(cursorLocation.x, getLine(cursorLine));
1545 if (cursorEnabled) {
1546 setCursorPos(pixelCursor).showCursor();
1547 }
1548 return true;
1549 }
1550 case IKeyboardEvent::pageDown: {
1551 LOGSECTION("AgView::pageDown");
1552 if (event.isCtrlDown()) {
1553 if (cursorLine >= nLines() - 1) {
1554 messageBeep();
1555 return true;
1556 }
1557 //cursorLine = verticalScrollBar.scrollableRange().upperBound();
1558 cursorLine = nLines() - 1;
1559 LOGV(cursorLine);
1560 verticalScrollBar.moveScrollBoxTo(cursorLine);
1561 updateCursor(cursorLine);
1562 cursorLocation.y = cursorLine;
1563 pixelCursor.y = cursorLine*lineHeight();
1564 return true;
1565 }
1566 if (!cursorLineHighlight && !cursorEnabled) {
1567 int line = verticalScrollBar.scrollBoxPosition();
1568 line += verticalScrollBar.visibleCount();
1569 verticalScrollBar.moveScrollBoxTo(line);
1570 line = verticalScrollBar.scrollBoxPosition();
1571 updateCursor(line);
1572 }
1573 int lastLine = nLines() - 1;
1574 if (cursorLine >= lastLine) {
1575 return true;
1576 }
1577 if (cursorEnabled) {
1578 hideCursor();
1579 }
1580 int line = cursorLine;
1581 cursorLine += verticalScrollBar.visibleCount();
1582 pixelCursor.y = lineHeight()*cursorLine;
1583 if (cursorLine > lastLine) {
1584 cursorLine = lastLine;
1585 }
1586 if (cursorLine > verticalScrollBar.scrollBoxPosition()) {
1587 int newLine = cursorLine - verticalScrollBar.visibleCount() + 1;
1588 verticalScrollBar.moveScrollBoxTo(newLine);
1589 reposition();
1590 }
1591 else if (cursorLineHighlight) {
1592 repaintLine(line);
1593 }
1594 cursorLocation.y = cursorLine;
1595 pixelCursor.y = lineHeight()*cursorLine;
1596 pixelCursor.x = xPosition(cursorLocation.x, getLine(cursorLine));
1597 if (cursorEnabled) {
1598 setCursorPos(pixelCursor).showCursor();
1599 }
1600 return true;
1601 }
1602 case IKeyboardEvent::left: {
1603 if (cursorEnabled) {
1604 hideCursor();
1605 if (cursorLocation.x > 0) {
1606 cursorLocation.x--;
1607 }
1608 pixelCursor.x = xPosition(cursorLocation.x, getLine(cursorLine));
1609 if (pixelCursor.x < horizontalScrollBar.scrollBoxPosition()) {
1610 int hPos = pixelCursor.x;
1611 if (cursorLocation.x == 0) {
1612 hPos = 0;
1613 }
1614 horizontalScrollBar.moveScrollBoxTo(hPos);
1615 reposition();
1616 }
1617 setCursorPos(pixelCursor);
1618 showCursor();
1619 return true;
1620 }
1621 pixelCursor.x = horizontalScrollBar.scrollBoxPosition();
1622 pixelCursor.x -= avgCharWidth();
1623 if (pixelCursor.x < 0) {
1624 pixelCursor.x = 0;
1625 }
1626 horizontalScrollBar.moveScrollBoxTo(pixelCursor.x);
1627 reposition();
1628 updateCursor();
1629 return true;
1630 }
1631 case IKeyboardEvent::right: {
1632 LOGS("cursor right");
1633 if (cursorEnabled) {
1634 hideCursor();
1635 LOGS("cursor hidden");
1636 AgString line = getLine(cursorLine);
1637 if (cursorLocation.x < line.size()) {
1638 cursorLocation.x++;
1639 }
1640 pixelCursor.x = xPosition(cursorLocation.x, line);
1641 int hPos = horizontalScrollBar.scrollBoxPosition();
1642 int rightEdge = hPos + horizontalScrollBar.visibleCount() - 4;
1643 if (pixelCursor.x > rightEdge) {
1644 hPos += pixelCursor.x - rightEdge;
1645 horizontalScrollBar.moveScrollBoxTo(hPos);
1646 reposition();
1647 }
1648 setCursorPos(pixelCursor);
1649 LOGS("cursor moved");
1650 showCursor();
1651 LOGS("cursor restored");
1652 return true;
1653 }
1654 pixelCursor.x = horizontalScrollBar.scrollBoxPosition();
1655 pixelCursor.x += avgCharWidth();
1656 int netWidth = tableWidth - horizontalScrollBar.visibleCount();
1657 if (pixelCursor.x > netWidth) {
1658 pixelCursor.x = netWidth;
1659 }
1660 horizontalScrollBar.moveScrollBoxTo(pixelCursor.x);
1661 reposition();
1662 cursorLocation.x = pixelCursor.x/avgCharWidth();
1663 updateCursor();
1664 return true;
1665 }
1666 case IKeyboardEvent::home: {
1667 if (event.isCtrlDown()) {
1668 if (cursorLine == 0) {
1669 messageBeep();
1670 return true;
1671 }
1672 verticalScrollBar.moveScrollBoxTo(0);
1673 int oldCursor = cursorLine;
1674 cursorLine = 0;
1675 if (cursorLineHighlight) {
1676 repaintLine(oldCursor);
1677 repaintLine(cursorLine);
1678 }
1679 reposition();
1680 cursorLocation.y = pixelCursor.y = 0;
1681 if (cursorEnabled) {
1682 setCursorPos(pixelCursor).showCursor();
1683 }
1684 return true;
1685 }
1686 pixelCursor.x = avgCharWidth();
1687 cursorLocation.x = 0;
1688 horizontalScrollBar.moveScrollBoxTo(0);
1689 reposition();
1690 updateCursor();
1691 return true;
1692 }
1693 case IKeyboardEvent::end: {
1694 if (event.isCtrlDown()) {
1695 if (cursorLine >= nLines() - 1) {
1696 messageBeep();
1697 return true;
1698 }
1699 //cursorLine = verticalScrollBar.scrollableRange().upperBound();
1700 cursorLine = nLines() - 1;
1701 LOGV(cursorLine);
1702 verticalScrollBar.moveScrollBoxTo(cursorLine);
1703 updateCursor(cursorLine);
1704 cursorLocation.y = cursorLine;
1705 pixelCursor.y = cursorLine*lineHeight();
1706 return true;
1707 }
1708 if (cursorEnabled) {
1709 LOGSECTION("AgView::end");
1710 hideCursor();
1711 AgString line = getLine(cursorLocation.y);
1712 cursorLocation.x = line.size();
1713 LOGV(cursorLocation);
1714 LOGV(line.size());
1715 pixelCursor.x = xPosition(cursorLocation.x, line);
1716 LOGV(charPosition(pixelCursor.x, line));
1717 int hPos = horizontalScrollBar.scrollBoxPosition();
1718 int rightEdge = hPos + horizontalScrollBar.visibleCount() - 4;
1719 if (pixelCursor.x > rightEdge) {
1720 hPos += pixelCursor.x - rightEdge;
1721 horizontalScrollBar.moveScrollBoxTo(hPos);
1722 reposition();
1723 }
1724 setCursorPos(pixelCursor);
1725 LOGS("cursor moved");
1726 showCursor();
1727 return true;
1728 }
1729 pixelCursor.x = tableWidth - horizontalScrollBar.visibleCount();
1730 horizontalScrollBar.moveScrollBoxTo(pixelCursor.x);
1731 reposition();
1732 updateCursor();
1733 return true;
1734 }
1735 }
1736 return false;
1737 }
1738
1739 Boolean AgView::mouseClicked(IMouseClickEvent &event) {
1740 //LOGSECTION("AgView::mouseClickEvent", Log::off);
1741 LOGSECTION_OFF("AgView::mouseClickEvent");
1742 LOGV(event.mouseButton());
1743 LOGV(event.mouseAction());
1744
1745 if (event.controlWindow() == &columnHeadTitle
1746 || event.controlWindow() == &verticalScrollBar
1747 || event.controlWindow() == &horizontalScrollBar) {
1748 if (event.mouseAction() == IMouseClickEvent::down) {
1749 dataArea.setFocus();
1750 }
1751 return false;
1752 }
1753
1754 if (ControlPanel::helpCursorSet) {
1755 if (event.mouseAction() == IMouseClickEvent::down) {
1756 ControlPanel::helpCursorSet = 0;
1757 ControlPanel::resetCursor();
1758 }
1759 }
1760
1761 int line = event.mousePosition().y()/lineHeight();
1762 LOGV(line) LCV(verticalScrollBar.scrollBoxPosition());
1763 line += verticalScrollBar.scrollBoxPosition();
1764 LOGV(line);
1765 //if (line >= nLines()) line = nLines() - 1;
1766
1767 if (event.mouseButton() == IMouseClickEvent::button2) {
1768 if (event.mouseAction() == IMouseClickEvent::down) {
1769 rightButtonDown = true;
1770 }
1771 else if (event.mouseAction() == IMouseClickEvent::up) {
1772 rightButtonDown = false;
1773 }
1774 return false;
1775 /*
1776 else if (event.mouseAction() == IMouseClickEvent::click) {
1777 if (line == cursorLine) {
1778 return true;
1779 }
1780 if (cursorLineHighlight) {
1781 int oldLine = cursorLine;
1782 cursorLine = line;
1783 LOGV(oldLine) LCV(cursorLine);
1784 repaintLine(oldLine);
1785 repaintLine(cursorLine);
1786 }
1787 return true;
1788 }
1789 */
1790 }
1791 if (event.mouseButton() != IMouseClickEvent::button1) {
1792 return false;
1793 }
1794 if (line >= nLines() && !mouseDown) {
1795 if (!dataArea.hasFocus()) {
1796 dataArea.setFocus();
1797 }
1798 return false;
1799 }
1800 switch (event.mouseAction()) {
1801 case IMouseClickEvent::down: {
1802 if (event.windowUnderPointer() != dataArea.handle()) {
1803 return false;
1804 }
1805 if (!cursorLineHighlight) {
1806 return false;
1807 }
1808 dataArea.capturePointer(true);
1809 mouseDownCursorLine = cursorLine;
1810 //int line = event.mousePosition().y()/lineHeight();
1811 int offset = horizontalScrollBar.scrollBoxPosition();
1812 int whereX = event.mousePosition().x() + offset;
1813 LOGV(cursorLine) LCV(offset) LCV(whereX);
1814 AgString text = getLine(line);
1815 cint loc(charPosition(whereX, text), line);
1816 LOGV(loc);
1817 cursorLocation = loc;
1818 if (line != cursorLine) {
1819 cursorLine = line;
1820 if (cursorLineHighlight) {
1821 LOGV(mouseDownCursorLine) LCV(cursorLine);
1822 repaintLine(mouseDownCursorLine);
1823 repaintLine(cursorLine);
1824 }
1825 onSelect();
1826 }
1827 mouseDown = true;
1828 return false;
1829 }
1830 case IMouseClickEvent::up: {
1831 mouseDown = false;
1832 dataArea.capturePointer(false);
1833 return false;
1834 }
1835 case IMouseClickEvent::click: {
1836 if (event.windowUnderPointer() != dataArea.handle()) {
1837 return false;
1838 }
1839 dataArea.setFocus();
1840 //if (line == mouseDownCursorLine) {
1841 // onSelect();
1842 //}
1843 return false;
1844 }
1845 case IMouseClickEvent::doubleClick: {
1846 dataArea.setFocus();
1847 //onSelect();
1848 onEnter();
1849 return false;
1850 }
1851 }
1852 return false;
1853 }
1854
1855 Boolean AgView::mouseMoved(IMouseEvent &event) {
1856 if (!mouseDown) {
1857 return false;
1858 }
1859 if (!cursorLineHighlight) {
1860 return false;
1861 }
1862 if (mouseTimer.isStarted()) {
1863 mouseTimer.stop();
1864 }
1865 int mouseY = event.mousePosition().y();
1866 if (mouseY < 0) {
1867 mouseY -= lineHeight();
1868 }
1869 int mouseLine = mouseY/lineHeight();
1870 int topLine = verticalScrollBar.scrollBoxPosition();
1871 //LOGSECTION("Mouse moved", Log::off);
1872 LOGSECTION_OFF("Mouse moved");
1873 LOGV(topLine) LCV(mouseLine);
1874 dragMouse(topLine, mouseLine);
1875 topLine = verticalScrollBar.scrollBoxPosition();
1876 int belowLine = topLine + verticalScrollBar.visibleCount();
1877 if (mouseLine >= topLine && mouseLine < belowLine) {
1878 return true;
1879 }
1880 IReference<ITimerFn> timerFn(new MouseDragTimer(this, topLine, mouseLine));
1881 mouseTimer.start(timerFn, 50);
1882 LOGS("timer started");
1883 return false;
1884 }
1885
1886 void AgView::dragMouse(int topLine, int mouseLine) {
1887 //LOGSECTION("Agview::dragMouse", Log::off);
1888 LOGSECTION_OFF("Agview::dragMouse");
1889 int bottomLine = topLine + verticalScrollBar.visibleCount() - 1;
1890 int line = topLine + mouseLine;
1891 if (line < 0) {
1892 line = 0;
1893 }
1894 if (line >= nLines()) {
1895 line = nLines() - 1;
1896 }
1897 if (line == cursorLine) {
1898 return;
1899 }
1900 int oldLine = cursorLine;
1901 cursorLocation.y = cursorLine = line;
1902 pixelCursor.y = lineHeight()*cursorLine;
1903 if (cursorLine < topLine) {
1904 if (cursorLineHighlight) repaintLine(oldLine);
1905 verticalScrollBar.moveScrollBoxTo(cursorLine);
1906 reposition();
1907 return;
1908 }
1909 if (cursorLine > bottomLine) {
1910 if (cursorLineHighlight) {
1911 repaintLine(oldLine);
1912 }
1913 verticalScrollBar.moveScrollBoxTo(topLine + cursorLine - bottomLine);
1914 reposition();
1915 return;
1916 }
1917
1918 if (cursorLineHighlight) {
1919 repaintLine(oldLine);
1920 repaintLine(cursorLine);
1921 }
1922 return;
1923 }
1924
1925 void AgView::mouseDragTimerInterrupt(int &topLine, int mouseLine) {
1926 //LOGSECTION("AgView::mouseDragTimer", Log::off);
1927 LOGSECTION_OFF("AgView::mouseDragTimer");
1928 LOGV(topLine) LCV(mouseLine) LCV(cursorLine);
1929 if (!mouseDown || topLine + mouseLine == cursorLine) {
1930 mouseTimer.stop();
1931 LOGV(mouseDown);
1932 LOGV(topLine) LCV(verticalScrollBar.scrollBoxPosition());
1933 return;
1934 }
1935 if (topLine + mouseLine != cursorLine) {
1936 dragMouse(topLine, mouseLine);
1937 }
1938 topLine = verticalScrollBar.scrollBoxPosition();
1939 }
1940
1941 AgView::MouseDragTimer::MouseDragTimer(AgView * window_, int topLine_,
1942 int mouseLine_)
1943 : window(window_)
1944 , topLine(topLine_)
1945 , mouseLine(mouseLine_)
1946 {}
1947
1948 void AgView::MouseDragTimer::timerExpired(unsigned long) {
1949 //LOGSECTION("AgView::MouseDragTimer::timerExpired", Log::off);
1950 LOGSECTION_OFF("AgView::MouseDragTimer::timerExpired");
1951 window->mouseDragTimerInterrupt(topLine, mouseLine);
1952 }