Source code for sas.qtgui.Utilities.CodeEditor


from PyQt5.QtCore import Qt, QRect, QSize
from PyQt5.QtWidgets import QWidget, QPlainTextEdit, QTextEdit
from PyQt5.QtGui import QColor, QPainter, QTextFormat


[docs]class QLineNumberArea(QWidget):
[docs] def __init__(self, editor): super().__init__(editor) self.codeEditor = editor
[docs] def sizeHint(self): return QSize(self.editor.lineNumberAreaWidth(), 0)
[docs] def paintEvent(self, event): self.codeEditor.lineNumberAreaPaintEvent(event)
[docs]class QCodeEditor(QPlainTextEdit):
[docs] def __init__(self, parent=None): super().__init__(parent) self.lineNumberArea = QLineNumberArea(self) self.setLineWrapMode(QPlainTextEdit.NoWrap) self.blockCountChanged.connect(self.updateLineNumberAreaWidth) self.updateRequest.connect(self.updateLineNumberArea) self.cursorPositionChanged.connect(self.highlightCurrentLine) self.updateLineNumberAreaWidth()
[docs] def lineNumberAreaWidth(self): digits = 1 max_value = max(1, self.blockCount()) while max_value >= 10: max_value /= 10 digits += 1 # line number display width padded with extra pixels. # Chosen to "look nice", hence magic numbers space = 3 + self.fontMetrics().width('9') * digits return space
[docs] def updateLineNumberAreaWidth(self): self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
[docs] def updateLineNumberArea(self, rect, dy): 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()
[docs] def resizeEvent(self, event): super().resizeEvent(event) cr = self.contentsRect() self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height()))
[docs] def highlightCurrentLine(self): extraSelections = [] if not self.isReadOnly(): selection = QTextEdit.ExtraSelection() lineColor = QColor(Qt.yellow).lighter(160) selection.format.setBackground(lineColor) selection.format.setProperty(QTextFormat.FullWidthSelection, True) selection.cursor = self.textCursor() selection.cursor.clearSelection() extraSelections.append(selection) self.setExtraSelections(extraSelections)
[docs] def lineNumberAreaPaintEvent(self, event): painter = QPainter(self.lineNumberArea) painter.fillRect(event.rect(), Qt.lightGray) block = self.firstVisibleBlock() blockNumber = block.blockNumber() top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top() bottom = top + self.blockBoundingRect(block).height() # Just to make sure I use the right font height = self.fontMetrics().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(), height, Qt.AlignRight, number) block = block.next() top = bottom bottom = top + self.blockBoundingRect(block).height() blockNumber += 1
if __name__ == '__main__': import sys from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) codeEditor = QCodeEditor() codeEditor.show() sys.exit(app.exec_())