From 96d146fb4efb1333dee2c879491765f52e324a54 Mon Sep 17 00:00:00 2001 From: hama Date: Wed, 24 Jun 2015 00:32:00 +0200 Subject: [PATCH] reditor: scrollbar sizes correct, tab expanding --- appl/reditor/mainwindow.cpp | 3 +- base/rebase.hpp | 8 ++ gui/ReEdit.cpp | 146 ++++++++++++++++++++++++++++++++---- gui/ReEdit.hpp | 33 +++++++- 4 files changed, 173 insertions(+), 17 deletions(-) diff --git a/appl/reditor/mainwindow.cpp b/appl/reditor/mainwindow.cpp index 92b679e..400b8f5 100644 --- a/appl/reditor/mainwindow.cpp +++ b/appl/reditor/mainwindow.cpp @@ -20,13 +20,12 @@ MainWindow::MainWindow(QWidget *parent) : ui->setupUi(this); ReEdit* edit = ui->widget; #if defined __linux__ - m_file = new ReFile("/home/hm/lehrplan.txt", false); + m_file = new ReFile("/home/hm/editor.txt", false); #else m_file = new ReFile("U:\\ws_cpp\\rplqt\\Doxyfile", false); #endif edit->setLines(m_file); edit->setCursorLine(0); - edit->paragraphs().load(0, 5, edit); connect(ui->actionOpen, SIGNAL(triggered()), this, SLOT(openFile())); diff --git a/base/rebase.hpp b/base/rebase.hpp index e1fc639..9e010bb 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -62,6 +62,14 @@ typedef QString ReString; #endif #define UNUSED_VAR(var) (void) var +inline +int max(int a, int b){ + return a > b ? a : b; +} +inline +int min(int a, int b){ + return a < b ? a : b; +} #include "remodules.hpp" #include "base/ReByteStorage.hpp" diff --git a/gui/ReEdit.cpp b/gui/ReEdit.cpp index 5a20432..4890ae7 100644 --- a/gui/ReEdit.cpp +++ b/gui/ReEdit.cpp @@ -13,6 +13,11 @@ #include "gui/regui.hpp" #include +QStringList ReEdit::m_tabStrings; +// left arrow: +QChar ReEdit::m_tabChar = QChar(2192); +int ReEdit::m_tabWidth = 3; + /** * Calculates the full line height (with gap between lines) * @@ -101,14 +106,18 @@ ReEdit::ReEdit(QWidget* parent) : m_cursorLine(0), m_cursorCol(-1), m_cursorVisible(true), + m_widthEdit(0), + m_heightEdit(0), m_insertMode(true), m_breakLines(false), m_widthLineNo(50), - m_widthVScrollBar(0), - m_widthHScrollBar(0), + m_widthVScrollBar(20), + m_heightHScrollBar(20), m_lines(NULL), 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), @@ -128,6 +137,9 @@ ReEdit::ReEdit(QWidget* parent) : m_standardFont->setPixelSize(16); m_standardMetrics = new QFontMetrics(*m_standardFont); m_standardBrush->setColor(Qt::white); + QColor color1(214, 210, 208); + m_scrollbarBrush->setColor(color1); + m_sliderBrush->setColor(Qt::lightGray); memset(m_looks, 0, sizeof m_looks); memset(m_brushColors, 0, sizeof m_brushColors); m_fontColors[ReLook::FG_STANDARD] = new QColor(Qt::black); @@ -178,6 +190,7 @@ ReEdit::ReEdit(QWidget* parent) : m_keyControl[Qt::Key_Delete] = EA_DEL_END_OF_LINE; m_keyShift[Qt::Key_Delete] = EA_DEL_BEGIN_OF_LINE; m_keyAlt[Qt::Key_Delete] = EA_DEL_LINE; + setTabStrings(3); } /** @@ -228,16 +241,17 @@ QBrush* ReEdit::createBrush(ReLook::BackGround background){ void ReEdit::paintEvent(QPaintEvent* event){ QRect rect = event->rect(); m_widthEdit = rect.width(); + m_heightEdit = rect.height(); int lineHeight = heightToFullHeight(m_standardMetrics->height()); - int pageSize = rect.height() / lineHeight; + 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(), - rect.bottom()); + 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; @@ -272,8 +286,64 @@ void ReEdit::paintEvent(QPaintEvent* event){ 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, pageSize * 100 / maxLines, + m_paragraphs.firstLine() * 100 / maxLines, width * 100 / maxWidth, 0); +} + +void calcSliderSize(int size, int minSize, int sizePercent, int posPercent, + int& position, int& length){ + if (sizePercent > 100) + sizePercent = 100; + if (posPercent > 100) + posPercent = 100; + length = size * sizePercent / 100; + if (length < minSize) + length = minSize; + position = (size - length) * posPercent / 100; } +/** + * Draws the scrollbars. + * + * @param painter the paint unit + * @param rect the full area of the edit field + * @param sizeVertical the size of the scrollbar (in %) + * @param posVertical the position of the scrollbar (in %) + * @param sizeHorizontal the size of the scrollbar (in %) + * @param posHorizontal the position of the scrollbar (in %) + */ +void ReEdit::drawScrollbars(QPainter& painter, const QRect& rect, + int sizeVertical, int posVertical, int sizeHorizontal, int posHorizontal){ + // We paint the vertical scrollbar: + painter.setBrush(*m_scrollbarBrush); + int x = rect.right() - m_widthVScrollBar; + painter.drawRect(x, rect.top(), m_widthVScrollBar, + rect.height() - m_heightHScrollBar); + + // We paint the horizontal scrollbar: + painter.drawRect(rect.left() + m_widthLineNo, + rect.bottom() - m_heightHScrollBar, + rect.width() - m_widthVScrollBar - m_widthLineNo, m_heightHScrollBar); + + // Slider (vertical) + painter.setBrush(*m_sliderBrush); + int sliderSize = 0; + int sliderPos = 0; + calcSliderSize(rect.height() - m_heightHScrollBar, m_heightHScrollBar, + sizeVertical, posVertical, sliderPos, sliderSize); + painter.drawRect(x + 1, rect.top() + sliderPos, m_widthVScrollBar - 2, + sliderSize); + // Slider (horizontal) + calcSliderSize(rect.width() - m_widthLineNo - m_widthVScrollBar, + m_heightHScrollBar, sizeHorizontal, posHorizontal, sliderPos, sliderSize); + painter.drawRect(rect.left() + m_widthLineNo + sliderPos, + rect.bottom() - m_heightHScrollBar + 1, sliderSize, + m_heightHScrollBar - 2); +} /** * Handles the mouse click event. * @@ -388,6 +458,26 @@ void ReEdit::keyPressEvent(QKeyEvent* event){ } emit repaint(); } +/** + * Calculates the tabulator expanding strings. + * + * Example (tab width = 3): + *
+ *   "\tz" -> '   z' -> '\t' + '  '
+ *  "x\tz" -> 'x  z' -> '\t' + ' '
+ * "xy\tz" -> 'xy z' -> '\t'
+ * 
+ * @param tabWidth + */ +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)); + } +} /** * Returns the line number of the cursor line. @@ -530,6 +620,18 @@ void ReEdit::setLines(ReLines* lines){ emit repaint(); } +/** + * Constructor. + */ +ReParagraphs::ReParagraphs() : + m_builders(), + m_firstLine(0), + m_lines(NULL), + m_list(), + m_maxLineLength(0){ + +} + /** * Destructor. */ @@ -541,6 +643,7 @@ ReParagraphs::~ReParagraphs(){ * Makes the list empty and frees the resources. */ void ReParagraphs::clear(){ + m_maxLineLength = 0; for (int ix = m_list.length() - 1; ix >= 0; ix--){ ReParagraph* current = m_list.at(ix); delete current; @@ -572,12 +675,16 @@ void ReParagraphs::draw(QPainter& painter, int top, int left){ */ void ReParagraphs::load(int lineNo, int count, ReEdit* edit){ clear(); + m_maxLineLength = 0; m_firstLine = lineNo; 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; } } @@ -592,8 +699,24 @@ void ReParagraphBuilder::buildParagraph(ReParagraph& paragraph, int lineNo, ReEdit* edit){ if (paragraph.length() == 0){ const QString& text = edit->lines().lineAt(lineNo); - ReEditText* part = new ReEditText(text, - edit->lookOf(ReLook::FG_STANDARD, ReLook::BG_STANDARD)); + ReLook* look = edit->lookOf(ReLook::FG_STANDARD, 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; + } + paragraph.append( + new ReEditText(ReEdit::tabString(paragraph.m_columns), look)); + start = ixTab + 1; + } + + part = new ReEditText(start == 0 ? text : text.mid(start), look); + paragraph.m_columns += part->text().length(); paragraph.append(part); } } @@ -619,23 +742,18 @@ ReParagraph::~ReParagraph(){ 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); -#if 0 - QBrush& brush = *current->look()->m_brush; - brush.setColor(Qt::lightGray); - painter.setBackground(brush); -#endif QFont& font = *current->look()->m_font; painter.setFont(font); QPen& pen = *current->look()->m_pen; - //pen.setColor(Qt::blue); - //QColor color1 = pen.color(); painter.setPen(pen); painter.drawText(x, y, current->text()); x += metrics->width(current->text()); } } + diff --git a/gui/ReEdit.hpp b/gui/ReEdit.hpp index 930b188..80ae8e8 100644 --- a/gui/ReEdit.hpp +++ b/gui/ReEdit.hpp @@ -130,6 +130,9 @@ public: virtual ~ReParagraph(); public: void draw(QPainter& painter, int& top, int left); +public: + // number of columns of the paragraph (length with expanded tabs). + int m_columns; }; /** @@ -160,6 +163,7 @@ public: */ class ReParagraphs { public: + ReParagraphs(); virtual ~ReParagraphs(); public: /** Appends a paragraph builder to the list @@ -206,6 +210,13 @@ public: 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; + } protected: QList m_builders; @@ -213,6 +224,7 @@ protected: int m_firstLine; ReLines* m_lines; QList m_list; + int m_maxLineLength; }; /** @@ -263,6 +275,8 @@ public: protected: int columnToTextIndex(int cursorCol); QBrush* createBrush(ReLook::BackGround background); + void drawScrollbars(QPainter& painter, const QRect& rect, int sizeVertical, + int posVertical, int sizeHorizontal, int posHorizontal); void ensureCursorVisible(int cursorLine = -1); void reposition(int firstLine); int textIndexToColumn(int index); @@ -270,6 +284,15 @@ protected slots: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent* event); void keyPressEvent(QKeyEvent* event); +public: + /** Returns the tabulator expanding string. + * @param position the position of the tabulator (0..N-1) + * @return the tabulator expanding string + */ + inline static const QString& tabString(int position){ + return m_tabStrings.at(position % m_tabWidth); + } + static void setTabStrings(int tabWidth); protected: /// the lines to display ReParagraphs m_paragraphs; @@ -285,6 +308,8 @@ protected: 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 + int m_heightEdit; /// true: keys will be inserted at the cursor position bool m_insertMode; /// true: a file line will be displayed in multiple lines (if long enough) @@ -294,10 +319,12 @@ protected: /// number of pixels for the right scroll bar int m_widthVScrollBar; /// number of pixels for the bottom scroll bar - int m_widthHScrollBar; + int m_heightHScrollBar; ReLines* m_lines; ReLook* m_looks[ReLook::BG_COUNT * ReLook::FG_COUNT]; QBrush* m_standardBrush; + QBrush* m_scrollbarBrush; + QBrush* m_sliderBrush; QColor* m_brushColors[ReLook::BG_COUNT]; QPen* m_standardPen; QFont* m_standardFont; @@ -311,6 +338,10 @@ protected: QMap m_keyControlShift; QMap m_keyRaw; QMap m_keyShift; +protected: + static QStringList m_tabStrings; + static QChar m_tabChar; + static int m_tabWidth; }; #endif // REEDITOR_HPP -- 2.39.5