1 /*
2 Copyright (C) 2010 Andres Cabrera
3 mantaraya36@gmail.com
4
5 This file is part of CsoundQt.
6
7 CsoundQt is free software; you can redistribute it
8 and/or modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 CsoundQt is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with Csound; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA
21 */
22
23 #ifdef USE_QT5
24 #include <QtWidgets>
25 #else
26 #include <QtGui>
27 #endif
28
29 #include "texteditor.h"
30
31
TextEditor(QWidget * parent)32 TextEditor::TextEditor(QWidget *parent) :
33 QTextEdit(parent)
34 {
35 setAcceptDrops(true);
36 setAcceptRichText(false);
37 m_parameterMode = false;
38 m_commaTyped = false;
39 // qDebug() << "TextEditor::TextEditor" << acceptDrops();
40 }
41
keyPressEvent(QKeyEvent * event)42 void TextEditor::keyPressEvent (QKeyEvent * event)
43 {
44 if (m_commaTyped && event->key() != Qt::Key_Space) {
45 m_commaTyped = false;
46 }
47 switch(event->key()) {
48 case Qt::Key_Tab:
49 if (m_parameterMode) {
50 emit tabPressed();
51 } else if(m_tabIndents) {
52 // this blocks default behaviour and only tab does not move any further
53 emit requestIndent();
54 } else {
55 QTextEdit::keyPressEvent(event);
56 }
57 return;
58 case Qt::Key_Backtab:
59 if (m_parameterMode) {
60 emit backtabPressed();
61 } else if(m_tabIndents) {
62 emit requestUnindent();
63 }
64 return;
65 case Qt::Key_Return:
66 case Qt::Key_Enter:
67 emit enterPressed();
68 break;
69 case Qt::Key_Space:
70 if (m_commaTyped) {
71 emit showParameterInfo();
72 }
73 m_commaTyped = false;
74 break;
75 case Qt::Key_Comma:
76 m_commaTyped = true;
77 break;
78 }
79 QTextEdit::keyPressEvent(event); // Process key events in the rest of the application
80 if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down
81 || event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) {
82 emit arrowPressed();
83 }
84
85 if (event->key() == Qt::Key_Escape) {
86 emit escapePressed();
87 } else if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
88 emit newLine();
89 }
90 return;
91 }
92
mouseReleaseEvent(QMouseEvent * e)93 void TextEditor::mouseReleaseEvent(QMouseEvent *e)
94 {
95 QTextEdit::mouseReleaseEvent(e); // and do all the necessary qt job
96 if (m_parameterMode) {
97 emit requestParameterModeExit();
98 }
99
100 }
101
102 //The following makes the editor almost accept drop events on OS X, but breaks all dragging on the same document on linux
103 //void TextEditor::dropEvent(QDropEvent *event)
104 //{
105 // qDebug() << "TextEditor::dropEvent" << event->format();
106 //// QString fileName = QString(event->encodedData("text/uri-list")).remove("file://");
107 //// event->;
108 //
109 // event->acceptProposedAction();
110 //}
111 //
112 //void TextEditor::dragEnterEvent(QDragEnterEvent *event)
113 //{
114 //// qDebug() << "TextEditor::dragEnterEvent" << event->format();
115 // // TODO remove file:// text from text
116 // event->acceptProposedAction();
117 //}
118 //
119 //void TextEditor::dragMoveEvent(QDragMoveEvent *event)
120 //{
121 //// qDebug() << "TextEditor::dragMoveEvent" << event->mimeData()->text();
122 // event->acceptProposedAction();
123 //}
124
TextEditLineNumbers(QWidget * parent)125 TextEditLineNumbers::TextEditLineNumbers(QWidget *parent)
126 : TextEditor(parent)
127 {
128 setLineAreaVisible(false);
129 lineNumberArea = new LineNumberArea(this);
130 connect(this->document(),SIGNAL(blockCountChanged(int)),this,SLOT(updateLineArea(int)));
131 connect(this->verticalScrollBar(),SIGNAL(valueChanged(int)),this,SLOT(updateLineArea(int)));
132 connect(this,SIGNAL(cursorPositionChanged()),this,SLOT(updateLineArea()));
133 lineNumberArea->setLineNumberSizeScaling(0.8);
134 m_editorPadding = 6;
135 }
136
getAreaWidth()137 int TextEditLineNumbers::getAreaWidth()
138 {
139 qreal scaling = lineNumberArea->lineNumberSizeScaling();
140 int right_padding = lineNumberArea->padding();
141 int left_padding = lineNumberArea->padding();
142 int numDigits = 4;
143 int oneDigit = this->fontMetrics().width(QLatin1Char('9'));
144 return oneDigit * scaling * numDigits + left_padding + right_padding;
145 }
146
resizeEvent(QResizeEvent * e)147 void TextEditLineNumbers::resizeEvent(QResizeEvent *e)
148 {
149 QTextEdit::resizeEvent(e);
150 if (m_lineAreaVisble) {
151 setViewportMargins(getAreaWidth()+m_editorPadding, 0, 0, 0); // since font might have changed
152 QRect cr = contentsRect();
153 lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), getAreaWidth(), cr.height()));
154 } else
155 setViewportMargins(m_editorPadding, 0, 0, 0); // since font might have changed
156
157 }
158
setLineAreaVisible(bool visible)159 void TextEditLineNumbers::setLineAreaVisible(bool visible)
160 {
161 m_lineAreaVisble = visible;
162 if (m_lineAreaVisble) {
163 setViewportMargins(getAreaWidth() + m_editorPadding, 0, 0, 0);
164 }
165 else {
166 setViewportMargins(m_editorPadding, 0, 0, 0);
167 }
168 }
169
markDebugLine(int line)170 void TextEditLineNumbers::markDebugLine(int line)
171 {
172 m_debugLines.append(line);
173 lineNumberArea->setDebugLines(m_debugLines);
174 }
175
unmarkDebugLine(int line)176 void TextEditLineNumbers::unmarkDebugLine(int line)
177 {
178 int index = m_debugLines.indexOf(line);
179 if (index >= 0) {
180 m_debugLines.remove(index);
181 } else {
182 qDebug() << "TextEditLineNumbers::unmarkDebugLine no marker at line " << line;
183 }
184 lineNumberArea->setDebugLines(m_debugLines);
185 updateLineArea();
186 }
187
setCurrentDebugLine(int line)188 void TextEditLineNumbers::setCurrentDebugLine(int line)
189 {
190 lineNumberArea->setCurrentDebugLine(line);
191 updateLineArea();
192 }
193
updateLineArea(int)194 void TextEditLineNumbers::updateLineArea(int)
195 {
196 lineNumberArea->update();
197 }
198
updateLineArea()199 void TextEditLineNumbers::updateLineArea()
200 {
201 lineNumberArea->update();
202 }
203
setLineAreaColors(QColor foreground,QColor background)204 void TextEditLineNumbers::setLineAreaColors(QColor foreground, QColor background)
205 {
206 lineNumberArea->setColors(foreground, background);
207 }
208
paintEvent(QPaintEvent *)209 void LineNumberArea::paintEvent(QPaintEvent *)
210 {
211 if ( !codeEditor->lineAreaVisble() )
212 return;
213 QPainter painter(this);
214 painter.fillRect(rect(), m_background);
215 //code based partly on: http://john.nachtimwald.com/2009/08/15/qtextedit-with-line-numbers/
216 QTextBlock block = codeEditor->document()->begin();
217 int contents_y = codeEditor->verticalScrollBar()->value();
218 int page_bottom = contents_y + codeEditor->viewport()->height();
219 QTextBlock current_block = codeEditor->document()->findBlock(codeEditor->textCursor().position());
220
221 int line_count = 0;
222 painter.setPen(m_foreground); // not exactly black
223
224 bool bold;
225 QFont font = painter.font();
226 font.setPointSizeF(font.pointSizeF() * m_lineNumbersSizeFactor);
227 painter.setFont(font);
228 auto width = codeEditor->getAreaWidth();
229 auto metrics = codeEditor->fontMetrics();
230
231 while (block.isValid()) {
232 line_count += 1;
233 QString number = QString::number(line_count);
234 QPointF position = codeEditor->document()->documentLayout()->blockBoundingRect(block).topLeft();
235 if (position.y() > page_bottom)
236 break;
237 int y = round(position.y()) - contents_y + metrics.ascent();
238 if (y>=0) { // the line is visible
239 if (block == current_block) {
240 bold = true;
241 font.setBold(true);
242 painter.setFont(font);
243 }
244 int x = width - metrics.width(number)*m_lineNumbersSizeFactor - m_padding;
245 painter.drawText(x, y, number);
246 if (bold) {
247 font.setBold(false);
248 painter.setFont(font);
249 }
250 if (m_debugLines.indexOf(line_count) >= 0) {
251 painter.setPen(QColor(Qt::red));
252 painter.setBrush(QColor(Qt::red));
253 int height = codeEditor->fontMetrics().ascent() ;
254 painter.drawEllipse(position.x(), y - height, height, height);
255 painter.setBrush(QBrush());
256 painter.setPen(QColor(Qt::darkGray).darker()); // not exactly black
257 }
258 if (m_currentDebugLine >= 0 && line_count == m_currentDebugLine) {
259 QImage image("://themes/boring/gtk-media-play-ltr.png");
260 painter.drawImage(position.x(), y, image);
261 }
262 }
263 block = block.next();
264 }
265 }
266