]> gitweb.hamatoma.de Git - reqt/commitdiff
horizontal scrolling works (mostly)
authorhama <hama@siduction.net>
Sun, 19 Jul 2015 06:40:45 +0000 (08:40 +0200)
committerhama <hama@siduction.net>
Sun, 19 Jul 2015 06:40:45 +0000 (08:40 +0200)
gui/ReEdit.cpp
gui/ReEdit.hpp

index f78617421f2bb63a01797389e37c4d7f25c67e43..3ef62133991d382f2d54b7cd370fa05bd85dfff7 100644 (file)
@@ -36,11 +36,11 @@ inline int heightToFullHeight(int height) {
  * @param edit          the parent
  */
 ReLook::ReLook() :
-               m_font(NULL),
-               m_metrics(NULL),
-               m_foreground(FG_STANDARD),
-               m_background(BG_STANDARD),
-               m_edit(NULL) {
+           m_font(NULL),
+           m_metrics(NULL),
+           m_foreground(FG_STANDARD),
+           m_background(BG_STANDARD),
+           m_edit(NULL) {
 }
 
 /**
@@ -50,8 +50,8 @@ ReLook::ReLook() :
  * @param look  the presentation of the text
  */
 ReEditText::ReEditText(const QString& text, ReLook* look) :
-               m_text(text),
-               m_look(look) {
+           m_text(text),
+           m_look(look) {
 
 }
 
@@ -64,8 +64,8 @@ ReEditText::ReEditText(const QString& text, ReLook* look) :
  * @param edit      the edit field (parent)
  */
 void ReCursortLineBuilder::buildParagraph(ReParagraph& paragraph, int lineNo,
-       ReEdit* edit) {
-       if (lineNo == edit->cursorLine()) {
+    ReEdit* edit) {
+       if (lineNo == edit->cursorLineNo()) {
                for (int ix = 0; ix < paragraph.length(); ix++) {
                        ReEditText* text = paragraph.at(ix);
                        ReLook::ForeGround foreground = text->look()->m_foreground;
@@ -100,32 +100,32 @@ void ReCursortLineBuilder::buildParagraph(ReParagraph& paragraph, int lineNo,
  * @param parent    NULL or a widget which destroy the instance
  */
 ReEdit::ReEdit(QWidget* parent) :
-               QWidget(parent),
-               ReMouseCatcher(),
-               m_widthEdit(0),
-               m_heightEdit(0),
-               m_insertMode(true),
-               m_breakLines(false),
-               m_widthLineNo(50),
-               m_widthVScrollBar(10),
-               m_heightHScrollBar(10),
-               m_looks(),
-               m_standardBrush(new QBrush(Qt::SolidPattern)),
-               m_scrollbarBrush(new QBrush(Qt::SolidPattern)),
-               m_sliderBrush(new QBrush(Qt::ConicalGradientPattern)),
-               m_brushColors(),
-               m_standardPen(new QPen(Qt::SolidLine)),
-               m_standardFont(NULL),
-               m_standardMetrics(NULL),
-               m_fontColors(),
-               m_keyAlt(),
-               m_keyAltControl(),
-               m_keyAltControlShift(),
-               m_keyAltShift(),
-               m_keyControl(),
-               m_keyControlShift(),
-               m_keyRaw(),
-               m_keyShift() {
+           QWidget(parent),
+           ReMouseCatcher(),
+           m_widthEdit(0),
+           m_heightEdit(0),
+           m_insertMode(true),
+           m_breakLines(false),
+           m_widthLineNo(50),
+           m_widthVScrollBar(16),
+           m_heightHScrollBar(16),
+           m_looks(),
+           m_standardBrush(new QBrush(Qt::SolidPattern)),
+           m_scrollbarBrush(new QBrush(Qt::SolidPattern)),
+           m_sliderBrush(new QBrush(Qt::ConicalGradientPattern)),
+           m_brushColors(),
+           m_standardPen(new QPen(Qt::SolidLine)),
+           m_standardFont(NULL),
+           m_standardMetrics(NULL),
+           m_fontColors(),
+           m_keyAlt(),
+           m_keyAltControl(),
+           m_keyAltControlShift(),
+           m_keyAltShift(),
+           m_keyControl(),
+           m_keyControlShift(),
+           m_keyRaw(),
+           m_keyShift() {
        setFocusPolicy(Qt::WheelFocus);
        m_standardFont = new QFont("Courier");
        m_standardFont->setStyleHint(QFont::TypeWriter);
@@ -206,6 +206,10 @@ void ReEdit::assignKeysStandard() {
        m_keyAlt[Qt::Key_Delete] = EA_DEL_LINE;
        m_keyControl[Qt::Key_Z] = EA_UNDO;
        m_keyControlShift[Qt::Key_Z] = EA_REDO;
+       m_keyAltControl[Qt::Key_Left] = EA_VIEW_LEFT;
+       m_keyAltControl[Qt::Key_Right] = EA_VIEW_RIGHT;
+       m_keyAltControlShift[Qt::Key_Left] = EA_PAGE_LEFT;
+       m_keyAltControlShift[Qt::Key_Right] = EA_PAGE_RIGHT;
 }
 
 /**
@@ -218,7 +222,7 @@ void ReEdit::assignKeysStandard() {
  * @param length        OUT: the slider length in pixel
  */
 void calcSliderSize(int size, int minSize, double sizeFactor, double posFactor,
-       int& position, int& length) {
+    int& position, int& length) {
        if (sizeFactor > 1.0)
                sizeFactor = 1.0;
        if (posFactor > 100)
@@ -247,8 +251,8 @@ QBrush* ReEdit::createBrush(ReLook::BackGround background) {
  *
  * @return the line number [0..N-1]
  */
-int ReEdit::cursorLine() const {
-       return m_cursorLine;
+int ReEdit::cursorLineNo() const {
+       return m_cursorLineNo;
 }
 
 /**
@@ -262,20 +266,24 @@ int ReEdit::cursorLine() const {
  * @param posHorizontal     the position of the scrollbar as factor [0..1]
  */
 void ReEdit::drawScrollbars(QPainter& painter, const QRect& rect,
-       double sizeVertical, double posVertical, double sizeHorizontal,
-       double posHorizontal) {
+    double sizeVertical, double posVertical, double sizeHorizontal,
+    double posHorizontal) {
        // We paint the vertical scrollbar:
        QBrush brush(*m_brushColors[ReLook::BG_SCROLLBAR], Qt::SolidPattern);
        painter.setBrush(brush);
        int x = rect.right() - m_widthVScrollBar;
-       m_vScrollBar->setRect(x, rect.top(), m_widthVScrollBar,
-               rect.height() - m_heightHScrollBar);
+       // Note: the frame is outside of the rectangle (edit field too!):
+       static int width = 1;
+       static int width2 = 2 * width;
+       m_vScrollBar->setRect(x + width2, rect.top(), m_widthVScrollBar - width2,
+           rect.height() - m_heightHScrollBar - width);
        painter.drawRect(*m_vScrollBar);
 
        // We paint the horizontal scrollbar:
        m_hScrollBar->setRect(rect.left() + m_widthLineNo,
-               rect.bottom() - m_heightHScrollBar,
-               rect.width() - m_widthVScrollBar - m_widthLineNo, m_heightHScrollBar);
+           rect.bottom() - m_heightHScrollBar + width,
+           rect.width() - m_widthVScrollBar - m_widthLineNo,
+           m_heightHScrollBar - width2);
        painter.drawRect(*m_hScrollBar);
 
        // Slider (vertical)
@@ -284,16 +292,17 @@ void ReEdit::drawScrollbars(QPainter& painter, const QRect& rect,
        int sliderSize = 0;
        int sliderPos = 0;
        calcSliderSize(rect.height() - m_heightHScrollBar, m_heightHScrollBar,
-               sizeVertical, posVertical, sliderPos, sliderSize);
-       m_vSlider->setRect(x, rect.top() + sliderPos, m_widthVScrollBar,
-               sliderSize);
+           sizeVertical, posVertical, sliderPos, sliderSize);
+       m_vSlider->setRect(x + width2, rect.top() + sliderPos + width,
+           m_widthVScrollBar - width2, sliderSize - width2);
        painter.drawRect(*m_vSlider);
        // Slider (horizontal)
        calcSliderSize(rect.width() - m_widthLineNo - m_widthVScrollBar,
-               m_heightHScrollBar, sizeHorizontal, posHorizontal, sliderPos,
-               sliderSize);
+           m_heightHScrollBar, sizeHorizontal, posHorizontal, sliderPos,
+           sliderSize);
        m_hSlider->setRect(rect.left() + m_widthLineNo + sliderPos,
-               rect.bottom() - m_heightHScrollBar, sliderSize, m_heightHScrollBar);
+           rect.bottom() - m_heightHScrollBar + width, sliderSize - width,
+           m_heightHScrollBar - width2);
        painter.drawRect(*m_hSlider);
 }
 
@@ -313,18 +322,18 @@ void ReEdit::editorAction(ReEdit::EditorAction action) {
                ensureCursorVisible();
                break;
        case EA_CHAR_RIGHT:
-               if (++m_cursorCol >= m_lines->lineAt(m_cursorLine).length())
-                       m_cursorCol = m_lines->lineAt(m_cursorLine).length() - 1;
+               if (++m_cursorCol >= m_lines->lineAt(m_cursorLineNo).length())
+                       m_cursorCol = m_lines->lineAt(m_cursorLineNo).length() - 1;
                ensureCursorVisible();
                break;
        case EA_LINE_UP:
-               if (--m_cursorLine < 0)
-                       m_cursorLine = 0;
+               if (--m_cursorLineNo < 0)
+                       m_cursorLineNo = 0;
                ensureCursorVisible();
                break;
        case EA_LINE_DOWN:
-               if (++m_cursorLine >= m_lines->lineCount())
-                       m_cursorLine = m_lines->lineCount() - 1;
+               if (++m_cursorLineNo >= m_lines->lineCount())
+                       m_cursorLineNo = m_lines->lineCount() - 1;
                ensureCursorVisible();
                break;
        case EA_BEGIN_OF_LINE:
@@ -332,8 +341,7 @@ void ReEdit::editorAction(ReEdit::EditorAction action) {
                ensureCursorVisible();
                break;
        case EA_END_OF_LINE:
-               m_cursorCol = m_lines->lineAt(m_cursorLine).length() - 1;
-               ;
+               m_cursorCol = m_lines->lineAt(m_cursorLineNo).length() - 1;
                ensureCursorVisible();
                break;
        case EA_BEGIN_OF_FILE:
@@ -344,11 +352,11 @@ void ReEdit::editorAction(ReEdit::EditorAction action) {
                break;
        case EA_PAGE_UP:
                // Do not change cursor line!
-               reposition(m_firstLine - pageSize);
+               reposition(m_firstLine - pageSize, m_firstCol);
                break;
        case EA_PAGE_DOWN:
                // Do not change cursor line!
-               reposition(m_firstLine + pageSize);
+               reposition(m_firstLine + pageSize, m_firstCol);
                break;
        case EA_DEL_CHAR:
                break;
@@ -361,10 +369,22 @@ void ReEdit::editorAction(ReEdit::EditorAction action) {
        case EA_DEL_LINE:
                break;
        case EA_UNDO:
-               m_lines->undo(m_cursorLine, m_cursorCol);
+               m_lines->undo(m_cursorLineNo, m_cursorCol);
                break;
        case EA_REDO:
                break;
+       case EA_VIEW_LEFT:
+               reposition(m_firstLine, m_firstCol - 1);
+               break;
+       case EA_VIEW_RIGHT:
+               reposition(m_firstLine, m_firstCol + 1);
+               break;
+       case EA_PAGE_RIGHT:
+               reposition(m_firstLine, m_firstCol + m_screenWidth);
+               break;
+       case EA_PAGE_LEFT:
+               reposition(m_firstLine, m_firstCol - m_screenWidth);
+               break;
        default:
                break;
        }
@@ -378,10 +398,10 @@ void ReEdit::editorAction(ReEdit::EditorAction action) {
  */
 void ReEdit::ensureCursorVisible(int cursorLine) {
        if (cursorLine >= 0)
-               m_cursorLine = cursorLine;
-       if (m_cursorLine < m_firstLine
-               || m_cursorLine >= m_firstLine + pageSize()) {
-               reposition(m_cursorLine);
+               m_cursorLineNo = cursorLine;
+       if (m_cursorLineNo < m_firstLine
+           || m_cursorLineNo >= m_firstLine + pageSize()) {
+               reposition(m_cursorLineNo, m_cursorCol);
        }
 }
 
@@ -400,37 +420,34 @@ void ReEdit::keyPressEvent(QKeyEvent* event) {
                switch (key) {
                case Qt::Key_Enter:
                case Qt::Key_Return:
-                       m_lines->splitLine(m_cursorLine,
-                               columnToIndex(m_cursorCol) + 1, true);
+                       m_lines->splitLine(m_cursorLineNo, m_cursorCol + 1, true);
                        m_cursorCol = -1;
-                       m_cursorLine++;
+                       m_cursorLineNo++;
                        break;
-               case Qt::Key_Backspace:{
+               case Qt::Key_Backspace: {
                        int currentCol = m_cursorCol;
                        m_cursorCol = max(-1, currentCol - 1);
-                       if (currentCol == -1 && m_cursorLine > 0) {
+                       if (currentCol == -1 && m_cursorLineNo > 0) {
                                // join the previous and the current line:
                                // the cursor position will be the end of the previous line:
-                               m_cursorCol = indexToColumn(m_lines->lineAt(m_cursorLine - 1)
-                                                                                       .length() - 1);
+                               m_cursorCol = m_lines->lineAt(m_cursorLineNo - 1).length() - 1;
                        }
-                       if (m_lines->removePart(m_cursorLine, columnToIndex(currentCol), 1, true))
-                               m_cursorLine = max(0, m_cursorLine - 1);
+                       if (m_lines->removePart(m_cursorLineNo, columnToIndex(currentCol),
+                           1, true))
+                               m_cursorLineNo = max(0, m_cursorLineNo - 1);
                        break;
                }
                case Qt::Key_Delete:
-                       m_lines->removePart(m_cursorLine, columnToIndex(m_cursorCol) + 1, 1, true);
+                       m_lines->removePart(m_cursorLineNo, m_cursorCol + 1, 1, true);
                        break;
                default:
-                       m_lines->insertText(m_cursorLine,
-                               columnToIndex(m_cursorCol) + 1, keyText);
+                       m_lines->insertText(m_cursorLineNo, m_cursorCol + 1, keyText);
                        m_cursorCol++;
                        break;
                }
-       } else if (shift && ! keyText.isEmpty() && key != Qt::Key_Delete
-                          && key != Qt::Key_Backspace){
-               m_lines->insertText(m_cursorLine,
-                       columnToIndex(m_cursorCol) + 1, keyText);
+       } else if (shift && !keyText.isEmpty() && key != Qt::Key_Delete
+           && key != Qt::Key_Backspace) {
+               m_lines->insertText(m_cursorLineNo, m_cursorCol + 1, keyText);
                m_cursorCol++;
        } else {
                QMap<int, EditorAction>* map;
@@ -475,7 +492,7 @@ ReLines& ReEdit::lines() {
  * @return
  */
 ReLook* ReEdit::lookOf(ReLook::ForeGround foreground,
-       ReLook::BackGround background) {
+    ReLook::BackGround background) {
        int index = foreground * ReLook::BG_COUNT + background;
        ReLook* rc = m_looks[index];
        if (rc == NULL) {
@@ -502,8 +519,8 @@ ReLook* ReEdit::lookOf(ReLook::ForeGround foreground,
  */
 void ReEdit::mouseMoveEvent(QMouseEvent* event) {
        if (m_lastMousePosition.x() >= 0
-               && (handleHScrollBar(event, true, this)
-                       || handleVScrollBar(event, true, this))) {
+           && (handleHScrollBar(event, true, this)
+               || handleVScrollBar(event, true, this))) {
                emit repaint();
        }
 }
@@ -520,15 +537,15 @@ void ReEdit::mousePressEvent(QMouseEvent* event) {
 
        } else {
                QPoint position = event->pos();
-               m_cursorLine = position.y()
-                       / heightToFullHeight(m_standardMetrics->height()) + m_firstLine;
+               m_cursorLineNo = position.y()
+                   / heightToFullHeight(m_standardMetrics->height()) + m_firstLine;
                int x = position.x();
                int charWidth = m_standardMetrics->width('x');
                if (x >= m_widthLineNo && x < m_widthEdit - m_widthVScrollBar) {
                        if (x <= m_widthLineNo + charWidth / 2)
                                m_cursorCol = -1;
                        else
-                               m_cursorCol = (x - m_widthLineNo) / charWidth;
+                               m_cursorCol = columnToIndex((x - m_widthLineNo) / charWidth);
                }
        }
        m_lastMousePosition = event->pos();
@@ -544,6 +561,7 @@ void ReEdit::mousePressEvent(QMouseEvent* event) {
  */
 void ReEdit::mouseReleaseEvent(QMouseEvent* event) {
        m_lastMousePosition.setX(-1);
+       m_lastMousePosition.setY(-1);
 }
 
 /**
@@ -558,13 +576,16 @@ void ReEdit::paintEvent(QPaintEvent* event) {
        m_heightEdit = rect.height();
        int lineHeight = heightToFullHeight(m_standardMetrics->height());
        int pageSize = (rect.height() - m_heightHScrollBar) / lineHeight;
+       int charWidth = m_standardMetrics->averageCharWidth();
+       int pageWidth = (rect.width() - m_widthVScrollBar - m_widthLineNo)
+           / charWidth;
        int firstLine = m_firstLine;
-       load(firstLine, pageSize, this);
+       load(firstLine, pageSize, pageWidth, this);
        QPainter painter(this);
        ReLook* look = lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD);
        painter.setBrush(*look->m_brush);
        QRect editArea(rect.left() + m_widthLineNo, rect.top(),
-               rect.right() - m_widthVScrollBar, rect.bottom() - m_heightHScrollBar);
+           rect.right() - m_widthVScrollBar, rect.bottom() - m_heightHScrollBar);
        painter.drawRect(editArea);
        draw(painter, rect.top(), rect.left() + m_widthLineNo);
        int left = rect.left() + m_widthLineNo - 3;
@@ -575,38 +596,38 @@ void ReEdit::paintEvent(QPaintEvent* event) {
        for (int ix = 0; ix < m_list.length(); ix++, lineNo++) {
                QString number = QString::number(lineNo) + ":";
                ReLook* look =
-                       lineNo == m_cursorLine + 1 ?
-                               lookOf(ReLook::FG_CURRENT_LINE, ReLook::BG_CURRENT_LINE) :
-                               lookStd;
+                   lineNo == m_cursorLineNo + 1 ?
+                       lookOf(ReLook::FG_CURRENT_LINE, ReLook::BG_CURRENT_LINE) :
+                       lookStd;
                int width = look->m_metrics->width(number);
                if (ix == 0)
                        y = rect.top() + look->m_metrics->height()
-                               - look->m_metrics->descent();
+                           - look->m_metrics->descent();
                painter.setFont(*look->m_font);
                painter.setPen(*look->m_pen);
                painter.drawText(left + m_widthLineNo - width - 5, y, number);
                y += lineHeight;
        }
        // We paint the cursor:
-       if (m_cursorVisible && m_cursorLine >= firstLine
-               && m_cursorLine < firstLine + pageSize) {
-               int col = m_cursorCol;
-               if (m_lines->lineAt(m_cursorLine).length() <= col)
-                       col = m_lines->lineAt(m_cursorLine).length() - 1;
+       if (m_cursorVisible && m_cursorLineNo >= firstLine
+           && m_cursorLineNo < firstLine + pageSize) {
+               ReParagraph* cursorPara = cursorParagraph();
+               int col = max(m_cursorCol, cursorPara->m_columns - 1);
+               col = indexToColumn(col, m_tabWidth, m_lines->lineAt(m_cursorLineNo))
+                   - m_firstCol;
                int x = rect.left() + m_widthLineNo + 1
-                       + (col + 1) * lookStd->m_metrics->width('x');
-               int y = rect.top() + (m_cursorLine - firstLine) * lineHeight;
+                   + (col + 1) * lookStd->m_metrics->width('x');
+               int y = rect.top() + (m_cursorLineNo - firstLine) * lineHeight;
                painter.setPen(*look->m_pen);
                painter.drawLine(x, y, x, y + lineHeight);
        }
-       int maxWidth = max(1, m_maxLineLength);
-       int width = (rect.width() - m_widthLineNo - m_widthVScrollBar)
-               / m_standardMetrics->width('x');
        int maxLines = max(1, m_lines->lineCount() - pageSize);
        drawScrollbars(painter, rect, double(pageSize) / maxLines,
-               double(m_firstLine) / maxLines, double(width) / maxWidth, 0.0);
+           double(m_firstLine) / maxLines,
+           m_maxCols == 0 ? 1.0 : (double) m_screenWidth / m_maxCols,
+           m_maxCols == 0 ? 0.0 : (double) m_firstCol / m_maxCols);
        ReLogger::globalLogger()->logv(LOG_INFO, 3, "draw: %.4f",
-               double(clock() - start) / CLOCKS_PER_SEC);
+           double(clock() - start) / CLOCKS_PER_SEC);
 }
 
 /**
@@ -614,14 +635,23 @@ void ReEdit::paintEvent(QPaintEvent* event) {
  *
  * @param firstLine    number of the line which should be visible
  */
-void ReEdit::reposition(int firstLine) {
-       int pageSize = m_list.length();
-       if (firstLine <= 0)
-               firstLine = 0;
-       else if (firstLine >= m_lines->lineCount() - pageSize)
-               firstLine = m_lines->lineCount() - pageSize + 1;
-       // We do not load because each redraw loads it:
-       m_firstLine = firstLine;
+void ReEdit::reposition(int firstLine, int firstCol) {
+       if (firstLine != m_firstLine) {
+               int pageSize = m_list.length();
+               if (firstLine <= 0)
+                       firstLine = 0;
+               else if (firstLine >= m_lines->lineCount() - pageSize)
+                       firstLine = m_lines->lineCount() - pageSize + 1;
+               // We do not load because each redraw loads it:
+               m_firstLine = firstLine;
+       }
+       if (firstCol != m_firstCol) {
+               if (firstCol < 0)
+                       firstCol = 0;
+               else if (firstCol > m_maxCols - m_screenWidth)
+                       firstCol = max(0, m_maxCols - m_screenWidth);
+               m_firstCol = firstCol;
+       }
 }
 
 /**
@@ -629,7 +659,7 @@ void ReEdit::reposition(int firstLine) {
  * @param cursorLine    the line number [0..N-1]
  */
 void ReEdit::setCursorLine(int cursorLine) {
-       m_cursorLine = cursorLine;
+       m_cursorLineNo = cursorLine;
 }
 
 /**
@@ -657,15 +687,16 @@ void ReEdit::setTabStrings(int tabWidth) {
  * Constructor.
  */
 ReParagraphs::ReParagraphs() :
-               m_builders(),
-               m_firstLine(0),
-               m_firstCol(0),
-               m_cursorLine(0),
-               m_cursorCol(-1),
-               m_lines(NULL),
-               m_list(),
-               m_maxLineLength(0),
-               m_cursorVisible(true) {
+           m_builders(),
+           m_firstLine(0),
+           m_firstCol(0),
+           m_cursorLineNo(0),
+           m_cursorCol(-1),
+           m_lines(NULL),
+           m_list(),
+           m_cursorVisible(true),
+           m_maxCols(0),
+           m_screenWidth(0) {
 }
 
 /**
@@ -679,7 +710,7 @@ ReParagraphs::~ReParagraphs() {
  * Makes the list empty and frees the resources.
  */
 void ReParagraphs::clear() {
-       m_maxLineLength = 0;
+       m_maxCols = 0;
        for (int ix = m_list.length() - 1; ix >= 0; ix--) {
                ReParagraph* current = m_list.at(ix);
                delete current;
@@ -707,20 +738,20 @@ void ReParagraphs::clear() {
  *                                     expanded tabs
  */
 int ReParagraphs::columnToIndex(int column, int tabWidth,
-       const QString& string) {
+    const QString& string) {
        int rc = 0;
        if (column < 0)
                rc = -1;
        else {
                int cursor = 0;
                int length = string.length();
-               while(rc < length - 1 && cursor < column) {
+               while (rc < length - 1 && cursor < column) {
                        rc++;
                        if (string.at(rc) != m_tabChar)
                                cursor++;
                        else {
                                cursor += tabWidth - 1 - (cursor % tabWidth);
-                               if (cursor >= column){
+                               if (cursor >= column) {
                                        break;
                                }
                        }
@@ -734,11 +765,11 @@ int ReParagraphs::columnToIndex(int column, int tabWidth,
  *
  * @return the cursor line
  */
-ReParagraph* ReParagraphs::cursorLine() {
+ReParagraph* ReParagraphs::cursorParagraph() {
        ReParagraph* rc = NULL;
-       if (m_cursorLine >= m_firstLine
-               && m_cursorLine < m_firstLine + m_list.length()) {
-               rc = m_list.at(m_cursorLine - m_firstLine);
+       if (m_cursorLineNo >= m_firstLine
+           && m_cursorLineNo < m_firstLine + m_list.length()) {
+               rc = m_list.at(m_cursorLineNo - m_firstLine);
        }
        return rc;
 }
@@ -750,7 +781,8 @@ ReParagraph* ReParagraphs::cursorLine() {
  * @return              the index of the content string
  */
 int ReParagraphs::columnToIndex(int cursorCol) {
-       int rc = columnToIndex(cursorCol, m_tabWidth, m_lines->lineAt(m_cursorLine));
+       int rc = columnToIndex(cursorCol, m_tabWidth,
+           m_lines->lineAt(m_cursorLineNo));
        return rc;
 }
 
@@ -788,7 +820,7 @@ void ReParagraphs::draw(QPainter& painter, int top, int left) {
  * @return
  */
 int ReParagraphs::indexToColumn(int index, int tabWidth,
-       const QString& string) {
+    const QString& string) {
        int rc = 0;
        if (index >= 0) {
                int length = string.length();
@@ -812,7 +844,7 @@ int ReParagraphs::indexToColumn(int index, int tabWidth,
  * @return      the column in the edit field
  */
 int ReParagraphs::indexToColumn(int index) {
-       int rc = indexToColumn(index, m_tabWidth, m_lines->lineAt(m_cursorLine));
+       int rc = indexToColumn(index, m_tabWidth, m_lines->lineAt(m_cursorLineNo));
        return rc;
 }
 
@@ -821,19 +853,19 @@ int ReParagraphs::indexToColumn(int index) {
  *
  * @param lineNo    the line number of the first line to transfer
  * @param count     the number of lines to transfer
+ * @param width                width of the screen (in chars)
  */
-void ReParagraphs::load(int lineNo, int count, ReEdit* edit) {
+void ReParagraphs::load(int lineNo, int count, int width, ReEdit* edit) {
        clear();
-       m_maxLineLength = 0;
+       m_maxCols = 0;
        m_firstLine = lineNo;
+       m_screenWidth = width;
        for (int ix = lineNo; ix < lineNo + count; ix++) {
                ReParagraph* para = new ReParagraph();
                m_list.append(para);
                for (int builder = 0; builder < m_builders.length(); builder++)
                        m_builders.at(builder)->buildParagraph(*para, ix, edit);
-               int current = para->m_columns;
-               if (current > m_maxLineLength)
-                       m_maxLineLength = current;
+               m_maxCols = max(m_maxCols, para->m_columns);
        }
 }
 
@@ -851,43 +883,69 @@ void ReParagraphs::setLines(ReLines* lines) {
  *
  * @param paragraph the paragraph to change
  * @param lineNo    the line number (0..N-1) of the paragraph in the source
+ * @param firstCol     the first column of the text (with expanded tabulators)
  * @param edit      the parent, the edit field
  */
 void ReParagraphBuilder::buildParagraph(ReParagraph& paragraph, int lineNo,
-ReEdit* edit) {
-if (paragraph.length() == 0) {
-       const QString& text = edit->lines().lineAt(lineNo);
-       ReLook* look = edit->lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD);
-       ReLook* lookTab = edit->lookOf(ReLook::FG_GREY_LIGHT, ReLook::BG_STANDARD);
-       paragraph.m_columns = 0;
-       int ixTab;
-       ReEditText* part;
-       int start = 0;
-       while ((ixTab = text.indexOf('\t', start)) >= 0) {
-               if (ixTab > start) {
-                       part = new ReEditText(text.mid(start, ixTab - start), look);
-                       paragraph.append(part);
-                       paragraph.m_columns += ixTab - start;
+    ReEdit* edit) {
+       if (paragraph.length() == 0) {
+               int firstCol = edit->m_firstCol;
+               const QString& text = edit->lines().lineAt(lineNo);
+               ReLook* look = edit->lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD);
+               ReLook* lookTab = edit->lookOf(ReLook::FG_GREY_LIGHT,
+                   ReLook::BG_STANDARD);
+               paragraph.m_columns = 0;
+               int ixTab;
+               ReEditText* part;
+               int start = 0;
+               int cursor = 0;
+               int length, length2, start2;
+               int maxCol = edit->m_maxCols;
+               while ((ixTab = text.indexOf('\t', start)) >= 0) {
+                       if (ixTab > start) {
+                               length = ixTab - start;
+                               if (cursor + length > firstCol && cursor < maxCol) {
+                                       start2 = start;
+                                       length2 = length;
+                                       if (cursor < firstCol) {
+                                               start2 -= firstCol - cursor;
+                                               length2 -= firstCol - cursor;
+                                       }
+                                       part = new ReEditText(text.mid(start2, length2), look);
+                                       paragraph.append(part);
+                               }
+                               cursor += length;
+                       }
+                       QString tabs = ReEdit::tabString(cursor + 1);
+                       length = tabs.length();
+                       if (cursor + length > firstCol && cursor < maxCol) {
+                               if (cursor < firstCol)
+                                       tabs = tabs.mid(0, length - firstCol - cursor);
+                               paragraph.append(new ReEditText(tabs, lookTab));
+                       }
+                       cursor += length;
+                       start = ixTab + 1;
                }
-               paragraph.append(
-                       new ReEditText(ReEdit::tabString(paragraph.m_columns + 1),
-                               lookTab));
-               start = ixTab + 1;
+               if (cursor < firstCol) {
+                       start2 = start + (firstCol - cursor);
+                       cursor += text.length() - start;
+                       part = new ReEditText(text.mid(start2), look);
+               } else {
+                       cursor += text.length() - start;
+                       part = new ReEditText(start == 0 ? text : text.mid(start), look);
+               }
+               paragraph.m_columns = cursor;
+               paragraph.append(part);
        }
-
-       part = new ReEditText(start == 0 ? text : text.mid(start), look);
-       paragraph.m_columns += part->text().length();
-       paragraph.append(part);
-}
 }
 
 /**
  * Destructor.
  */
 ReParagraph::~ReParagraph() {
-for (int ix = length() - 1; ix >= 0; ix--)
-       delete at(ix);
-clear();
+       for (int ix = length() - 1; ix >= 0; ix--)
+               delete at(ix);
+       clear();
 }
 
 /**
@@ -900,47 +958,47 @@ clear();
  * @param left      the starting x position (left hand)
  */
 void ReParagraph::draw(QPainter& painter, int& top, int left) {
-int x = left;
-QFontMetrics* metrics = at(0)->look()->m_metrics;
-x += metrics->width('x') / 2;
-int height = metrics->height();
-int y = top + height - metrics->descent();
-top += heightToFullHeight(height);
-for (int ix = 0; ix < length(); ix++) {
-       ReEditText* current = at(ix);
-       ReLook* look = current->look();
-       painter.setFont(*look->m_font);
-       const ReLook::ForeGround fg = look->m_foreground;
-       QPen pen(*look->m_edit->foregroundColors()[fg]);
-       painter.setPen(pen);
-       painter.drawText(x, y, current->text());
-       x += metrics->width(current->text());
-}
+       int x = left;
+       QFontMetrics* metrics = at(0)->look()->m_metrics;
+       x += metrics->width('x') / 2;
+       int height = metrics->height();
+       int y = top + height - metrics->descent();
+       top += heightToFullHeight(height);
+       for (int ix = 0; ix < length(); ix++) {
+               ReEditText* current = at(ix);
+               ReLook* look = current->look();
+               painter.setFont(*look->m_font);
+               const ReLook::ForeGround fg = look->m_foreground;
+               QPen pen(*look->m_edit->foregroundColors()[fg]);
+               painter.setPen(pen);
+               painter.drawText(x, y, current->text());
+               x += metrics->width(current->text());
+       }
 }
 
 /**
  * Constructor.
  */
 ReMouseCatcher::ReMouseCatcher() :
-       m_clickObjects(),
-       m_vScrollBar(new ClickPosition(CO_VSCROLLBAR)),
-       m_hScrollBar(new ClickPosition(CO_HSCROLLBAR)),
-       m_hSlider(new ClickPosition(CO_HSLIDER)),
-       m_vSlider(new ClickPosition(CO_VSLIDER)),
-       m_lastMousePosition(),
-       m_lastTopVSlider(0),
-       m_lastLeftHSlider(0) {
+           m_clickObjects(),
+           m_vScrollBar(new ClickPosition(CO_VSCROLLBAR)),
+           m_hScrollBar(new ClickPosition(CO_HSCROLLBAR)),
+           m_hSlider(new ClickPosition(CO_HSLIDER)),
+           m_vSlider(new ClickPosition(CO_VSLIDER)),
+           m_lastMousePosition(),
+           m_lastTopVSlider(0),
+           m_lastLeftHSlider(0) {
 
 }
 /**
  * Destructor.
  */
 ReMouseCatcher::~ReMouseCatcher() {
-delete m_vScrollBar;
-delete m_hScrollBar;
-delete m_vSlider;
-delete m_vSlider;
-m_vScrollBar = m_hScrollBar = m_vSlider = m_hSlider = NULL;
+       delete m_vScrollBar;
+       delete m_hScrollBar;
+       delete m_vSlider;
+       delete m_hSlider;
+       m_vScrollBar = m_hScrollBar = m_vSlider = m_hSlider = NULL;
 }
 
 /**
@@ -949,8 +1007,8 @@ m_vScrollBar = m_hScrollBar = m_vSlider = m_hSlider = NULL;
  * @param object    the object to insert.
  */
 void ReMouseCatcher::insertClickObject(ReMouseCatcher::ClickPosition* object) {
-if (!m_clickObjects.contains(object))
-       m_clickObjects.append(object);
+       if (!m_clickObjects.contains(object))
+               m_clickObjects.append(object);
 }
 
 /**
@@ -962,13 +1020,27 @@ if (!m_clickObjects.contains(object))
  * @return      <code>true</code>: the mouse click is inside the horizontal sb
  */
 bool ReMouseCatcher::handleHScrollBar(QMouseEvent* event, bool isDragged,
-ReEdit* edit) {
-QPoint pos = event->pos();
-bool rc = rectContains(*m_hScrollBar, pos, "hScrollBar");
-if (rc) {
-
-}
-return rc;
+    ReEdit* edit) {
+       QPoint pos = event->pos();
+       bool rc = rectContains(*m_hScrollBar, pos, "hScrollBar");
+       if (rc) {
+               if (isDragged) {
+                       int distance = pos.x() - m_lastMousePosition.x();
+                       int sliderPos = m_lastLeftHSlider + distance;
+                       int moveGap = m_hScrollBar->width() - m_hSlider->width();
+                       double position = moveGap == 0 ? 0.0 : double(sliderPos) / moveGap;
+                       int col = roundInt(
+                           (edit->m_maxCols - edit->m_screenWidth)
+                               * max(0.0, min(position, 1.0)));
+                       edit->reposition(edit->m_cursorLineNo, col);
+               } else {
+                       if (pos.y() < m_hSlider->left())
+                               edit->editorAction(ReEdit::EA_PAGE_LEFT);
+                       else if (pos.y() > m_hSlider->right())
+                               edit->editorAction(ReEdit::EA_PAGE_RIGHT);
+               }
+       }
+       return rc;
 }
 
 /**
@@ -980,27 +1052,27 @@ return rc;
  * @return          <code>true</code>: the mouse click is inside the vertical sb
  */
 bool ReMouseCatcher::handleVScrollBar(QMouseEvent* event, bool isDragged,
-ReEdit* edit) {
-QPoint pos = event->pos();
-bool rc = rectContains(*m_vScrollBar, pos, "vScrollBar")
-       || (isDragged && m_vScrollBar->contains(m_lastMousePosition));
-if (rc) {
-       if (isDragged) {
-               int distance = pos.y() - m_lastMousePosition.y();
-               int sliderPos = m_lastTopVSlider + distance;
-               double position = double(sliderPos)
-                       / (m_vScrollBar->height() - m_vSlider->height());
-               int line = roundInt(
-                       (edit->lines().lineCount() - edit->pageSize())
-                               * max(0.0, min(position, 1.0)));
-               edit->reposition(line);
-       } else {
-               if (pos.y() < m_vSlider->top())
-                       edit->editorAction(ReEdit::EA_PAGE_UP);
-               else if (pos.y() > m_vSlider->bottom())
-                       edit->editorAction(ReEdit::EA_PAGE_DOWN);
+    ReEdit* edit) {
+       QPoint pos = event->pos();
+       bool rc = rectContains(*m_vScrollBar, pos, "vScrollBar")
+           || (isDragged && m_vScrollBar->contains(m_lastMousePosition));
+       if (rc) {
+               if (isDragged) {
+                       int distance = pos.y() - m_lastMousePosition.y();
+                       int sliderPos = m_lastTopVSlider + distance;
+                       int moveGap = m_vScrollBar->height() - m_vSlider->height();
+                       double position = moveGap == 0 ? 0.0 : double(sliderPos) / moveGap;
+                       int line = roundInt(
+                           (edit->lines().lineCount() - edit->pageSize())
+                               * max(0.0, min(position, 1.0)));
+                       edit->reposition(line, edit->m_cursorCol);
+               } else {
+                       if (pos.y() < m_vSlider->top())
+                               edit->editorAction(ReEdit::EA_PAGE_UP);
+                       else if (pos.y() > m_vSlider->bottom())
+                               edit->editorAction(ReEdit::EA_PAGE_DOWN);
+               }
        }
-}
-return rc;
+       return rc;
 }
 
index 81d6a6cdcc224d0dc7efd1b11ce488fa90b0896c..591c58b2a9e9d930a9b96333f90369cde395b090 100644 (file)
@@ -85,8 +85,8 @@ public:
         * @param source    source to copy
         */
        inline ReEditText(const ReEditText& source) :
-                       m_text(source.m_text),
-                       m_look(source.m_look) {
+                   m_text(source.m_text),
+                   m_look(source.m_look) {
        }
        /** Assignment operator.
         * @param source    source to copy
@@ -146,14 +146,14 @@ public:
 class ReParagraphBuilder {
 public:
        virtual void buildParagraph(ReParagraph& paragraph, int lineNo,
-               ReEdit* edit);
+           ReEdit* edit);
 };
 
 class ReCursortLineBuilder: public ReParagraphBuilder {
        // ReParagraphBuilder interface
 public:
        virtual void buildParagraph(ReParagraph& paragraph, int lineNo,
-               ReEdit* edit);
+           ReEdit* edit);
 };
 
 /**
@@ -164,6 +164,8 @@ public:
  * and a search engine paints up the last hits of the search.
  */
 class ReParagraphs {
+       friend class ReParagraphBuilder;
+       friend class ReMouseCatcher;
 public:
        ReParagraphs();
        virtual ~ReParagraphs();
@@ -175,7 +177,7 @@ public:
                m_builders.append(builder);
        }
        void clear();
-       ReParagraph* cursorLine();
+       ReParagraph* cursorParagraph();
        void draw(QPainter& painter, int top, int left);
        int columnToIndex(int cursorCol);
        /** Returns the paragraph with a given index from the list.
@@ -186,7 +188,7 @@ public:
        virtual ReParagraph* lineAt(int ix) {
                return ix < 0 || ix >= m_list.length() ? NULL : m_list.at(ix);
        }
-       void load(int lineNo, int count, ReEdit* edit);
+       void load(int lineNo, int count, int width, ReEdit* edit);
        int indexToColumn(int index);
 
 public:
@@ -200,13 +202,14 @@ protected:
        int m_firstLine;
        /// the first visible column (horizontal scrolling)
        int m_firstCol;
-       /// the number of the line containing the insertion cursor (0..N-1)
-       int m_cursorLine;
-       /// the column of the insertion cursor (0..N-1)
+       /// the file line number containing the insertion cursor (0..N-1)
+       int m_cursorLineNo;
+       /// the file line column of the insertion cursor (0..N-1)
        int m_cursorCol;
        ReLines* m_lines;
        QList<ReParagraph*> m_list;
-       int m_maxLineLength;
+       int m_maxCols;
+       int m_screenWidth;
        /// true: the text cursor is visible (blinking)
        bool m_cursorVisible;
 protected:
@@ -231,10 +234,10 @@ public:
        class ClickPosition: public QRect {
        public:
                ClickPosition(ClickObjType type) :
-                               QRect(0, 0, 0, 0),
-                               m_type(type),
-                               m_title(),
-                               m_object(NULL) {
+                           QRect(0, 0, 0, 0),
+                           m_type(type),
+                           m_title(),
+                           m_object(NULL) {
                }
        public:
                bool operator <(const ClickPosition& op) {
@@ -291,17 +294,21 @@ public:
                EA_DEL_LINE,
                EA_UNDO,
                EA_REDO,
+               EA_VIEW_LEFT,
+               EA_VIEW_RIGHT,
+               EA_PAGE_LEFT,
+               EA_PAGE_RIGHT,
        };
 public:
        explicit ReEdit(QWidget *parent = 0);
 public:
        void assignColorsStandard();
        void assignKeysStandard();
-       int cursorLine() const;
+       int cursorLineNo() const;
        void editorAction(EditorAction action);
        ReLines& lines();
        ReLook* lookOf(ReLook::ForeGround foreground,
-               ReLook::BackGround background);
+           ReLook::BackGround background);
        /** Returns the current page size.
         * return    number of visible lines in the edit field
         */
@@ -309,8 +316,8 @@ public:
        int pageSize() {
                return m_list.length();
        }
-       void reposition(int firstLine);
-       void setCursorLine(int cursorLine);
+       void reposition(int firstLine, int firstCol);
+       void setCursorLine(int cursorParagraph);
        /** Returns the array of the foreground colors.
         * @return the array of the foreground colors
         */
@@ -326,9 +333,9 @@ public:
 protected:
        QBrush* createBrush(ReLook::BackGround background);
        void drawScrollbars(QPainter& painter, const QRect& rect,
-               double sizeVertical, double posVertical, double sizeHorizontal,
-               double posHorizontal);
-       void ensureCursorVisible(int cursorLine = -1);protected slots:
+           double sizeVertical, double posVertical, double sizeHorizontal,
+           double posHorizontal);
+       void ensureCursorVisible(int cursorParagraph = -1);protected slots:
        void keyPressEvent(QKeyEvent* event);
        void paintEvent(QPaintEvent *);
        void mouseMoveEvent(QMouseEvent* event);