From d291df9cf06ac71b8326ab4d8e9812562460ee5f Mon Sep 17 00:00:00 2001 From: hama Date: Tue, 30 Jun 2015 00:24:30 +0200 Subject: [PATCH] Refactoring: ReParagraphs as base class of ReEdit --- gui/ReEdit.cpp | 731 +++++++++++++++++++++++++++---------------------- gui/ReEdit.hpp | 81 ++---- 2 files changed, 417 insertions(+), 395 deletions(-) diff --git a/gui/ReEdit.cpp b/gui/ReEdit.cpp index 32e97d2..927605b 100644 --- a/gui/ReEdit.cpp +++ b/gui/ReEdit.cpp @@ -13,10 +13,10 @@ #include "gui/regui.hpp" #include -QStringList ReEdit::m_tabStrings; +QStringList ReParagraphs::m_tabStrings; // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -QChar ReEdit::m_tabChar = QChar(0xBB); -int ReEdit::m_tabWidth = 3; +QChar ReParagraphs::m_tabChar = QChar(0xBB); +int ReParagraphs::m_tabWidth = 3; /** * Calculates the full line height (with gap between lines) @@ -101,12 +101,6 @@ void ReCursortLineBuilder::buildParagraph(ReParagraph& paragraph, int lineNo, ReEdit::ReEdit(QWidget* parent) : QWidget(parent), ReMouseCatcher(), - m_paragraphs(), - m_firstLine(0), - m_firstCol(0), - m_cursorLine(0), - m_cursorCol(-1), - m_cursorVisible(true), m_widthEdit(0), m_heightEdit(0), m_insertMode(true), @@ -114,7 +108,6 @@ ReEdit::ReEdit(QWidget* parent) : m_widthLineNo(50), m_widthVScrollBar(10), m_heightHScrollBar(10), - m_lines(NULL), m_looks(), m_standardBrush(new QBrush(Qt::SolidPattern)), m_scrollbarBrush(new QBrush(Qt::SolidPattern)), @@ -147,8 +140,8 @@ ReEdit::ReEdit(QWidget* parent) : assignColorsStandard(); setTabStrings(3); - m_paragraphs.appendBuilder(new ReParagraphBuilder()); - m_paragraphs.appendBuilder(new ReCursortLineBuilder()); + appendBuilder(new ReParagraphBuilder()); + appendBuilder(new ReCursortLineBuilder()); assignKeysStandard(); } void ReEdit::assignColorsStandard(){ @@ -213,111 +206,6 @@ void ReEdit::assignKeysStandard(){ } -/** - * Returns a look with the given specifications. - * - * @param foreground the symbolic name of the foreground - * @param background the symbolic name of the background - * @return - */ -ReLook* ReEdit::lookOf(ReLook::ForeGround foreground, - ReLook::BackGround background){ - int index = foreground * ReLook::BG_COUNT + background; - ReLook* rc = m_looks[index]; - if (rc == NULL){ - rc = m_looks[index] = new ReLook(); - rc->m_edit = this; - rc->m_foreground = foreground; - rc->m_background = background; - rc->m_brush = createBrush(background); - if (foreground != ReLook::FG_CURRENT_LINE) - rc->m_font = m_standardFont; - else{ - rc->m_font = new QFont(*m_standardFont); - rc->m_font->setBold(true); - } - rc->m_metrics = m_standardMetrics; - rc->m_pen = new QPen(*m_standardPen); - rc->m_pen->setColor(*m_fontColors[foreground]); - } - return rc; -} -/** - * Creates a brush with a given color. - * - * @param background the symbolic background color - * @return an new created instance of a brush - */ -QBrush* ReEdit::createBrush(ReLook::BackGround background){ - QBrush* rc = new QBrush(); - *rc = *m_standardBrush; - rc->setColor(*m_brushColors[background]); - return rc; -} -/** - * Draw the edit field. - * - * @param event the trigger event - */ -void ReEdit::paintEvent(QPaintEvent* event){ - clock_t start = clock(); - QRect rect = event->rect(); - m_widthEdit = rect.width(); - m_heightEdit = rect.height(); - int lineHeight = heightToFullHeight(m_standardMetrics->height()); - int pageSize = (rect.height() - m_heightHScrollBar) / lineHeight; - int firstLine = m_paragraphs.firstLine(); - m_paragraphs.load(firstLine, pageSize, 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); - painter.drawRect(editArea); - m_paragraphs.draw(painter, rect.top(), rect.left() + m_widthLineNo); - int left = rect.left() + m_widthLineNo - 3; - left = rect.left(); - int y = 0; - int lineNo = firstLine + 1; - ReLook* lookStd = lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD); - for (int ix = 0; ix < m_paragraphs.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; - int width = look->m_metrics->width(number); - if (ix == 0) - y = rect.top() + look->m_metrics->height() - - 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; - int x = rect.left() + m_widthLineNo + 1 - + (col + 1) * lookStd->m_metrics->width('x'); - int y = rect.top() + (m_cursorLine - firstLine) * lineHeight; - painter.setPen(*look->m_pen); - painter.drawLine(x, y, x, y + lineHeight); - } - int maxWidth = max(1, m_paragraphs.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_paragraphs.firstLine()) / maxLines, double(width) / maxWidth, - 0.0); - ReLogger::globalLogger()->logv(LOG_INFO, 3, "draw: %.4f", - double(clock() - start) / CLOCKS_PER_SEC); -} - /** * Calculates the size/position of a slider from a relative value [0..1]. * @param size the size of the scrollbar (width/height for horiz/vert bar) @@ -339,6 +227,28 @@ void calcSliderSize(int size, int minSize, double sizeFactor, double posFactor, position = roundInt((size - length) * posFactor); } +/** + * Creates a brush with a given color. + * + * @param background the symbolic background color + * @return an new created instance of a brush + */ +QBrush* ReEdit::createBrush(ReLook::BackGround background){ + QBrush* rc = new QBrush(); + *rc = *m_standardBrush; + rc->setColor(*m_brushColors[background]); + return rc; +} + +/** + * Returns the line number of the cursor line. + * + * @return the line number [0..N-1] + */ +int ReEdit::cursorLine() const{ + return m_cursorLine; +} + /** * Draws the scrollbars. * @@ -382,92 +292,87 @@ void ReEdit::drawScrollbars(QPainter& painter, const QRect& rect, rect.bottom() - m_heightHScrollBar, sliderSize, m_heightHScrollBar); painter.drawRect(*m_hSlider); } -/** - * Handles the event when a drag action is done - * @param event - */ -void ReEdit::mouseMoveEvent(QMouseEvent* event){ - if (m_lastMousePosition.x() >= 0 - && (handleHScrollBar(event, true, this) - || handleVScrollBar(event, true, this))){ - emit repaint(); - } -} /** - * Handles the mouse click event. + * Does an editor action. * - * @param event the description of the mouse click + * @param action action to do */ -void ReEdit::mousePressEvent(QMouseEvent* event){ - if (handleVScrollBar(event, false, this)){ - - }else if (handleHScrollBar(event, false, this)){ - - }else{ - QPoint position = event->pos(); - m_cursorLine = position.y() - / heightToFullHeight(m_standardMetrics->height()) - + m_paragraphs.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; - } +void ReEdit::editorAction(ReEdit::EditorAction action){ + int pageSize = m_list.length() - 1; + switch (action) { + case EA_UNDEF: + break; + case EA_CHAR_LEFT: + if (m_cursorCol-- < -1) + m_cursorCol = -1; + ensureCursorVisible(); + break; + case EA_CHAR_RIGHT: + if (++m_cursorCol >= m_lines->lineAt(m_cursorLine).length()) + m_cursorCol = m_lines->lineAt(m_cursorLine).length() - 1; + ensureCursorVisible(); + break; + case EA_LINE_UP: + if (--m_cursorLine < 0) + m_cursorLine = 0; + ensureCursorVisible(); + break; + case EA_LINE_DOWN: + if (++m_cursorLine >= m_lines->lineCount()) + m_cursorLine = m_lines->lineCount() - 1; + ensureCursorVisible(); + break; + case EA_BEGIN_OF_LINE: + m_cursorCol = -1; + ensureCursorVisible(); + break; + case EA_END_OF_LINE: + m_cursorCol = m_lines->lineAt(m_cursorLine).length() - 1; + ; + ensureCursorVisible(); + break; + case EA_BEGIN_OF_FILE: + ensureCursorVisible(0); + break; + case EA_END_OF_FILE: + ensureCursorVisible(m_lines->lineCount() - 1); + break; + case EA_PAGE_UP: + // Do not change cursor line! + reposition(m_firstLine - pageSize); + break; + case EA_PAGE_DOWN: + // Do not change cursor line! + reposition(m_firstLine + pageSize); + break; + case EA_DEL_CHAR: + break; + case EA_BACKSPACE: + break; + case EA_DEL_END_OF_LINE: + break; + case EA_DEL_BEGIN_OF_LINE: + break; + case EA_DEL_LINE: + break; + default: + break; } - m_lastMousePosition = event->pos(); - m_lastTopVSlider = m_vSlider->top(); - m_lastLeftHSlider = m_hSlider->left(); emit repaint(); } /** - * Handles the mouse click event. - * - * @param event the description of the mouse click - */ -void ReEdit::mouseReleaseEvent(QMouseEvent* event){ - m_lastMousePosition.setX(-1); -} - -/** - * Calculates the index of the line string from the cursor column. - * - * The index may be smaller because of expanded tabulators. - * Example: - *
"x\ty", tabulator width: 3, screen display: "x  y"
- * columnToTextIndex(0) == 0; ('x')
- * columnToTextIndex(1) == 1; ('\t')
- * columnToTextIndex(2) == 1; ('\t')
- * columnToTextIndex(3) == 2; ('y')
- * 
- * - * @param cursorCol the cursor position - * @return the - */ -int ReEdit::columnToTextIndex(int cursorCol){ - //@ToDo: tab handling - return cursorCol; -} -/** - * Calculates the cursor column from the line string index. + * Ensures that the cursor line is visible. * - * The index may be larger because of expanded tabulators. - * Example: - *
"x\ty", tabulator width: 3, screen display: "x  y"
- * textIndexToColumn(0) == 0;
- * textIndexToColumn(1) == 1;
- * textIndexToColumn(2) == 3;
- * 
- * @param index the index in the line string - * @return the column in the edit field + * @param cursorLine -1 or number of the new cursor line */ -int ReEdit::textIndexToColumn(int index){ - //@ToDo: tab handling - return index; +void ReEdit::ensureCursorVisible(int cursorLine){ + if (cursorLine >= 0) + m_cursorLine = cursorLine; + if (m_cursorLine < m_firstLine || m_cursorLine >= m_firstLine + pageSize()){ + reposition(m_cursorLine); + } } /** @@ -527,117 +432,159 @@ void ReEdit::keyPressEvent(QKeyEvent* event){ } emit repaint(); } + /** - * Calculates the tabulator expanding strings. + * Returns the text source of the instance. * - * Example (tab width = 3): - *
- *   "\tz" -> '   z' -> '\t' + '  '
- *  "x\tz" -> 'x  z' -> '\t' + ' '
- * "xy\tz" -> 'xy z' -> '\t'
- * 
- * @param tabWidth + * @return the text source */ -void ReEdit::setTabStrings(int tabWidth){ - m_tabWidth = tabWidth; - m_tabStrings.clear(); - QString blanks; - blanks.fill(' ', tabWidth); - for (int ix = 0; ix < tabWidth - 1; ix++){ - m_tabStrings.append(m_tabChar + blanks.mid(0, tabWidth - 1 - ix)); +ReLines& ReEdit::lines(){ + if (m_lines == NULL) + m_lines = new ReLines(); + return *m_lines; +} + +/** + * Returns a look with the given specifications. + * + * @param foreground the symbolic name of the foreground + * @param background the symbolic name of the background + * @return + */ +ReLook* ReEdit::lookOf(ReLook::ForeGround foreground, + ReLook::BackGround background){ + int index = foreground * ReLook::BG_COUNT + background; + ReLook* rc = m_looks[index]; + if (rc == NULL){ + rc = m_looks[index] = new ReLook(); + rc->m_edit = this; + rc->m_foreground = foreground; + rc->m_background = background; + rc->m_brush = createBrush(background); + if (foreground != ReLook::FG_CURRENT_LINE) + rc->m_font = m_standardFont; + else{ + rc->m_font = new QFont(*m_standardFont); + rc->m_font->setBold(true); + } + rc->m_metrics = m_standardMetrics; + rc->m_pen = new QPen(*m_standardPen); + rc->m_pen->setColor(*m_fontColors[foreground]); + } + return rc; +} +/** + * Handles the event when a drag action is done + * @param event + */ +void ReEdit::mouseMoveEvent(QMouseEvent* event){ + if (m_lastMousePosition.x() >= 0 + && (handleHScrollBar(event, true, this) + || handleVScrollBar(event, true, this))){ + emit repaint(); + } +} + +/** + * Handles the mouse click event. + * + * @param event the description of the mouse click + */ +void ReEdit::mousePressEvent(QMouseEvent* event){ + if (handleVScrollBar(event, false, this)){ + + }else if (handleHScrollBar(event, false, this)){ + + }else{ + QPoint position = event->pos(); + m_cursorLine = 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_lastMousePosition = event->pos(); + m_lastTopVSlider = m_vSlider->top(); + m_lastLeftHSlider = m_hSlider->left(); + emit repaint(); } /** - * Returns the line number of the cursor line. + * Handles the mouse click event. * - * @return the line number [0..N-1] + * @param event the description of the mouse click */ -int ReEdit::cursorLine() const{ - return m_cursorLine; +void ReEdit::mouseReleaseEvent(QMouseEvent* event){ + m_lastMousePosition.setX(-1); } /** - * Ensures that the cursor line is visible. + * Draw the edit field. * - * @param cursorLine -1 or number of the new cursor line + * @param event the trigger event */ -void ReEdit::ensureCursorVisible(int cursorLine){ - if (cursorLine >= 0) - m_cursorLine = cursorLine; - int firstLine = m_paragraphs.firstLine(); - if (m_cursorLine < firstLine || m_cursorLine >= firstLine + pageSize()){ - reposition(m_cursorLine); +void ReEdit::paintEvent(QPaintEvent* event){ + clock_t start = clock(); + QRect rect = event->rect(); + m_widthEdit = rect.width(); + m_heightEdit = rect.height(); + int lineHeight = heightToFullHeight(m_standardMetrics->height()); + int pageSize = (rect.height() - m_heightHScrollBar) / lineHeight; + int firstLine = m_firstLine; + load(firstLine, pageSize, 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); + painter.drawRect(editArea); + draw(painter, rect.top(), rect.left() + m_widthLineNo); + int left = rect.left() + m_widthLineNo - 3; + left = rect.left(); + int y = 0; + int lineNo = firstLine + 1; + ReLook* lookStd = lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD); + 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; + int width = look->m_metrics->width(number); + if (ix == 0) + y = rect.top() + look->m_metrics->height() + - 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; } -} - -/** - * Does an editor action. - * - * @param action action to do - */ -void ReEdit::editorAction(ReEdit::EditorAction action){ - int pageSize = m_paragraphs.list().length() - 1; - switch (action) { - case EA_UNDEF: - break; - case EA_CHAR_LEFT: - if (m_cursorCol-- < -1) - m_cursorCol = -1; - ensureCursorVisible(); - break; - case EA_CHAR_RIGHT: - if (++m_cursorCol >= m_lines->lineAt(m_cursorLine).length()) - m_cursorCol = m_lines->lineAt(m_cursorLine).length() - 1; - ensureCursorVisible(); - break; - case EA_LINE_UP: - if (--m_cursorLine < 0) - m_cursorLine = 0; - ensureCursorVisible(); - break; - case EA_LINE_DOWN: - if (++m_cursorLine >= m_lines->lineCount()) - m_cursorLine = m_lines->lineCount() - 1; - ensureCursorVisible(); - break; - case EA_BEGIN_OF_LINE: - m_cursorCol = -1; - ensureCursorVisible(); - break; - case EA_END_OF_LINE: - m_cursorCol = m_lines->lineAt(m_cursorLine).length() - 1; - ; - ensureCursorVisible(); - break; - case EA_BEGIN_OF_FILE: - ensureCursorVisible(0); - break; - case EA_END_OF_FILE: - ensureCursorVisible(m_lines->lineCount() - 1); - break; - case EA_PAGE_UP: - // Do not change cursor line! - reposition(m_paragraphs.firstLine() - pageSize); - break; - case EA_PAGE_DOWN: - // Do not change cursor line! - reposition(m_paragraphs.firstLine() + pageSize); - break; - case EA_DEL_CHAR: - break; - case EA_BACKSPACE: - break; - case EA_DEL_END_OF_LINE: - break; - case EA_DEL_BEGIN_OF_LINE: - break; - case EA_DEL_LINE: - break; - default: - break; + // 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; + int x = rect.left() + m_widthLineNo + 1 + + (col + 1) * lookStd->m_metrics->width('x'); + int y = rect.top() + (m_cursorLine - firstLine) * lineHeight; + painter.setPen(*look->m_pen); + painter.drawLine(x, y, x, y + lineHeight); } - emit repaint(); + 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); + ReLogger::globalLogger()->logv(LOG_INFO, 3, "draw: %.4f", + double(clock() - start) / CLOCKS_PER_SEC); } /** @@ -646,13 +593,13 @@ void ReEdit::editorAction(ReEdit::EditorAction action){ * @param firstLine number of the line which should be visible */ void ReEdit::reposition(int firstLine){ - int pageSize = m_paragraphs.list().length(); + 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_paragraphs.setFirstLine(firstLine); + m_firstLine = firstLine; } /** @@ -664,28 +611,24 @@ void ReEdit::setCursorLine(int cursorLine){ } /** - * Returns the text source of the instance. - * - * @return the text source - */ -ReLines& ReEdit::lines(){ - if (m_lines == NULL) - setLines(new ReLines()); - return *m_lines; -} - -/** - * Sets the text source of the instance. + * Calculates the tabulator expanding strings. * - * @param lines the new text source + * Example (tab width = 3): + *
+ *   "\tz" -> '   z' -> '\t' + '  '
+ *  "x\tz" -> 'x  z' -> '\t' + ' '
+ * "xy\tz" -> 'xy z' -> '\t'
+ * 
+ * @param tabWidth */ -void ReEdit::setLines(ReLines* lines){ - m_lines = lines; - m_paragraphs.setLines(lines); - int count = height(); - count = count / heightToFullHeight(m_standardMetrics->height()); - m_paragraphs.load(m_cursorLine, count, this); - emit repaint(); +void ReEdit::setTabStrings(int tabWidth){ + m_tabWidth = tabWidth; + m_tabStrings.clear(); + QString blanks; + blanks.fill(' ', tabWidth); + for (int ix = 0; ix < tabWidth - 1; ix++){ + m_tabStrings.append(m_tabChar + blanks.mid(0, tabWidth - 1 - ix)); + } } /** @@ -694,10 +637,13 @@ void ReEdit::setLines(ReLines* lines){ 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_maxLineLength(0), + m_cursorVisible(true) { } /** @@ -719,6 +665,66 @@ void ReParagraphs::clear(){ m_list.clear(); } +/** + * Returns the cursor line. + * + * @return the cursor line + */ +ReParagraph* ReParagraphs::cursorLine(){ + ReParagraph* rc = NULL; + if (m_cursorLine >= m_firstLine && m_cursorLine < m_firstLine + m_list.length()){ + rc = m_list.at(m_cursorLine - m_firstLine); + } + return rc; +} + +/** + * Calculates the index of the line string from the cursor column. + * + * The index may be smaller because of expanded tabulators. + * Example: + *
"x\ty", tabulator width: 3, screen display: "x  y"
+ * columnToTextIndex(0) == 0; ('x')
+ * columnToTextIndex(1) == 1; ('\t')
+ * columnToTextIndex(2) == 1; ('\t')
+ * columnToTextIndex(3) == 2; ('y')
+ * 
+ * + * @param cursorCol the cursor position + * @return the + */ +int ReParagraphs::columnToTextIndex(int cursorCol){ + ReParagraph* current = cursorLine(); + int rc = 0; + if (current == NULL) + rc = cursorCol; + else { + // tab gaps (spaces between tab and tab position) + int gaps = 0; + // sum of columns + int cursor = 0; + for (int ix = 0; cursor < cursorCol && ix < current->length(); ix++){ + ReEditText* text = current->at(ix); + int len = text->text().length(); + if (len > 0 && text->text().at(0) == m_tabChar){ + gaps = len - 1; + rc += 1; + cursor += len; + if (cursor >= cursorCol) + break; + } else { + if (cursor + len <= cursorCol) + rc += len; + else { + rc += cursorCol - cursor; + break; + } + } + } + } + return rc; +} + /** * Renders the texts of the paragraph list. * @@ -756,6 +762,58 @@ void ReParagraphs::load(int lineNo, int count, ReEdit* edit){ } } +/** + * Sets the text source of the instance. + * + * @param lines the new text source + */ +void ReParagraphs::setLines(ReLines* lines){ + m_lines = lines; +} + +/** + * Calculates the cursor column from the line string index. + * + * The index may be larger because of expanded tabulators. + * Example: + *
"x\ty", tabulator width: 3, screen display: "x  y"
+ * textIndexToColumn(0) == 0;
+ * textIndexToColumn(1) == 1;
+ * textIndexToColumn(2) == 3;
+ * 
+ * @param index the index in the line string + * @return the column in the edit field + */ +int ReParagraphs::textIndexToColumn(int index){ + ReParagraph* current = cursorLine(); + int rc = 0; + if (current == NULL) + rc = index; + else { + int cursor; + for (int ix = 0; cursor < index && ix < current->length(); ix++){ + ReEditText* text = current->at(ix); + int len = text->text().length(); + if (len > 0 && text->text().at(0) == m_tabChar){ + rc += len; + cursor += 1; + if (cursor >= index) + break; + } else { + if (cursor + len < index){ + cursor += len; + rc += len; + } else { + rc += index - cursor; + break; + } + } + } + } + return rc; +} + + /** * Changes the look of a paragraph. * @@ -864,45 +922,52 @@ void ReMouseCatcher::insertClickObject(ReMouseCatcher::ClickPosition* object){ } /** - * Does some things if the mouse position is inside the vertical scrollbar. + * Does some things if the mouse position is inside the horizontal scrollbar. * - * @param event the mouse click event + * @param event the mouse click event * @param isDragged true: called from mouseMoveEvent - * @param edit the edit field - * @return true: the mouse click is inside the vertical sb + * @param edit the edit field + * @return true: the mouse click is inside the horizontal sb */ -bool ReMouseCatcher::handleVScrollBar(QMouseEvent* event, bool isDragged, +bool ReMouseCatcher::handleHScrollBar(QMouseEvent* event, bool isDragged, ReEdit* edit){ QPoint pos = event->pos(); - bool rc = rectContains(*m_vScrollBar, pos, "vScrollBar") - || (isDragged && m_vScrollBar->contains(m_lastMousePosition)); + bool rc = rectContains(*m_hScrollBar, pos, "hScrollBar"); if (rc){ - 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); + } return rc; } /** - * Does some things if the mouse position is inside the horizontal scrollbar. + * Does some things if the mouse position is inside the vertical scrollbar. * - * @param event the mouse click event + * @param event the mouse click event * @param isDragged true: called from mouseMoveEvent - * @param edit the edit field - * @return true: the mouse click is inside the horizontal sb + * @param edit the edit field + * @return true: the mouse click is inside the vertical sb */ -bool ReMouseCatcher::handleHScrollBar(QMouseEvent* event, bool isDragged, +bool ReMouseCatcher::handleVScrollBar(QMouseEvent* event, bool isDragged, ReEdit* edit){ QPoint pos = event->pos(); - bool rc = rectContains(*m_hScrollBar, pos, "hScrollBar"); + 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); + } } return rc; } diff --git a/gui/ReEdit.hpp b/gui/ReEdit.hpp index 1051acb..b3f5ed2 100644 --- a/gui/ReEdit.hpp +++ b/gui/ReEdit.hpp @@ -174,7 +174,9 @@ public: m_builders.append(builder); } void clear(); + ReParagraph* cursorLine(); void draw(QPainter& painter, int top, int left); + int columnToTextIndex(int cursorCol); /** Returns the paragraph with a given index from the list. * @param ix the index [0..N-1] of the paragraph in the list * @return NULL: wrong index
@@ -184,48 +186,29 @@ public: return ix < 0 || ix >= m_list.length() ? NULL : m_list.at(ix); } void load(int lineNo, int count, ReEdit* edit); + int textIndexToColumn(int index); public: - /** Sets the line source. - * @param lines the line source to set - */ - void setLines(ReLines* lines){ - m_lines = lines; - } - /** Returns the number of the first line. - * @return the linenumber of the first line [0..N-1] - */ - int firstLine() const{ - return m_firstLine; - } - /** Sets the number of the first line. - * @param firstLine the number of the first line - */ - void setFirstLine(int firstLine){ - m_firstLine = firstLine; - } - - /** Returns the paragraph list. - * @return the paragraph list - */ - QList & list(){ - return m_list; - } - /** Returns the maximal line length of all lines in the paragraph list. - * @return the maximal line length - */ - inline - int maxLineLength() const{ - return m_maxLineLength; - } - + void setLines(ReLines* lines); protected: QList m_builders; - // the m_list.at(0) belongs to m_lines.atLine(m_firstLine) + /// the m_list.at(0) belongs to m_lines.atLine(m_firstLine) 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) + int m_cursorCol; ReLines* m_lines; QList m_list; int m_maxLineLength; + /// true: the text cursor is visible (blinking) + bool m_cursorVisible; +protected: + static QStringList m_tabStrings; + static QChar m_tabChar; + static int m_tabWidth; }; /** @@ -279,7 +262,7 @@ public: * It displays a set of paragraphs with line number, vertical and horizontal * scroll bars and handle the key and mouse events to implement an editor. */ -class ReEdit: public QWidget, protected ReMouseCatcher { +class ReEdit: public QWidget, protected ReMouseCatcher, public ReParagraphs { Q_OBJECT public: enum EditorAction { @@ -314,17 +297,10 @@ public: */ inline int pageSize(){ - return m_paragraphs.list().length(); + return m_list.length(); } void reposition(int firstLine); void setCursorLine(int cursorLine); - void setLines(ReLines* lines); - /** Returns the paragraph list - * @return the paragraph list - */ - inline ReParagraphs& paragraphs(){ - return m_paragraphs; - } /** Returns the array of the foreground colors. * @return the array of the foreground colors */ @@ -338,13 +314,11 @@ public: return m_brushColors; } protected: - int columnToTextIndex(int cursorCol); 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); - int textIndexToColumn(int index); protected slots: void keyPressEvent(QKeyEvent* event); void paintEvent(QPaintEvent *); @@ -361,18 +335,6 @@ public: } static void setTabStrings(int tabWidth); protected: - /// the lines to display - ReParagraphs m_paragraphs; - /// line number of the first displayed line - int m_firstLine; - /// first column of the displayed lines - int m_firstCol; - /// the line number of the cursor line. May be outside of the visual area. - int m_cursorLine; - /// the column number of the cursor. -1: before the first column - int m_cursorCol; - /// true: the text cursor is visible (blinking) - bool m_cursorVisible; // number of pixels of the width of the edit field int m_widthEdit; // number of pixels of the height of the edit field @@ -387,7 +349,6 @@ protected: int m_widthVScrollBar; /// number of pixels for the bottom scroll bar int m_heightHScrollBar; - ReLines* m_lines; ReLook* m_looks[ReLook::BG_COUNT * ReLook::FG_COUNT]; QBrush* m_standardBrush; QBrush* m_scrollbarBrush; @@ -406,10 +367,6 @@ protected: QMap m_keyRaw; QMap m_keyShift; ReMouseCatcher m_mouseCatcher; -protected: - static QStringList m_tabStrings; - static QChar m_tabChar; - static int m_tabWidth; }; #endif // REEDITOR_HPP -- 2.39.5