diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/linenumberarea.py b/plugins/extensions/pykrita/plugin/plugins/scripter/linenumberarea.py new file mode 100644 index 0000000000..d7ac02a844 --- /dev/null +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/linenumberarea.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from PyQt5.QtWidgets import * +from PyQt5.QtCore import * + +class LineNumberArea(QWidget): + + def __init__(self, editor): + super(LineNumberArea, self).__init__(editor) + self.codeEditor = editor + + def sizeHint(self): + return QSize(self.codeEditor.lineNumberAreaWidth(), 0) + + def paintEvent(self, event): + """It Invokes the draw method(lineNumberAreaPaintEvent) in CodeEditor""" + self.codeEditor.lineNumberAreaPaintEvent(event) diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/pythoneditor.py b/plugins/extensions/pykrita/plugin/plugins/scripter/pythoneditor.py new file mode 100644 index 0000000000..03d808028d --- /dev/null +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/pythoneditor.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +from PyQt5.QtCore import * +from PyQt5.QtWidgets import * +from scripter import linenumberarea +from PyQt5.QtGui import * + +class CodeEditor(QPlainTextEdit): + + def __init__(self, parent=None): + super(CodeEditor, self).__init__(parent) + + self.setLineWrapMode(self.NoWrap) + + self.lineNumberArea = linenumberarea.LineNumberArea(self) + + self.blockCountChanged.connect(self.updateLineNumberAreaWidth) + self.updateRequest.connect(self.updateLineNumberArea) + self.cursorPositionChanged.connect(self.highlightCurrentLine) + + self.updateLineNumberAreaWidth() + self.highlightCurrentLine() + + def lineNumberAreaWidth(self): + """The lineNumberAreaWidth is the quatity of decimal places in blockCount""" + digits = 1 + max_ = max(1, self.blockCount()) + while (max_ >= 10): + max_ /= 10 + digits += 1 + + space = 3 + self.fontMetrics().width('9') * digits + + return space + + def resizeEvent(self, event): + super(CodeEditor, self).resizeEvent(event) + + qRect = self.contentsRect(); + self.lineNumberArea.setGeometry(QRect(qRect.left(), qRect.top(), self.lineNumberAreaWidth(), qRect.height())); + + def updateLineNumberAreaWidth(self): + self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0) + + def updateLineNumberArea(self, rect, dy): + """ This slot is invoked when the editors viewport has been scrolled """ + + if dy: + self.lineNumberArea.scroll(0, dy) + else: + self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height()) + + if rect.contains(self.viewport().rect()): + self.updateLineNumberAreaWidth() + + def lineNumberAreaPaintEvent(self, event): + """This method draws the current lineNumberArea for while""" + painter = QPainter(self.lineNumberArea) + painter.fillRect(event.rect(), Qt.lightGray) + + block = self.firstVisibleBlock() + blockNumber = block.blockNumber() + top = int(self.blockBoundingGeometry(block).translated(self.contentOffset()).top()) + bottom = top + int(self.blockBoundingRect(block).height()) + + while block.isValid() and top <= event.rect().bottom(): + if block.isVisible() and bottom >= event.rect().top(): + number = str(blockNumber + 1) + painter.setPen(Qt.black) + painter.drawText(0, top, self.lineNumberArea.width(), self.fontMetrics().height(), + Qt.AlignRight, number) + + block = block.next() + top = bottom + bottom = top + int(self.blockBoundingRect(block).height()) + blockNumber += 1 + + def highlightCurrentLine(self): + """Highlight current line under cursor""" + currentSelection = QTextEdit.ExtraSelection() + + lineColor = QColor(Qt.gray).lighter(180) + currentSelection.format.setBackground(lineColor) + currentSelection.format.setProperty(QTextFormat.FullWidthSelection, True) + currentSelection.cursor = self.textCursor() + currentSelection.cursor.clearSelection() + self.setExtraSelections([currentSelection]) diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/scripter.py b/plugins/extensions/pykrita/plugin/plugins/scripter/scripter.py index 0ab2cbb649..fff9fdbb10 100644 --- a/plugins/extensions/pykrita/plugin/plugins/scripter/scripter.py +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/scripter.py @@ -1,71 +1,70 @@ from PyQt5.QtGui import * from PyQt5.QtWidgets import * from krita import * -from scripter import syntax +from scripter import syntax, pythoneditor import sys class docWrapper: def __init__(self, textdocument): self.textdocument = textdocument def write(self, text, view = None): cursor = QTextCursor(self.textdocument) cursor.clearSelection() cursor.movePosition(QTextCursor.End) cursor.insertText(text) class ScripterViewExtension(ViewExtension): def __init__(self, parent): super().__init__(parent) def setup(self): print("Scripter setup") action = Krita.instance().createAction("Scripter") action.triggered.connect(self.showScripter) def execute(self): stdout = sys.stdout stderr = sys.stderr output = docWrapper(self.output.document()) output.write("======================================\n") sys.stdout = output sys.stderr = output script = self.editor.document().toPlainText() try: bc = compile(script, "", "exec") except Exception as e: QMessageBox.critical(self.editor, "Error compiling script", str(e)) return exec(bc) sys.stdout = stdout sys.stderr = stderr def showScripter(self): dialog = QDialog() dialog.setWindowModality(Qt.NonModal) - self.editor = QPlainTextEdit() + self.editor = pythoneditor.CodeEditor() f = QFont("monospace", 10, QFont.Normal) f.setFixedPitch(True) self.editor.document().setDefaultFont(f) highlight = syntax.PythonHighlighter(self.editor.document()) vbox = QVBoxLayout(dialog) vbox.addWidget(self.editor) button = QPushButton("Execute") button.clicked.connect(self.execute) vbox.addWidget(button) self.output = QPlainTextEdit() vbox.addWidget(self.output) dialog.resize(400, 500) dialog.setWindowTitle("Scripter") dialog.setSizeGripEnabled(True) dialog.show() dialog.activateWindow() dialog.exec() Krita.instance().addViewExtension(ScripterViewExtension(Krita.instance())) -