]> gitweb.hamatoma.de Git - reqt/commitdiff
Refactoring: ReParagraphs as base class of ReEdit
authorhama <hama@siduction.net>
Mon, 29 Jun 2015 22:24:30 +0000 (00:24 +0200)
committerhama <hama@siduction.net>
Mon, 29 Jun 2015 22:24:30 +0000 (00:24 +0200)
gui/ReEdit.cpp
gui/ReEdit.hpp

index 32e97d23d27818ea6f3210a7614cb272e25864dc..927605b026bf3d96c1b2efffdd82c1729bd86f71 100644 (file)
 #include "gui/regui.hpp"
 #include <QPaintEvent>
 
-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:
- * <pre>"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')
- * </pre>
- *
- * @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:
- * <pre>"x\ty", tabulator width: 3, screen display: "x  y"
- * textIndexToColumn(0) == 0;
- * textIndexToColumn(1) == 1;
- * textIndexToColumn(2) == 3;
- * </pre>
- * @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):
- * <pre>
- *   "\tz" -> '   z' -> '\t' + '  '
- *  "x\tz" -> 'x  z' -> '\t' + ' '
- * "xy\tz" -> 'xy z' -> '\t'
- * </pre>
- * @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):
+ * <pre>
+ *   "\tz" -> '   z' -> '\t' + '  '
+ *  "x\tz" -> 'x  z' -> '\t' + ' '
+ * "xy\tz" -> 'xy z' -> '\t'
+ * </pre>
+ * @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:
+ * <pre>"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')
+ * </pre>
+ *
+ * @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:
+ * <pre>"x\ty", tabulator width: 3, screen display: "x  y"
+ * textIndexToColumn(0) == 0;
+ * textIndexToColumn(1) == 1;
+ * textIndexToColumn(2) == 3;
+ * </pre>
+ * @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 <code>true</code>: called from <code>mouseMoveEvent</code>
- * @param edit      the edit field
- * @return          <code>true</code>: the mouse click is inside the vertical sb
+ * @param edit  the edit field
+ * @return      <code>true</code>: 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 <code>true</code>: called from <code>mouseMoveEvent</code>
- * @param edit  the edit field
- * @return      <code>true</code>: the mouse click is inside the horizontal sb
+ * @param edit      the edit field
+ * @return          <code>true</code>: 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;
 }
index 1051acbe5969286b2cf1f1b10e8c9a6258ce85f9..b3f5ed2478e8dd085ed8ce4e8d21f1e2ad3da3a6 100644 (file)
@@ -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<br>
@@ -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 <ReParagraph*>& 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 <ReParagraphBuilder*> 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 <ReParagraph*> 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 <int, EditorAction> m_keyRaw;
    QMap <int, EditorAction> m_keyShift;
    ReMouseCatcher m_mouseCatcher;
-protected:
-   static QStringList m_tabStrings;
-   static QChar m_tabChar;
-   static int m_tabWidth;
 };
 
 #endif // REEDITOR_HPP