Mercurial > ~dholland > hg > ag > index.cgi
diff anagram/vaclgui/dview.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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/anagram/vaclgui/dview.cpp Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,1980 @@ +/* + * AnaGram, A System for Syntax Directed Programming + * Copyright 1997-2002 Parsifal Software. All Rights Reserved. + * See the file COPYING for license and usage terms. + * + * dview.cpp + */ + +#include <icoordsy.hpp> +#include <windows.h> +#include "port.h" + +#include "agcstack.h" +#include "arrays.h" +#include "ctrlpanel.hpp" +#include "dview.hpp" +#include "dvplug.hpp" +#include "helpview.hpp" +#include "minmax.h" +#include "myalloc.h" +#include "vaclgui.hpp" + +//#define INCLUDE_LOGGING +#include "log.h" + + +const int AgDataView::defaultWindowHeight = 12; + +void logFont(IFont activeFont, char *p) { + LOGV(activeFont.name()) LV(activeFont.pointSize()); + LOGV(activeFont.isBold()) LCV(activeFont.isItalic()); + LOGV(activeFont.textWidth(p)) LCV(p); +} + +void logFont(IFont activeFont) { + LOGV(activeFont.name()) LV(activeFont.pointSize()); + LOGV(activeFont.isBold()) LCV(activeFont.isItalic()); +} + +AgDataView::AgDataView(IWindow *ownerWindow_, WindowData *windowData_) + : ICanvas(nextChildId(), ownerWindow_, ownerWindow_) + , ownerWindow(ownerWindow_) + , windowData(windowData_) + , horizontalScrollBar(nextChildId(), this, this, IRectangle(), + IScrollBar::horizontal | IWindow::visible) + , verticalScrollBar(nextChildId(), this, this, IRectangle(), + IScrollBar::vertical | IWindow::visible) + , dataArea(this) + , vsbShowing(false) + , hsbShowing(false) + , columnHeadTitle(nextChildId(), this) + , columnHeadsPresent(0) + , cursorLine(0) + , mouseDown(0) + , tabArray(0) + , popUpMenu(this, nextChildId()) + , popUpInitialized(0) + , tableWidth(0) + , color(&ColorSpec::data) + , cursorColor(&ColorSpec::inactiveCursor) + , prevHorizontal(0) + , prevVertical(0) + //, rightButtonDown(0) + , rightButtonState(buttonIdle) + , layoutActive(0) + , dataColorChange(this, onColorChange) + , fontChange(this, onFontChange) + , enterAction(actionObject(messageBeep)) + , verticalLineCount(0) + , layoutComplete(0) + , helpTopic(0) +{ + windowId = id(); + LOGSECTION("AgDataView::AgDataView"); + LOGV(windowId); + LOGV((int) this); + setFont(FontSpec::dataTable); + dataArea.setFont(FontSpec::dataTable); + LOGV(dataArea.font().name()); + columnHeadTitle.setFont(FontSpec::columnHead); + dataColorChange.attach(&ColorSpec::data); + dataColorChange.attach(&ColorSpec::inactiveCursor); + dataColorChange.attach(&ColorSpec::activeCursor); + fontChange.attach(&FontSpec::dataTable); + fontChange.attach(&FontSpec::columnHead); + fontChange.attach(&FontSpec::markedToken); + + horizontalScrollBar.setScrollableRange(IRange(0,100)); + horizontalScrollBar.moveScrollBoxTo(0); + verticalScrollBar.setScrollableRange(IRange(0,100)); + verticalScrollBar.moveScrollBoxTo(0); + cursorLine = 0; + + IWindow *f; + for (f = ownerWindow; !f->isFrameWindow(); f=f->parent()); + frameWindow = (AgFrame *) f; + frameWindow->helpCursorSupported = 1; + LOGV(frameWindow->windowTitle.text()); + + ok_ptr(windowData); + AgString title = windowData->columnHeadTitle(); + LOGV(title.pointer()); + if (title.exists()) { + columnHeadTitle.setTitles(windowData->nColumns(), title); + columnHeadTitle.setMargin(avgCharWidth()); + columnHeadTitle.enableFillBackground(); + columnHeadTitle.show(); + columnHeadsPresent = 1; + } + + + int nCols = windowData->nColumns(); + tabArray = new int[nCols + 1]; + memset(tabArray, 0, (nCols+1)*sizeof(int)); + columnHeadTitle.setTabs(tabArray); + LOGV(tabArray[0]); + tableHeight = lineHeight()*windowData->nLines(); + LOGV(windowData->nLines()); + LOGV(tableHeight); + + LOGV(auxMenu.exists()); + + ICommandHandler ::handleEventsFor(this); + IKeyboardHandler::handleEventsFor(this); + IMouseHandler ::handleEventsFor(&dataArea); + IMouseHandler ::handleEventsFor(&columnHeadTitle); + IMouseHandler ::handleEventsFor(&verticalScrollBar); + IMouseHandler ::handleEventsFor(&horizontalScrollBar); + IPaintHandler ::handleEventsFor(&dataArea); + IResizeHandler ::handleEventsFor(this); + IScrollHandler ::handleEventsFor(this); + AgHelpHandler ::handleEventsFor(frameWindow); + AgFocusHandler ::handleEventsFor(&dataArea); + + ((AgDataViewPlug *)windowData)->connect(this); + + auxMenu = windowData->auxMenu(); + if (auxMenu.exists()) { + IMenuHandler::handleEventsFor(&dataArea); + } + LOGV(auxMenu.exists()); + LOGS("menu handler attached"); + + initPopUp(); + + show(); + windowData->synchCursor(cursorLine); +} + +void AgDataView::disconnect() { + LOGSECTION("AgDataView::disconnect"); + LOGV((int) frameWindow); +} + + +AgDataView &AgDataView::setColumnTitles(AgString title) { + LOGSECTION("AgDataView::setColumnTitles"); + LOGV((int) frameWindow); + if (title.exists()) { + LOGV(title.pointer()); + columnHeadTitle.setTitles(windowData->nColumns(), title); + columnHeadTitle.setMargin(avgCharWidth()); + columnHeadTitle.enableFillBackground(); + columnHeadsPresent = 1; + } + return *this; +} + +Boolean AgDataView::gotFocus(IEvent &) { + LOGSECTION("AgDataView::gotFocus"); + LOGV(windowId); + LOGV((int) this); + focusWindowId = windowId; + columnHeadTitle.color = &ColorSpec::activeTitle; + columnHeadTitle.refresh(); + cursorColor = &ColorSpec::activeCursor; + if (windowData == 0) { + return true; + } + repaintLine(cursorLine); + windowData->synchCursor(cursorLine); + return false; +} + +Boolean AgDataView::lostFocus(IEvent &) { + LOGSECTION("AgDataView::lostFocus"); + LOGV(windowId); + LOGV((int) this) LCV((int) windowData); + columnHeadTitle.color = &ColorSpec::inactiveTitle; + columnHeadTitle.refresh(); + cursorColor = &ColorSpec::inactiveCursor; + if (windowData == 0) { + return true; + } + ok_ptr(windowData); + repaintLine(cursorLine); + return false; +} + + +AgDataView &AgDataView::init(WindowData *windowData_) { + LOGSECTION("AgDataView::init"); + LOGV(windowId); + LOGV((int) this); + horizontalScrollBar.setScrollableRange(IRange(0,100)); + horizontalScrollBar.moveScrollBoxTo(0); + verticalScrollBar.setScrollableRange(IRange(0,100)); + verticalScrollBar.moveScrollBoxTo(0); + cursorLine = 0; + + ok_ptr(windowData_); + windowData = windowData_; + LOGV((int) frameWindow); + LOGV((int) windowData); + LOGV(windowId); + AgString title = windowData->columnHeadTitle(); + if (title.exists()) { + LOGV(title.pointer()); + columnHeadTitle.setTitles(windowData->nColumns(), title); + columnHeadTitle.setMargin(avgCharWidth()); + columnHeadTitle.enableFillBackground(); + columnHeadTitle.show(); + columnHeadsPresent = 1; + } + + + if (tabArray == NULL) { + int nCols = windowData->nColumns(); + tabArray = new int[nCols + 1]; + memset(tabArray, 0, (nCols+1)*sizeof(int)); + } + columnHeadTitle.setTabs(tabArray); + LOGV(tabArray[0]); + tableHeight = lineHeight()*windowData->nLines(); + LOGV(windowData->nLines()); + LOGV(tableHeight); + setLayoutDistorted(IWindow::layoutChanged,0); + + ((AgDataViewPlug *)windowData)->connect(this); + auxMenu = windowData->auxMenu(); + if (auxMenu.exists()) { + IMenuHandler::handleEventsFor(&dataArea); + LOGS("menu handler attached"); + initPopUp(); + } + + windowData->synchCursor(cursorLine); + return *this; +} + + +AgDataView &AgDataView::reset() { + LOGSECTION("AgDataView::reset"); + LOGV(windowId); + LOGV((int) this); + ok_ptr(windowData); + int nLines = windowData->nLines(); + LOGV(nLines); + int newTableHeight = lineHeight()*nLines; + LOGV(windowData->nLines()); + LOGV(tableHeight); + if (cursorLine >= nLines) { + cursorLine = nLines-1; + } + windowData->synchCursor(cursorLine); + //if (tableHeight != newTableHeight) { + tableHeight = newTableHeight; + doLayout(); + refresh(); + //} + LOGV(horizontalScrollBar.scrollBoxPosition()); + LOGV(verticalScrollBar.scrollBoxPosition()); + return *this; +} + +AgDataView::AgDataView(IWindow *ownerWindow_) + : ICanvas(nextChildId(), ownerWindow_, ownerWindow_) + , ownerWindow(ownerWindow_) + , windowData(NULL) + , horizontalScrollBar(nextChildId(), this, this, IRectangle(), + IScrollBar::horizontal | IWindow::visible) + , verticalScrollBar(nextChildId(), this, this, IRectangle(), + IScrollBar::vertical | IWindow::visible) + , dataArea(this) + , vsbShowing(false) + , hsbShowing(false) + , columnHeadTitle(nextChildId(), this) + , columnHeadsPresent(0) + , cursorLine(0) + , mouseDown(0) + , tabArray(0) + , popUpMenu(this, nextChildId()) + , popUpInitialized(0) + , tableWidth(0) + , color(&ColorSpec::data) + , cursorColor(&ColorSpec::inactiveCursor) + , prevHorizontal(0) + , prevVertical(0) + //, rightButtonDown(0) + , rightButtonState(buttonIdle) + , layoutActive(0) + , dataColorChange(this, onColorChange) + , fontChange(this, onFontChange) + , enterAction(actionObject(messageBeep)) + , verticalLineCount(0) + , layoutComplete(0) + , helpTopic(0) +{ + windowId = id(); + LOGSECTION("AgDataView::AgDataView"); + LOGV(windowId); + LOGV((int) this); + setFont(FontSpec::dataTable); + dataArea.setFont(FontSpec::dataTable); + LOGV(dataArea.font().name()); + columnHeadTitle.setFont(FontSpec::columnHead); + + dataColorChange.attach(&ColorSpec::data); + dataColorChange.attach(&ColorSpec::inactiveCursor); + dataColorChange.attach(&ColorSpec::activeCursor); + fontChange.attach(&FontSpec::dataTable); + fontChange.attach(&FontSpec::columnHead); + fontChange.attach(&FontSpec::markedToken); + IWindow *f; + for (f = ownerWindow; !f->isFrameWindow(); f=f->parent()); + frameWindow = (AgFrame *) f; + frameWindow->helpCursorSupported = 1; + LOGV(frameWindow->windowTitle.text()); + LOGV((int) frameWindow); + LOGV((int) this); + + LOGV(id()); + + ICommandHandler ::handleEventsFor(this); + IKeyboardHandler::handleEventsFor(this); + if (auxMenu.exists()) { + IMenuHandler::handleEventsFor(&dataArea); + } + LOGV(auxMenu.exists()); + LOGS("menu handler attached"); + IMouseHandler ::handleEventsFor(&dataArea); + IMouseHandler ::handleEventsFor(&columnHeadTitle); + IMouseHandler ::handleEventsFor(&verticalScrollBar); + IMouseHandler ::handleEventsFor(&horizontalScrollBar); + IPaintHandler ::handleEventsFor(&dataArea); + IResizeHandler ::handleEventsFor(this); + IScrollHandler ::handleEventsFor(this); + AgHelpHandler ::handleEventsFor(frameWindow); + AgFocusHandler ::handleEventsFor(&dataArea); + show(); +} + +AgDataView::~AgDataView() { + LOGSECTION("AgDataView::~AgDataView"); + LOGV(windowId) LCV((int) this) LCV((int) windowData); + ok_ptr(windowData); + delete [] tabArray; + //if (windowData == 0) return; + ICommandHandler ::stopHandlingEventsFor(this); + IKeyboardHandler::stopHandlingEventsFor(this); + if (auxMenu.exists()) { + IMenuHandler::stopHandlingEventsFor(&dataArea); + } + IMouseHandler ::stopHandlingEventsFor(&dataArea); + IMouseHandler ::stopHandlingEventsFor(&columnHeadTitle); + IMouseHandler ::stopHandlingEventsFor(&verticalScrollBar); + IMouseHandler ::stopHandlingEventsFor(&horizontalScrollBar); + IPaintHandler ::stopHandlingEventsFor(&dataArea); + IResizeHandler ::stopHandlingEventsFor(this); + IScrollHandler ::stopHandlingEventsFor(this); + AgHelpHandler ::stopHandlingEventsFor(frameWindow); + AgFocusHandler ::stopHandlingEventsFor(&dataArea); + ok_ptr(windowData); + delete windowData; +} + +void AgDataView::onFontChange() { + LOGSECTION("AgDataView::onFontChange"); + disableUpdate(); + LOGS("dataTableFont"); + logFont(FontSpec::dataTable); + setFont(FontSpec::dataTable); + dataArea.setFont(FontSpec::dataTable); + columnHeadTitle.setFont(FontSpec::columnHead); + LOGS("font()"); + logFont(font()); + logFont(dataArea.font()); + tableWidth = 0; + doLayout(); + enableUpdate(); + show(); +} + +int AgDataView::findMaxWidth() { + LOGSECTION("AgDataView::findMaxWidth"); + LOGV(windowId); + LOGV((int) this); + LOGV((int) frameWindow); + + int maxWidth = 0; + ok_ptr(windowData); + int nLines = windowData->nLines(); + int nCols = windowData->nColumns(); + char *columnTitles = columnHeadTitle.title.pointer(); + int i; + + LOGV(nLines) LCV(nCols); + if (tabArray == NULL) { + tabArray = new int[nCols + 1]; + } + memset(tabArray, 0, (nCols+1)*sizeof(int)); + IFont windowFont = font(); + LOGV(windowFont.name()); + LOGV(windowFont.pointSize()); + + int lastColumnTitleWidth = 0; + //int *columnWidth = new int[nCols]; + //int *columnWidth = local_array(nCols, int); + LocalArray<int> columnWidth(nCols); + memset(columnWidth, 0, nCols*sizeof(int)); + LOGV(columnTitles); + if (columnTitles) { + //char *titles = new char[1+strlen(columnTitles)]; + //char *titles = local_array(1+strlen(columnTitles), char); + LocalArray<char> titles(1+strlen(columnTitles)); + strcpy(titles, columnTitles); + FindTabs tabs(titles); + char *p = tabs.getField(); + i = 0; + while(i < nCols && p) { + int width = columnHeadTitle.font().textWidth(p); + columnWidth[i] = width; + LOGV(width) LCV(p); + lastColumnTitleWidth = width; + if (++i >= nCols) { + break; + } + p = tabs.getField(); + } + while (i < nCols) { + tabArray[i++] = 0; + } + //delete [] titles; + } + else { + for (i = 0; i < nCols; i++) { + tabArray[i] = 0; + } + } + LOGV(tabArray[0]); + LOGV(columnWidth[0]); + //int *width = new int[nCols]; + //int *width = local_array(nCols, int); + LocalArray<int> width(nCols); + int partialWidth = 0; + + while (nLines--) { + //LOGSECTION("AgDataView::findMaxWidth line detail", Log::off); + LOGSECTION_OFF("AgDataView::findMaxWidth line detail"); + AgString line = windowData->getLine(nLines); + LOGV(line.pointer()); + FindTabs tabs(line.pointer()); + char *p = tabs.getField(); + LOGV(nLines); + LOGV(p); + i = 0; + while(i < nCols && p) { + width[i] = windowFont.textWidth(p); + LOGV(i) LCV(width[i]) LCV(p); + if (width[i] > columnWidth[i]) { + columnWidth[i] = width[i]; + } + if (++i >= nCols) { + break; + } + p = tabs.getField(); + } + LOGV(width[0]) LCV(line.pointer()); + if (i < nCols) { + int w = 0; + while (i--) { + w += width[i]; + } + if (w > partialWidth) { + partialWidth = w; + } + //continue; + } + } + + //delete [] width; + for (i = 0; i < nCols; i++) { + columnWidth[i] += 2*avgCharWidth(); + if (columnWidth[i] > tabArray[i]) { + tabArray[i] = columnWidth[i]; + } + maxWidth += tabArray[i]; + LOGV(tabArray[i]) LCV(maxWidth); + } + LOGV(tabArray[0]); + maxWidth += 2*avgCharWidth(); + if (maxWidth < partialWidth) { + maxWidth = partialWidth; + } + //delete [] columnWidth; + columnHeadWidth = maxWidth - tabArray[nCols-1] + + lastColumnTitleWidth+2*avgCharWidth(); + LOGV(columnHeadWidth); + return maxWidth; +} + +AgDataView &AgDataView::adjustMaxWidth(AgString text) { + int nCols = windowData->nColumns(); + int maxWidth = 0; + int margin = 2*avgCharWidth(); + char *line = text.pointer(); + + LOGSECTION("AgDataView::adjustMaxWidth"); + LOGV((int) frameWindow); + LOGV(line); + if (tableWidth == 0) { + tableWidth = findMaxWidth(); + } + FindTabs tabs(line); + char *p = tabs.getField(); + + LOGV(p); + + if (tabArray == NULL) { + tabArray = new int[nCols + 1]; + memset(tabArray, 0, (nCols+1)*sizeof(int)); + } + int i = 0; + while(i < nCols && p) { + int width = font().textWidth(p) + margin; + if (width > tabArray[i]) { + tabArray[i] = width; + } + LOGV(p) LCV(width); + if (++i >= nCols) { + break; + } + p = tabs.getField(); + } + for (i = 0; i < nCols; i++) { + maxWidth += tabArray[i]; + LOGV(tabArray[i]) LCV(maxWidth); + } + if (tableWidth < maxWidth) { + tableWidth = maxWidth; + } + LOGV(maxWidth); + LOGV(tabArray[0]); + return *this; +} + +AgDataView &AgDataView::layout() { + LOGSECTION("AgDataView::layout"); + LOGV(windowId); + LOGV((int) this); + LOGV((int) frameWindow); + if (layoutActive) { + return *this; + } + layoutActive++; + doLayout(); + ICanvas::setLayoutDistorted(0, IWindow::layoutChanged); + ICanvas::layout(); + layoutActive--; + return *this; +} + +AgDataView &AgDataView::setLayoutDistorted(unsigned long i, unsigned long j) { + LOGSECTION("AgDataView::setLayoutDistorted"); + LOGV((int) frameWindow); + LOGV(windowId); + LOGV((int) this); + LOGV(i) LCV(j); + LOGSTACK; + + ICanvas::setLayoutDistorted(i, j); + return *this; +} + +Boolean AgDataView::windowResize(IResizeEvent &event){ + LOGSECTION("AgDataView::windowResize"); + LOGV(windowId); + LOGV((int) this); + LOGV((int) frameWindow); + + //if (event.controlWindow() != this) { + // return false; + //} + + LOGV(id()); + + //setLayoutDistorted(IWindow::layoutChanged,0); + doLayout(); + return false; +} + +ISize AgDataView::calcMinimumSize() const { + int minWidth = 10*font().avgCharWidth(); + int minHeight = 3*lineHeight(); + if (columnHeadsPresent) { + minHeight += 2 + columnHeadTitle.minimumSize().height(); + } + return ISize(minWidth, minHeight); +} + +ISize AgDataView::suggestSize() { + LOGSECTION("AgDataView::suggestSize"); + LOGV(windowId); + LOGV((int) this); + LOGV((int) frameWindow); + + if (tableWidth == 0) { + tableWidth = findMaxWidth(); +/* + int minWidth = 20*font().avgCharWidth(); + int minHeight = 5*lineHeight(); + if (columnHeadsPresent) { + minHeight += 2 + columnHeadTitle.minimumSize().height(); + } + setMinimumSize(ISize(minWidth, minHeight)); +*/ + } + int width = tableWidth; + int height = tableHeight; + ok_ptr(windowData); + LOGV(windowData->nLines()); + LOGV(tableHeight); + LOGV(columnHeadsPresent); + LOGV(columnHeadTitle.minimumSize().height()); + if (windowData->nLines() > defaultWindowHeight) { + width += verticalScrollBar.minimumSize().width() + 1; + height = lineHeight() * defaultWindowHeight; + } + else if (windowData->nLines() < 5) { + height = lineHeight() * 5; + } + if (columnHeadsPresent) { + height += 2 + columnHeadTitle.minimumSize().height(); + } + LOGV(height); + + LOGV(width) LCV(height); + + return ISize(width, height); +} + +ColorSpec *AgDataView::getLineColor(int k) { + if (k == cursorLine) { + return cursorColor; + } + return color; +} + +char *findDelimiter(char *p, char c) { + + // XXX: are we guaranteed that '\\' never occurs immediately before + // the end of a string, or do we just zoom off into the beyond when + // that happens? + + while (*p && *p != c) { + if (*p == '\'') { + p++; + while (*p != '\'') { + if (*p++ == '\\') { + p++; + } + } + } + else if (*p == '"') { + p++; + while (*p != '"') { + if (*p++ == '\\') { + p++; + } + } + } + p++; + } + return p; +} + +Boolean AgDataView::paintWindow(IPaintEvent &event) { + if (event.controlWindow() != &dataArea) { + return false; + } + if (windowData == 0) { + return false; + } + int nLines = windowData->nLines() - 1; + int height = lineHeight(); + int leadingBias = 0; + IFont markFont(FontSpec::markedToken); + + LOGSECTION("AgDataView::paintWindow"); + LOGV(tabArray[0]); + LOGV(windowId); + LOGV((int) this); + IPresSpaceHandle presSpaceHandle = event.presSpaceHandle(); + + font().beginUsingFont(presSpaceHandle); + LOGV(font().name()) LCV(font().pointSize()); + leadingBias = font().maxAscender() - markFont.maxAscender(); + SetBkMode(presSpaceHandle, TRANSPARENT); + LOGV((int) frameWindow); + + LOGV(nLines); + IRectangle invalidRect( + ICoordinateSystem::isConversionNeeded() + ? ICoordinateSystem::convertToApplication(event.rect(),dataArea.size()) + : event.rect() + ); + + LOGV(invalidRect.asString()); + LOGV(dataArea.size().asString()); + + int baseLine = verticalScrollBar.scrollBoxPosition(); + int firstLine = baseLine + invalidRect.minY()/height; + int lastLine = baseLine + (invalidRect.maxY()+height - 1)/height - 1; + + LOGV(horizontalScrollBar.scrollBoxPosition()); + LOGV(verticalScrollBar.scrollBoxPosition()); + LOGV(baseLine); + LOGV(firstLine); + LOGV(lastLine); + + int yBias = + ICoordinateSystem::isConversionNeeded() + ? height - maxDescender() + : 0; + + int xMargin = avgCharWidth(); + + + LOGV(yBias); + + int whereX = -horizontalScrollBar.scrollBoxPosition(); + int whereY = (firstLine - baseLine)*height; //baseline location + + LOGV(baseLine); + LOGV(firstLine); + LOGV(lastLine); + LOGV(horizontalScrollBar.scrollBoxPosition()); + + int lastInvalidLine = lastLine; + if (lastLine > nLines) { + lastLine = nLines; + } + int windowHeight = dataArea.rect().size().height(); + int dataAreaWidth = dataArea.rect().size().width() - whereX; + ISize lineSize(dataAreaWidth, height); + IPoint offset(xMargin, 0); + int k; + + LOGV(firstLine); + LOGV(lastLine); + for (k = firstLine; k >= 0 && k <= lastLine; k++, whereY += height) { + LOGSECTION("AgDataView::paintWindow line loop"); + IPoint trueWhere(whereX, whereY + yBias); + IPoint where = + ICoordinateSystem::isConversionNeeded() + ? ICoordinateSystem::convertToNative(trueWhere, dataArea.size()) + : trueWhere; + IRectangle trueLineRect(0, whereY, dataAreaWidth, whereY+height); + IRectangle lineRect = + ICoordinateSystem::isConversionNeeded() + ? ICoordinateSystem::convertToNative(trueLineRect, dataArea.size()) + : trueLineRect; + ColorSpec *lineColor = getLineColor(k); + IColor bgndColor = lineColor->bg(); + IColor fgndColor = lineColor->fg(); + + LOGV(lineRect.asString()); + LOGV(where.asString()); + event.clearBackground(lineRect,bgndColor); + + AgString line = windowData->getLine(k); + char *p = line.pointer(); + LOGV((int)p); + LOGV(p); + while (*p && *p != '<') { + p++; + } + if (*p == '<') { + while (*p && *p != '>') { + p++; + } + } + int bracketFlag = *p == '>'; + + LOGV(line.pointer()); + FindTabs tabs(line.pointer()); + p = tabs.getField(); + int nCols = windowData->nColumns(); + where += offset; + int i = 0; + char *star = 0; + IPoint starWhere = where; + if (*p == '*') { + *p = ' '; + star = p; + } + while (i < nCols && p) { + LOGV(p - line.pointer()); + LOGV(p); + IPoint drawPoint(where); + int j = 0; + while (p[j] && p[j] == ' ') { + j++; + } + int flag = bracketFlag && p[j] == 'R' && p[j+7] == '<' && p[j+8] != '<'; + if (!flag) { + char *q = p; + while (*q && strncmp(q, ", <", 3) != 0) { + q++; + } + //LOGV(q); + if (*q == ',') { + q += 2; + *q = 0; + logFont(font(), p); + //LOGV(drawPoint.asString()); + event.drawText(p, drawPoint, fgndColor); + drawPoint += IPair(font().textWidth(p), 0); + //drawPoint += IPair(gcFont.textWidth(p), 0); + //LOGV(font().textWidth(p)) LCV(p); + //LOGV(drawPoint.asString()); + p = q; + *p = '<'; + } + } + else { + p[j+7] = 0; + logFont(font(), p); + //LOGV(drawPoint.asString()); + event.drawText(p, drawPoint, fgndColor); + drawPoint += IPair(font().textWidth(p), 0); + //LOGV(font().textWidth(p)) LCV(p); + //LOGV(drawPoint.asString()); + p += j+7; + *p = '<'; + } + //LOGV(flag); + //LOGV(p); + if (bracketFlag && *p == '<' && p[1] != '<') { + p += 2; + IFont markFont(FontSpec::markedToken); + char *q = p; + q = findDelimiter(q, '>'); + if (q) { + *q = 0; + } + //LOGV(p); + //LOGV(font().textWidth(p)); + //LOGV(markFont.name()) LCV(markFont.pointSize()); + //LOGV(markFont.textWidth(p)); + logFont(font(), p); + //LOGV(drawPoint.asString()); + int saveY = drawPoint.y(); + drawPoint.setY(saveY +leadingBias); + //LOGV(drawPoint.asString()); + markFont.beginUsingFont(presSpaceHandle); + logFont(font(), p); + event.drawText(p, drawPoint, fgndColor); + drawPoint.setY(saveY); + drawPoint += IPair(markFont.textWidth(p), 0); + //LOGV(font().textWidth(p)) LCV(p); + //LOGV(drawPoint.asString()); + markFont.endUsingFont(presSpaceHandle); + p = q+1; + //LOGS("emphasis complete"); + } + logFont(font(), p); + LOGV(drawPoint.asString()); + event.drawText(p,drawPoint, fgndColor); + where += IPoint(tabArray[i], 0); + LOGV(font().textWidth(p)) LCV(p); + LOGV(tabArray[i]); + LOGV(where); + if (++i >= nCols) { + break; + } + p = tabs.getField(); + } + if (star) { + event.drawText("*", starWhere, fgndColor); + } + } + if (k <= lastInvalidLine) { + IRectangle trueRemainder(0,whereY,dataAreaWidth, windowHeight); + IRectangle remainder = + ICoordinateSystem::isConversionNeeded() + ? ICoordinateSystem::convertToNative(trueRemainder, dataArea.size()) + : trueRemainder; + //LOGV(remainder.asString()); + event.clearBackground(remainder,color->bg()); + } + + font().endUsingFont(presSpaceHandle); + return true; +} + +AgDataView &AgDataView::repaintLine(int line) { + if (windowData == 0) { + return *this; + } + if (line < 0 || line >= windowData->nLines()) { + return *this; + } + int topLine = verticalScrollBar.scrollBoxPosition(); + int y = (line - topLine)*lineHeight(); + LOGSECTION("AgDataView::repaintLine"); + LOGV(windowId); + LOGV((int) this); + LOGV((int) frameWindow); + LOGV(horizontalScrollBar.scrollBoxPosition()); + LOGV(verticalScrollBar.scrollBoxPosition()); + LOGV(line); + LOGV(cursorLine); + IRectangle rect(0,y,dataArea.rect().size().width(), y + lineHeight()); + LOGV(rect.asString()); + //dataArea.refresh(rect, true); + dataArea.refresh(rect); + return *this; +} + +AgDataView &AgDataView::copyTo(IClipboard &clipboard) { + int i; + int nLines = windowData->nLines(); + AgCharStack charStack; + if (copyTitle.exists()) { + //charStack.push(copyTitle).push("\r\n\r\n"); + charStack << copyTitle << "\r\n\r\n"; + } + //charStack.push(windowData->columnHeadTitle()); + charStack << windowData->columnHeadTitle(); + charStack.push("\r\n"); + for (i = 0; i < nLines; i++) { + //charStack.push(windowData->getLine(i)); + charStack << windowData->getLine(i); + charStack.push("\r\n"); + } + clipboard.setText(charStack.popString().pointer()); + return *this; +} + +AgDataView &AgDataView::repositionWindow() { + LOGSECTION("AgDataView::repositionWindow"); + LOGV(windowId); + LOGV((int) this); + int horizontalOffset = horizontalScrollBar.scrollBoxPosition() + - prevHorizontal; + int verticalOffset = verticalScrollBar.scrollBoxPosition() + - prevVertical; + + IPoint displacement(-horizontalOffset, -lineHeight()*verticalOffset); + + LOGV(displacement.asString()); + + int oldCursor = cursorLine; + int line = verticalScrollBar.scrollBoxPosition(); + if (cursorLine < line) { + cursorLine = line; + } + else { + LOGV(windowData->nLines()); + LOGV(verticalScrollBar.scrollableRange().asString()); + LOGV(verticalScrollBar.visibleCount()); + //line += verticalScrollBar.visibleCount() - 1; + line += verticalLineCount - 1; + if (line < 0) { + line = 0; + } + if (cursorLine > line) { + cursorLine = line; + } + } + if (columnHeadsPresent) { + int pos = horizontalScrollBar.scrollBoxPosition(); + if (pos != columnHeadTitle.xPos) { + columnHeadTitle.xPos = pos; + columnHeadTitle.refresh(); + } + } + LOGV(cursorLine); + dataArea.scrollWindow(displacement); + dataArea.refresh(); + prevHorizontal = horizontalScrollBar.scrollBoxPosition(); + prevVertical = verticalScrollBar.scrollBoxPosition(); + if (cursorLine != oldCursor) { + repaintLine(oldCursor); + repaintLine(cursorLine); + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + } + + return *this; +} + +Boolean AgDataView::findNext(AgString s) { + LOGSECTION("AgDataView::findNext"); + LOGV(s); + searchProcess.setKey(s); + int ln = cursorLine + 1; + while (ln < windowData->nLines()) { + AgString line = windowData->getLine(ln); + LOGV(line); + char *p = searchProcess.scanForward(line.pointer(), line.size()); + if (p) { + LOGV(ln) LCV(line); + setCursorLine(ln).synchCursor(ln); + return true; + } + ln++; + } + return false; +} + +Boolean AgDataView::findPrev(AgString s) { + searchProcess.setKey(s); + int ln = cursorLine - 1; + while (ln >= 0) { + AgString line = windowData->getLine(ln); + char *p = searchProcess.scanReverse(line.pointer(), line.size()); + if (p) { + setCursorLine(ln).synchCursor(ln); + return true; + } + ln--; + } + return false; +} + + +AgDataView &AgDataView::setCursorLine(int ln) { + LOGSECTION("AgDataView::setCursorLine"); + LOGV(ln); + LOGV(windowId); + LOGV(frameWindow->windowTitle.text()); + LOGV((int) this); + LOGV((int) frameWindow); + LOGV(layoutComplete); + + int lastLine = windowData->nLines() - 1; + if (ln > lastLine) { + ln = lastLine; + } + if (ln < 0) { + ln = 0; + } + int oldLine = cursorLine; + LOGV(windowData->nLines()); + LOGV(verticalScrollBar.scrollableRange().asString()); + LOGV(verticalScrollBar.visibleCount()); + //int count = verticalScrollBar.visibleCount(); + int count = verticalLineCount; + cursorLine = ln; + if (!layoutComplete) { + return *this; + } + + LOGV(oldLine); + LOGV(cursorLine); + LOGV(count); + + int firstLine = verticalScrollBar.scrollBoxPosition(); + lastLine = firstLine + count - 1; + + LOGV(firstLine); + LOGV(lastLine); + int repositionFlag = 0; + if (cursorLine < firstLine) { + firstLine = cursorLine; + verticalScrollBar.moveScrollBoxTo(firstLine); + repositionFlag = 1; + } + if (cursorLine > lastLine) { + firstLine = cursorLine - (count - 1); + if (firstLine < 0) { + firstLine = 0; + } + verticalScrollBar.moveScrollBoxTo(firstLine); + repositionFlag = 1; + } + if (repositionFlag) { + repositionWindow(); + } + if (cursorLine == oldLine) { + return *this; + } + //windowData->synchCursor(cursorLine); + repaintLine(oldLine); + repaintLine(cursorLine); + LOGV(firstLine); + return *this; +} + +AgDataView &AgDataView::synchCursor(int ln) { + windowData->synchCursor(ln); + return *this; +} + +/* + * + * Layout considerations: + * + * The data view consists of up to four parts: two scroll bars, a heading + * and a data area. + * + * The presence or absence of the scroll bars depends on the relative size + * of the data area and the size of the table to be displayed. + */ + +AgDataView &AgDataView::doLayout() { + LOGSECTION("AgDataView::doLayout"); + LOGV((int) frameWindow); + LOGV(id()); + + LOGV(windowId); + LOGV((int) this); + LOGV(font().name()); + LOGV(font().pointSize()); + ISize canvasSize = size(); + int canvasWidth = canvasSize.width(); + int canvasHeight = canvasSize.height(); + if (canvasHeight == 0) { + return *this; + } + //if (tableWidth == 0) tableWidth = findMaxWidth(); + tableWidth = findMaxWidth(); + tableHeight = lineHeight()*windowData->nLines(); + + LOGV(canvasWidth); + LOGV(canvasHeight); + + int dataWidth = canvasWidth; + int dataHeight = canvasHeight; + int dataY = 0; + ISize columnHeadSize = columnHeadTitle.minimumSize(); + if (columnHeadsPresent) { + dataY = columnHeadSize.height() + 2; + columnHeadSize.setHeight(dataY); + dataHeight -= dataY; + columnHeadTitle.moveTo(IPoint(0, 0)); + } + + LOGV(dataWidth); + LOGV(dataHeight); + + + int vsbWidth = verticalScrollBar.minimumSize().width(); + int hsbHeight = horizontalScrollBar.minimumSize().height(); + + int horizontalPosition = horizontalScrollBar.scrollBoxPosition(); + int verticalPosition = verticalScrollBar.scrollBoxPosition(); + + Boolean vsb = true; + Boolean hsb = true; + + if (tableHeight > dataHeight + && tableWidth <= canvasWidth - vsbWidth - 1) { + // vertical scroll bar only + vsb = true; + hsb = false; + } + else if (tableWidth > canvasWidth + && tableHeight <= dataHeight - hsbHeight - 1) { + // horizontal scroll bar only + vsb = false; + hsb = true; + } + else if (tableWidth <= canvasWidth && tableHeight <= dataHeight) { + // no scroll bars + vsb = hsb = false; + } + + if (vsb && !vsbShowing) { + verticalScrollBar.moveScrollBoxTo(0); + prevVertical = 0; + verticalScrollBar.show(); + vsbShowing = true; + } + if (!vsb && vsbShowing) { + verticalScrollBar.hide(); + vsbShowing = false; + verticalScrollBar.moveScrollBoxTo(0); + prevVertical = 0; + } + + if (hsb && !hsbShowing) { + horizontalScrollBar.show(); + hsbShowing = true; + horizontalScrollBar.moveScrollBoxTo(0); + prevHorizontal = 0; + } + if (!hsb && hsbShowing) { + horizontalScrollBar.hide(); + hsbShowing = false; + horizontalScrollBar.moveScrollBoxTo(0); + prevHorizontal = 0; + } + + if (vsbShowing) { + dataWidth -= vsbWidth + 1; + verticalScrollBar.moveTo(IPoint(dataWidth+1, 0)); + verticalScrollBar.sizeTo(ISize(vsbWidth, canvasHeight)); + } + + if (hsbShowing) { + dataHeight -= hsbHeight + 1; + horizontalScrollBar.moveTo(IPoint(0, canvasHeight - hsbHeight)); + horizontalScrollBar.sizeTo(ISize(dataWidth, hsbHeight)); + } + + dataArea.sizeTo(ISize(dataWidth, dataHeight)); + dataArea.moveTo(IPoint(0, dataY)); + + + LOGV(dataArea.size().asString()); + LOGV(dataArea.parentSize().asString()); + + LOGV(rect().asString()); + LOGV(dataArea.rect().asString()); + LOGV(horizontalScrollBar.rect().asString()); + LOGV(verticalScrollBar.rect().asString()); + + //int widthUnit = charWidth(); + + horizontalScrollBar.setScrollableRange(IRange(0,tableWidth-1)); + horizontalScrollBar.setVisibleCount(dataWidth); + LOGV(horizontalScrollBar.scrollableRange().asString()) LCV(tableWidth); + LOGV(horizontalScrollBar.visibleCount()) LCV(dataWidth); + + + verticalScrollBar.setScrollableRange(IRange(0, windowData->nLines() - 1)); + verticalLineCount = dataHeight/lineHeight(); + //verticalScrollBar.setVisibleCount(dataHeight/lineHeight()); + verticalScrollBar.setVisibleCount(verticalLineCount); + LOGV(dataHeight/lineHeight()); + LOGV(windowData->nLines()); + LOGV(verticalScrollBar.scrollableRange().asString()); + LOGV(verticalScrollBar.visibleCount()); + LOGV(verticalLineCount); + horizontalPosition = min( + (int) horizontalScrollBar.scrollBoxRange().upperBound(), + horizontalPosition + ); + verticalPosition = min( + (int) verticalScrollBar.scrollBoxRange().upperBound(), + verticalPosition + ); + + horizontalScrollBar.setMinScrollIncrement(charWidth()); + verticalScrollBar.setMinScrollIncrement(1); + + prevHorizontal = horizontalScrollBar.scrollBoxPosition(); + horizontalScrollBar.moveScrollBoxTo(horizontalPosition); + + prevVertical = verticalScrollBar.scrollBoxPosition(); + verticalScrollBar.moveScrollBoxTo(verticalPosition); + + LOGV(prevHorizontal); + LOGV(prevVertical); + LOGV(horizontalPosition); + LOGV(verticalPosition); + LOGV(horizontalScrollBar.scrollBoxPosition()); + LOGV(verticalScrollBar.scrollBoxPosition()); + LOGV(verticalPosition); + + if (columnHeadsPresent) { + columnHeadSize.setWidth(dataWidth); + columnHeadTitle.sizeTo(columnHeadSize); + columnHeadTitle.xPos = horizontalPosition; + columnHeadTitle.refresh(); + } + layoutComplete = 1; + setCursorLine(cursorLine).synchCursor(cursorLine); + return *this; +} + +Boolean AgDataView::lineDown(IScrollEvent &event) { + if (event.scrollBarWindow() != &verticalScrollBar) { + return false; + } + LOGSECTION("AgDataView::lineDown"); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::lineLeft(IScrollEvent &event) { + if (event.scrollBarWindow() != &horizontalScrollBar) { + return false; + } + LOGSECTION("AgDataView::lineLeft"); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::lineRight(IScrollEvent &event) { + if (event.scrollBarWindow() != &horizontalScrollBar) { + return false; + } + LOGSECTION("AgDataView::lineRight"); + LOGV(horizontalScrollBar.scrollBoxPosition()); + moveScrollBox(event); + repositionWindow(); + LOGV(horizontalScrollBar.scrollBoxPosition()); + return true; +} + +Boolean AgDataView::lineUp(IScrollEvent &event) { + if (event.scrollBarWindow() != &verticalScrollBar) { + return false; + } + LOGSECTION("AgDataView::lineUp"); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::pageDown(IScrollEvent &event) { + if (event.scrollBarWindow() != &verticalScrollBar) { + return false; + } + LOGSECTION("AgDataView::pageDown"); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::pageLeft(IScrollEvent &event) { + if (event.scrollBarWindow() != &horizontalScrollBar) { + return false; + } + LOGSECTION("AgDataView::pageLeft"); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::pageRight(IScrollEvent &event) { + if (event.scrollBarWindow() != &horizontalScrollBar) { + return false; + } + LOGSECTION("AgDataView::pageRight"); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::pageUp(IScrollEvent &event) { + if (event.scrollBarWindow() != &verticalScrollBar) { + return false; + } + LOGSECTION("AgDataView::pageUp"); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::scrollBoxTrack(IScrollEvent &event) { + LOGSECTION("AgDataView::scrollBoxTrack"); + LOGV(verticalScrollBar.scrollBoxPosition()); + LOGV(horizontalScrollBar.scrollBoxPosition()); + moveScrollBox(event); + //if (!event.controlWindow()->hasPointerCaptured()) { + // event.controlWindow()->capturePointer(true); + //} + LOGV(verticalScrollBar.scrollBoxPosition()); + LOGV(horizontalScrollBar.scrollBoxPosition()); + repositionWindow(); + return true; +} + +Boolean AgDataView::scrollBoxTrackEnd(IScrollEvent &event) { + //event.controlWindow()->releasePointer(); + moveScrollBox(event); + repositionWindow(); + return true; +} + +Boolean AgDataView::key(IKeyboardEvent &event) { + return false; +} + + +Boolean AgDataView::virtualKeyPress(IKeyboardEvent &event) { + LOGSECTION("AgDataView::virtualKeyPress"); + LOGV((int) frameWindow); + LOGV((int) event.virtualKey()); + LOGV(event.isShiftDown()) LCV(event.isCtrlDown()) LCV(event.isAltDown()); + switch (event.virtualKey()) { + case IKeyboardEvent::newLine: + case IKeyboardEvent::enter: { + LOGSECTION("AgDataView::enter"); + if (enterAction.exists()) { + enterAction.performDeferred(); + } + return true; + } + case IKeyboardEvent::up: { + int line = cursorLine; + if (cursorLine > 0) { + cursorLine--; + } + else { + messageBeep(); + } + if (line != cursorLine) { + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + } + LOGV(cursorLine); + if (cursorLine < verticalScrollBar.scrollBoxPosition()) { + repaintLine(line); + verticalScrollBar.moveScrollBoxTo(cursorLine); + repositionWindow(); + return true; + } + repaintLine(line); + repaintLine(cursorLine); + return true; + } + case IKeyboardEvent::down: { + LOGSECTION("Cursor down one line"); + int line = cursorLine; + if (cursorLine < windowData->nLines() - 1) { + cursorLine++; + } + else { + messageBeep(); + } + if (line != cursorLine) { + selectAction.performDeferred(); + windowData->synchCursor(cursorLine); + } + LOGV(line) LCV(cursorLine); + LOGV((int) this); + LOGV((int) &cursorLine); + LOGV(cursorLine); + int bottomLine = verticalScrollBar.scrollBoxPosition() + + verticalLineCount - 1; + //+ verticalScrollBar.visibleCount() - 1; + + LOGV(line); + LOGV(cursorLine); + LOGV(bottomLine); + + if (cursorLine > bottomLine) { + LOGS("scrolling"); + verticalScrollBar.moveScrollBoxTo( + cursorLine + - verticalLineCount + 1 + //- verticalScrollBar.visibleCount() + 1 + ); + repositionWindow(); + } + repaintLine(line); + repaintLine(cursorLine); + return true; + } + case IKeyboardEvent::pageUp: { + int line = cursorLine; + if (cursorLine == 0) { + messageBeep(); + return true; + } + //cursorLine -= verticalScrollBar.visibleCount(); + cursorLine -= verticalLineCount; + if (cursorLine < 0 || event.isCtrlDown()) { + cursorLine = 0; + repaintLine(line); + repaintLine(cursorLine); + } + if (cursorLine < verticalScrollBar.scrollBoxPosition()) { + verticalScrollBar.moveScrollBoxTo(cursorLine); + repositionWindow(); + } + if (line != cursorLine) { + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + } + return true; + } + case IKeyboardEvent::home: { + if (cursorLine && event.isCtrlDown()) { + int line = cursorLine; + cursorLine = 0; + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + if (cursorLine < verticalScrollBar.scrollBoxPosition()) { + repaintLine(line); + verticalScrollBar.moveScrollBoxTo(cursorLine); + repositionWindow(); + return true; + } + repaintLine(line); + repaintLine(cursorLine); + return true; + } + else { + messageBeep(); + } + return true; + } + case IKeyboardEvent::end: { + int lastLine = windowData->nLines() - 1; + if (cursorLine < lastLine && event.isCtrlDown()) { + int line = cursorLine; + cursorLine = lastLine; + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + if (cursorLine < + verticalScrollBar.scrollBoxPosition()-verticalLineCount) { + repaintLine(line); + verticalScrollBar.moveScrollBoxTo(cursorLine); + repositionWindow(); + return true; + } + repaintLine(line); + repaintLine(cursorLine); + return true; + } + else { + messageBeep(); + } + return true; + } + case IKeyboardEvent::pageDown: { + int line = cursorLine; + cursorLine += verticalLineCount; + int lastLine = windowData->nLines() - 1; + if (cursorLine == lastLine) { + messageBeep(); + return true; + } + if (cursorLine > lastLine || event.isCtrlDown()) { + cursorLine = lastLine; + repaintLine(line); + repaintLine(cursorLine); + } + if (cursorLine > verticalScrollBar.scrollBoxPosition()) { + verticalScrollBar.moveScrollBoxTo( + cursorLine - verticalLineCount + 1 + ); + repositionWindow(); + } + if (line != cursorLine) { + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + } + return true; + } + case IKeyboardEvent::left: { + int position = horizontalScrollBar.scrollBoxPosition() - charWidth(); + if (position >= 0) { + horizontalScrollBar.moveScrollBoxTo(position); + repositionWindow(); + } + else { + messageBeep(); + } + return true; + } + case IKeyboardEvent::right: { + int position = horizontalScrollBar.scrollBoxPosition() + charWidth(); + if (position <= horizontalScrollBar.scrollableRange().upperBound()) { + horizontalScrollBar.moveScrollBoxTo(position); + repositionWindow(); + } + else { + messageBeep(); + } + return true; + } + //default: return false; + } + return false; +} + +Boolean AgDataView::mouseClicked(IMouseClickEvent &event) { + //LOGSECTION("AgDataView::mouseClicked", Log::off); + LOGSECTION_OFF("AgDataView::mouseClicked"); + LOGV(frameWindow->activeFlag); + + unsigned line = event.mousePosition().y()/lineHeight(); + line += verticalScrollBar.scrollBoxPosition(); + unsigned nLines = windowData->nLines(); + + if (ControlPanel::helpCursorSet) { + if (event.mouseButton() == IMouseClickEvent::button2) { + return false; + } + if (event.mouseAction() == IMouseClickEvent::down) { + if (line < nLines && line != cursorLine) { + setCursorLine(line).synchCursor(line); + selectAction.performDeferred(); + } + showHelp(event); + ControlPanel::helpCursorSet = 0; + ControlPanel::resetCursor(); + } + return true; + } + + if (event.controlWindow() == &columnHeadTitle + || event.controlWindow() == &verticalScrollBar + || event.controlWindow() == &horizontalScrollBar) + { + if (event.mouseAction() == IMouseClickEvent::down) { + dataArea.setFocus(); + } + return false; + } + + LOGV(event.mouseButton()); + LOGV(event.mouseAction()); + LOGV(line); + + if (event.mouseButton() == IMouseClickEvent::button2) { + if (!dataArea.hasFocus()) { + dataArea.setFocus(); + } + if (line >= nLines) { + return true; + } +/* + if (event.mouseAction() == IMouseClickEvent::down) { + rightButtonDown = true; + } + else if (event.mouseAction() == IMouseClickEvent::up) { + rightButtonDown = false; + } + else if (event.mouseAction() == IMouseClickEvent::click) { + LOGS("right click"); + if (line == cursorLine) { + //return true; + return false; + } + setCursorLine(line).synchCursor(line); + selectAction.performDeferred(); + return false; + } +*/ + if (event.mouseAction() == IMouseClickEvent::down) { + rightButtonState = buttonDown; + } + else if (event.mouseAction() == IMouseClickEvent::up) { + rightButtonState = waitingForClick; + if (line == cursorLine) { + return false; + } + setCursorLine(line).synchCursor(line); + selectAction.performDeferred(); + return false; + } + else if (event.mouseAction() == IMouseClickEvent::click) { + rightButtonState = buttonIdle; + return false; + } + } + if (line >= nLines && event.mouseAction() == IMouseClickEvent::down) { + if (!dataArea.hasFocus()) { + dataArea.setFocus(); + } + return false; + } + if (!mouseDown && line >= nLines) { + return false; + } + if (event.mouseButton() != IMouseClickEvent::button1) { + return false; + } + switch (event.mouseAction()) { + case IMouseClickEvent::down: { + if (event.windowUnderPointer() != dataArea.handle()) { + return false; + } + LOGS("mouse down"); + if (!dataArea.hasFocus()) { + dataArea.setFocus(); + } + dataArea.capturePointer(true); + mouseDownCursorLine = cursorLine; + if (line != cursorLine) { + setCursorLine(line).synchCursor(line); + selectAction.performDeferred(); + } + mouseDown = true; + return true; + } + case IMouseClickEvent::up: { + LOGS("mouse up"); + mouseDown = false; + dataArea.capturePointer(false); + return true; + } + case IMouseClickEvent::click: { + if (event.windowUnderPointer() != dataArea.handle()) { + return false; + } + LOGS("mouse click"); + return true; + } + case IMouseClickEvent::doubleClick: { + LOGS("double click"); + enterAction.performDeferred(); + return true; + } + } + return false; +} + +Boolean AgDataView::mouseMoved(IMouseEvent &event) { + if (!mouseDown) { + return false; + } + if (mouseTimer.isStarted()) { + mouseTimer.stop(); + } + int mouseY = event.mousePosition().y(); + if (mouseY < 0) { + mouseY -= lineHeight(); + } + int mouseLine = mouseY/lineHeight(); + int topLine = verticalScrollBar.scrollBoxPosition(); + LOGSECTION("AgDataView::mouseMoved"); + LOGV((int) frameWindow); + LOGV(topLine) LCV(mouseLine); + dragMouse(topLine, mouseLine); + if (mouseLine >= 0 && mouseLine < verticalLineCount) { + return true; + } + topLine = verticalScrollBar.scrollBoxPosition(); + IReference<ITimerFn> timerFn(new MouseDragTimer(this, topLine, mouseLine)); + mouseTimer.start(timerFn, 50); + LOGS("timer started"); + return true; +} + +void AgDataView::dragMouse(int topLine, int mouseLine) { + LOGSECTION("AgDataView::DragMouse"); + LOGV((int) frameWindow); + int bottomLine = topLine + verticalLineCount - 1; + int line = topLine + mouseLine; + if (line < 0) { + line = 0; + } + if (line >= windowData->nLines()) { + line = windowData->nLines() - 1; + } + if (line == cursorLine) { + return; + } + int oldLine = cursorLine; + cursorLine = line; + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + LOGV(topLine); + LOGV(mouseLine); + LOGV(oldLine); + LOGV(cursorLine); + if (cursorLine < topLine) { + repaintLine(oldLine); + verticalScrollBar.moveScrollBoxTo(cursorLine); + repositionWindow(); + return; + } + //if (cursorLine > bottomLine + 1) { + if (cursorLine > bottomLine) { + repaintLine(oldLine); + verticalScrollBar.moveScrollBoxTo(topLine + cursorLine - bottomLine); + repositionWindow(); + return; + } + else { + repaintLine(oldLine); + repaintLine(cursorLine); + } + LOGV(cursorLine); + windowData->synchCursor(cursorLine); + selectAction.performDeferred(); + return; +} + +void AgDataView::mouseDragTimerInterrupt(int &topLine, int mouseLine) { + LOGSECTION("AgDataView::mouseDragTimerInterrupt"); + LOGV((int) frameWindow); + LOGV(topLine) LCV(mouseLine) LCV(cursorLine); + if (!mouseDown || topLine + mouseLine == cursorLine) { + mouseTimer.stop(); + LOGV(mouseDown); + LOGV(topLine) LCV(verticalScrollBar.scrollBoxPosition()); + return; + } + if (topLine + mouseLine != cursorLine) { + dragMouse(topLine, mouseLine); + } + topLine = verticalScrollBar.scrollBoxPosition(); +} + +AgDataView::MouseDragTimer::MouseDragTimer(AgDataView * window_, + int topLine_, + int mouseLine_) + : window(window_) + , topLine(topLine_) + , mouseLine(mouseLine_) +{} + +void AgDataView::MouseDragTimer::timerExpired(unsigned long) { + LOGSECTION("AgDataView::MouseDragTimer::timerExpired"); + window->mouseDragTimerInterrupt(topLine, mouseLine); +} + +Boolean AgDataView::command(ICommandEvent &event) { + unsigned id = event.commandId() - 1; + LOGSECTION("AgDataView::command"); + LOGV((int) event.controlWindow()); + LOGV((int) event.dispatchingWindow()); + LOGV((int) frameWindow); + LOGV((int) id); + + if (id >= auxMenu.size()) { + return false; + } + LOGV(ControlPanel::helpCursorSet) LCV(AgFrame::menuShowingFlag); + if (ControlPanel::helpCursorSet) { + ControlPanel::helpCursorSet = 0; + ControlPanel::resetCursor(); + AgHelpWindow::showHelp(auxMenu[id].text); + return true; + } + + auxMenu[id].action.perform(); + return true; +} + +AgDataView &AgDataView::initPopUp() { + if (popUpInitialized) { + return *this; + } + popUpInitialized = 1; + + LOGSECTION("AgDataView::initPopUp"); + LOGV(windowId); + LOGV((int) this); + LOGV((int) frameWindow); + LOGV((int) &popUpMenu); + + int n = auxMenu.size(); + int i; + for (i = 0; i < n; i++) { + char *text = auxMenu[i].text.pointer(); + LOGV(text); + LOGV((int) auxMenu[i].displayControl); + popUpMenu.addText(i+1, text); + } + return *this; +} + +AgDataView &AgDataView::validatePopUp() { + LOGSECTION("AgDataView::validatePopUp"); + LOGV(windowId) LCV((int) this); + LOGV((int) frameWindow) LCV((int) windowData); + LOGV(windowData->getCursorLine()); + LOGV(ControlPanel::helpCursorSet) LCV(AgFrame::menuShowingFlag); + + if (ControlPanel::helpCursorSet) { + return *this; + } + int n = auxMenu.size(); + LOGV(n); + int i; + for (i = 0; i < n; i++) { + //char *text = auxMenu[i].text.pointer(); + //LOGV(text); + dc *d = auxMenu[i].displayControl; + LOGV((int) d); + ok_ptr(d); + dc::MenuOption **option = d->getAuxWinMenu(); +#ifdef INCLUDE_LOGGING + LOGV((int) option) LCV((int) option[i]); + union { int(dc::*fun)(); int address; } kluge; + kluge.fun = option[i]->ok_action; + LOGV(kluge.address); +#endif + int flag = ((*d).*(option[i]->ok_action))(); + LOGV(flag); + popUpMenu.enableItem(i+1, flag); + } + return *this; +} + +Boolean AgDataView::makePopUpMenu(IMenuEvent &event ) { + LOGSECTION("AgDataView::makePopUpMenu"); + LOGV(windowId); + LOGV((int) this); + LOGV((int) frameWindow); + if (!auxMenu.exists()) { + return false; + } + IPoint where = dataArea.position(); + if (rightButtonState == waitingForClick) { + LOGV(event.mousePosition().asString()); + where = event.mousePosition(); + } + LOGV(auxMenu.exists()); + + int n = auxMenu.size(); + int i; + for (i = 0; i < n; i++) { + popUpMenu.enableItem(i+1); + } + validatePopUp(); + + AgFrame::activeAuxMenu = auxMenu; + + LOGS("activeAuxMenu has been set"); + + AgFrame::activePopUpMenu = &popUpMenu; + + LOGS("activePopUpMenu has been set"); + LOGS("ready to display popUpMenu"); + + //popUpMenu.show(event.mousePosition()); + popUpMenu.show(where); + + LOGS("popUpMenu should be visible"); + + AgFrame::activeAuxMenu.discardData(); + AgFrame::activePopUpMenu = 0; + + return true; +} + +Boolean AgDataView::showHelp(IEvent &event) { + showHelp(); + return true; +} + +void AgDataView::showHelp() { + AgString topic; + LOGSECTION("AgDataView::showHelp"); + int n = popUpMenu.numberOfItems(); + for (int i = 0; i++ < n;) { + IMenuItem item = popUpMenu.menuItem(i); + if (item.isHighlighted()) { + topic = auxMenu[i-1].text; + break; + } + } + LOGV(i) LCV(n) LCV(topic); + if (!topic.exists() && helpTopic != 0) { + topic = helpTopic; + } + if (!topic.exists()) { + topic = windowData->findHelpTopic(); + } + if (!topic.exists()) { + topic = windowData->headTitle(); + } + AgHelpWindow::showHelp(topic); +} + +Boolean AgDataView::menuEnded(IMenuEvent &event) { + LOGSECTION("AgDataView::menuEnded"); + LOGV((int) frameWindow); + LOGV(ControlPanel::helpCursorSet) LCV(AgFrame::menuShowingFlag); + if (!ControlPanel::helpCursorSet) { + frameWindow->activeAuxMenu.discardData(); + } + return true; +} +