18 : QPlainTextEdit(parent), m_settings(settings), m_highlighter(new
PythonHighlighter(document()))
23 connect(
this, &QPlainTextEdit::blockCountChanged,
this, &CodeEditor::updateLineNumberAreaWidth);
24 connect(
this, &QPlainTextEdit::updateRequest,
this, &CodeEditor::updateLineNumberArea);
25 connect(
this, &QPlainTextEdit::cursorPositionChanged,
this, &CodeEditor::startAllHighlighting);
27 updateLineNumberAreaWidth(0);
28 setAttribute(Qt::WA_DeleteOnClose);
29 updateUsingSettings();
30 installEventFilter(
this);
35 if (target ==
this &&
event->type() == QEvent::Wheel)
37 auto *wheel =
static_cast<QWheelEvent *
>(
event);
38 if (wheel->modifiers() == Qt::ControlModifier)
40 if (wheel->angleDelta().y() > 0)
51 return QPlainTextEdit::eventFilter(target,
event);
54 void CodeEditor::updateUsingSettings()
57 font.setFamily(
"Courier");
58 font.setFixedPitch(
true);
59 font.setPointSize(m_settings->
fontSize());
62 QPalette p = palette();
67 setLineWrapMode(QPlainTextEdit::NoWrap);
71 m_highlighter->rehighlight();
72 highlightCurrentLine();
76 void CodeEditor::startAllHighlighting()
78 const QList<QTextEdit::ExtraSelection> selections;
79 setExtraSelections(selections);
80 highlightCurrentLine();
86 int max = qMax(1, blockCount());
93 int space = 3 + fontMetrics().maxWidth() * digits;
98 void CodeEditor::updateLineNumberAreaWidth(
int )
103 void CodeEditor::updateLineNumberArea(
const QRect &
rect,
int dy)
106 m_lineNumberArea->scroll(0, dy);
108 m_lineNumberArea->update(0,
rect.
y(), m_lineNumberArea->width(),
rect.height());
110 if (
rect.contains(viewport()->
rect()))
111 updateLineNumberAreaWidth(0);
116 QPlainTextEdit::resizeEvent(e);
118 QRect cr = contentsRect();
119 m_lineNumberArea->setGeometry(QRect(cr.left(), cr.top(),
lineNumberAreaWidth(), cr.height()));
122 void CodeEditor::highlightCurrentLine()
129 QList<QTextEdit::ExtraSelection> selections = extraSelections();
133 QTextEdit::ExtraSelection selection;
136 selection.format.setProperty(QTextFormat::FullWidthSelection,
true);
137 selection.cursor = textCursor();
138 selection.cursor.clearSelection();
139 selections.append(selection);
142 setExtraSelections(selections);
147 QPainter painter(m_lineNumberArea);
148 painter.fillRect(
event->rect(), Qt::lightGray);
150 QTextBlock block = firstVisibleBlock();
151 int blockNumber = block.blockNumber();
152 int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top();
153 int bottom = top + (int)blockBoundingRect(block).height();
155 while (block.isValid() && top <=
event->rect().bottom())
157 if (block.isVisible() && bottom >=
event->rect().top())
159 QString number = QString::number(blockNumber + 1);
162 0, top, m_lineNumberArea->width(), fontMetrics().
height(), Qt::AlignRight, number);
165 block = block.next();
167 bottom = top + (int)blockBoundingRect(block).height();
174 static int sequenceNumber = 1;
177 m_curFile = tr(
"script%1.py").arg(sequenceNumber++);
178 setWindowTitle(m_curFile +
"[*]");
180 connect(document(), &QTextDocument::contentsChanged,
this, &CodeEditor::documentWasModified);
185 QFile file(fileName);
186 if (!file.open(QFile::ReadOnly | QFile::Text))
188 QMessageBox::warning(
189 this, tr(
"MDI"), tr(
"Cannot read file %1:\n%2.").arg(fileName).arg(file.errorString()));
193 QTextStream in(&file);
194 QApplication::setOverrideCursor(Qt::WaitCursor);
195 setPlainText(in.readAll());
196 QApplication::restoreOverrideCursor();
198 setCurrentFile(fileName);
200 connect(document(), &QTextDocument::contentsChanged,
this, &CodeEditor::documentWasModified);
219 QString fileName = QFileDialog::getSaveFileName(
this, tr(
"Save As"), m_curFile);
220 if (fileName.isEmpty())
228 QFile file(fileName);
229 if (!file.open(QFile::WriteOnly | QFile::Text))
231 QMessageBox::warning(
this,
233 tr(
"Cannot write file %1:\n%2.")
234 .arg(QDir::toNativeSeparators(fileName), file.errorString()));
238 QTextStream out(&file);
239 QApplication::setOverrideCursor(Qt::WaitCursor);
240 out << toPlainText();
241 QApplication::restoreOverrideCursor();
243 setCurrentFile(fileName);
249 return strippedName(m_curFile);
264 void CodeEditor::documentWasModified()
266 setWindowModified(document()->isModified());
269 bool CodeEditor::maybeSave()
271 if (!document()->isModified())
273 const QMessageBox::StandardButton ret =
274 QMessageBox::warning(
this,
276 tr(
"'%1' has been modified.\n"
277 "Do you want to save your changes?")
279 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
282 case QMessageBox::Save:
284 case QMessageBox::Cancel:
292 void CodeEditor::setCurrentFile(
const QString &fileName)
294 m_curFile = QFileInfo(fileName).canonicalFilePath();
295 m_isUntitled =
false;
296 document()->setModified(
false);
297 setWindowModified(
false);
301 QString CodeEditor::strippedName(
const QString &fullFileName)
303 return QFileInfo(fullFileName).fileName();
306 void CodeEditor::createPairedCharsSelection(
int pos)
308 QList<QTextEdit::ExtraSelection> selections = extraSelections();
310 QTextEdit::ExtraSelection selection;
311 QTextCharFormat
format = selection.format;
313 selection.format =
format;
315 QTextCursor cursor = textCursor();
316 cursor.setPosition(pos);
317 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
318 selection.cursor = cursor;
320 selections.append(selection);
322 setExtraSelections(selections);
327 int lineCount = getSelectedLineCount();
328 QTextCursor cursor = textCursor();
329 cursor.setPosition(cursor.selectionEnd());
331 for (
int i = 0; i < lineCount; i++)
333 cursor.movePosition(QTextCursor::MoveOperation::StartOfLine);
335 cursor.movePosition(QTextCursor::MoveOperation::Up);
341 int lineCount = getSelectedLineCount();
342 QTextCursor cursor = textCursor();
343 cursor.setPosition(cursor.selectionEnd());
345 for (
int i = 0; i < lineCount; i++)
347 cursor.movePosition(QTextCursor::MoveOperation::StartOfLine);
348 QString line = cursor.block().text();
354 cursor.movePosition(QTextCursor::MoveOperation::Up);
360 int lineCount = getSelectedLineCount();
361 QTextCursor cursor = textCursor();
362 cursor.setPosition(cursor.selectionEnd());
364 for (
int i = 0; i < lineCount; i++)
366 cursor.movePosition(QTextCursor::MoveOperation::StartOfLine);
368 cursor.movePosition(QTextCursor::MoveOperation::Up);
374 int lineCount = getSelectedLineCount();
375 QTextCursor cursor = textCursor();
376 cursor.setPosition(cursor.selectionEnd());
378 for (
int i = 0; i < lineCount; i++)
380 cursor.movePosition(QTextCursor::MoveOperation::StartOfLine);
381 QString line = cursor.block().text();
382 if (line.startsWith(
"\t"))
388 for (
int i = 0; i < 4; i++)
395 cursor.movePosition(QTextCursor::MoveOperation::Up);
399 int CodeEditor::getSelectedLineCount()
401 QTextCursor cursor = textCursor();
402 if (cursor.hasSelection())
404 cursor.setPosition(cursor.selectionStart());
405 int temp = cursor.blockNumber();
406 cursor = textCursor();
407 cursor.setPosition(cursor.selectionEnd());
408 int diff = cursor.blockNumber() - temp;
424 case Qt::Key_Backtab:
428 QPlainTextEdit::keyPressEvent(e);
static const char *const INDENT_STRING
static const char *const PYTHON_COMMENT_STR
filament::Texture::InternalFormat format
CodeEditor(EditorSettings *settings, QWidget *parent=nullptr)
bool loadFile(const QString &fileName)
bool saveFile(const QString &fileName)
QString userFriendlyCurrentFile()
void lineNumberAreaPaintEvent(QPaintEvent *event)
void closeEvent(QCloseEvent *event) override
void resizeEvent(QResizeEvent *event) override
void keyPressEvent(QKeyEvent *e) override
bool eventFilter(QObject *target, QEvent *event) override
int lineNumberAreaWidth()
QColor foregroundColor() const
Color to be used for regular text.
QColor currentLineHighlightColor() const
Color to be used if a highlight of the current line is shown.
QColor backgroundColor() const
Color to be used as the background for the displayed text.
const ColorScheme & colorScheme() const
bool shouldHighlightCurrentLine() const
void useColorScheme(const ColorScheme &colorScheme)
std::string space(size_t n)
constexpr Rgb black(0, 0, 0)
constexpr Rgb green(0, MAX, 0)