File indexing completed on 2024-05-12 17:11:40

0001 /***************************************************************************
0002  *   Copyright (C) 2016 by Renaud Guezennec                                *
0003  *   http://www.rolisteam.org/contact                                      *
0004  *                                                                         *
0005  *   rolisteam is free software; you can redistribute it and/or modify     *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 #include "codeeditor.h"
0021 
0022 #include <QtWidgets>
0023 
0024 #include <QFontDatabase>
0025 
0026 CodeEditor::CodeEditor(QWidget* parent) : QPlainTextEdit(parent)
0027 {
0028     const QFont fixedFont= QFontDatabase::systemFont(QFontDatabase::FixedFont);
0029     setFont(fixedFont);
0030     QFontMetrics metrics(fixedFont);
0031     // setTabStopWidth(metrics.boundingRect("    ").width());
0032     lineNumberArea= new LineNumberArea(this);
0033 
0034     connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
0035     connect(this, SIGNAL(updateRequest(QRect, int)), this, SLOT(updateLineNumberArea(QRect, int)));
0036     connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
0037 
0038     updateLineNumberAreaWidth(0);
0039     highlightCurrentLine();
0040 }
0041 
0042 int CodeEditor::lineNumberAreaWidth()
0043 {
0044     int digits= 1;
0045     int max= qMax(1, blockCount());
0046     while(max >= 10)
0047     {
0048         max/= 10;
0049         ++digits;
0050     }
0051 
0052     int space= 3 + fontMetrics().boundingRect('9').width() * digits;
0053 
0054     return space;
0055 }
0056 
0057 void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
0058 {
0059     setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
0060 }
0061 
0062 void CodeEditor::updateLineNumberArea(const QRect& rect, int dy)
0063 {
0064     if(dy)
0065         lineNumberArea->scroll(0, dy);
0066     else
0067         lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
0068 
0069     if(rect.contains(viewport()->rect()))
0070         updateLineNumberAreaWidth(0);
0071 }
0072 
0073 void CodeEditor::resizeEvent(QResizeEvent* e)
0074 {
0075     QPlainTextEdit::resizeEvent(e);
0076 
0077     QRect cr= contentsRect();
0078     lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
0079 }
0080 
0081 void CodeEditor::highlightCurrentLine()
0082 {
0083     QList<QTextEdit::ExtraSelection> extraSelections;
0084 
0085     if(!isReadOnly())
0086     {
0087         QTextEdit::ExtraSelection selection;
0088 
0089         QColor lineColor= QColor(Qt::yellow).lighter(160);
0090 
0091         selection.format.setBackground(lineColor);
0092         selection.format.setProperty(QTextFormat::FullWidthSelection, true);
0093         selection.cursor= textCursor();
0094         selection.cursor.clearSelection();
0095         extraSelections.append(selection);
0096     }
0097 
0098     setExtraSelections(extraSelections);
0099 }
0100 
0101 void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent* event)
0102 {
0103     QPainter painter(lineNumberArea);
0104     painter.fillRect(event->rect(), Qt::lightGray);
0105 
0106     QTextBlock block= firstVisibleBlock();
0107     int blockNumber= block.blockNumber();
0108     int top= (int)blockBoundingGeometry(block).translated(contentOffset()).top();
0109     int bottom= top + (int)blockBoundingRect(block).height();
0110 
0111     while(block.isValid() && top <= event->rect().bottom())
0112     {
0113         if(block.isVisible() && bottom >= event->rect().top())
0114         {
0115             QString number= QString::number(blockNumber + 1);
0116             painter.setPen(Qt::black);
0117             painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number);
0118         }
0119 
0120         block= block.next();
0121         top= bottom;
0122         bottom= top + (int)blockBoundingRect(block).height();
0123         ++blockNumber;
0124     }
0125 }