From d370ca946f82989382e1abf60b06707815b2900c Mon Sep 17 00:00:00 2001 From: hama Date: Sun, 19 Jul 2015 08:40:45 +0200 Subject: [PATCH] horizontal scrolling works (mostly) --- gui/ReEdit.cpp | 520 ++++++++++++++++++++++++++++--------------------- gui/ReEdit.hpp | 49 +++-- 2 files changed, 324 insertions(+), 245 deletions(-) diff --git a/gui/ReEdit.cpp b/gui/ReEdit.cpp index f786174..3ef6213 100644 --- a/gui/ReEdit.cpp +++ b/gui/ReEdit.cpp @@ -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* 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 true: 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 true: 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; } diff --git a/gui/ReEdit.hpp b/gui/ReEdit.hpp index 81d6a6c..591c58b 100644 --- a/gui/ReEdit.hpp +++ b/gui/ReEdit.hpp @@ -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 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); -- 2.39.5