| from PySide.QtWidgets import QWidget, QPlainTextEdit |
| from PySide.QtGui import QPainter, QFont |
| from PySide.QtCore import Qt, QRect, QSize |
|
|
|
|
| class LineNumberArea(QWidget): |
| def __init__(self, editor): |
| super().__init__(editor) |
| self.editor = editor |
|
|
| def sizeHint(self): |
| return QSize(self.editor.fontMetrics().horizontalAdvance("999") + 4, 0) |
|
|
| def paintEvent(self, event): |
| painter = QPainter(self) |
| painter.fillRect(event.rect(), Qt.black) |
| font = QFont() |
| font.setFamily(self.editor.font().family()) |
| font.setFixedPitch(self.editor.font().fixedPitch()) |
| font.setPointSize(self.editor.font().pointSize()) |
| painter.setFont(font) |
|
|
| block = self.editor.firstVisibleBlock() |
| blockNumber = block.blockNumber() |
| top = self.editor.blockBoundingGeometry(block).translated(self.editor.contentOffset()).top() |
| bottom = top + self.editor.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.gray) |
| painter.drawText( |
| -6, |
| int(top), |
| self.width(), |
| self.editor.fontMetrics().height(), |
| Qt.AlignRight, |
| number, |
| ) |
|
|
| block = block.next() |
| top = bottom |
| bottom = top + self.editor.blockBoundingRect(block).height() |
| blockNumber += 1 |
|
|
|
|
| class CodeEditor(QPlainTextEdit): |
| def __init__(self, parent=None): |
| super().__init__(parent) |
| self.lineNumberArea = LineNumberArea(self) |
| self.blockCountChanged.connect(self.updateLineNumberAreaWidth) |
| self.updateRequest.connect(self.updateLineNumberArea) |
| self.verticalScrollBar().valueChanged.connect(self.lineNumberArea.update) |
|
|
| self.updateLineNumberAreaWidth(0) |
|
|
| def lineNumberAreaWidth(self): |
| digits = 2 |
| max_value = max(1, self.blockCount()) |
| while max_value >= 10: |
| max_value /= 10 |
| digits += 1 |
| space = 3 + self.fontMetrics().horizontalAdvance("9") * digits |
| return space |
|
|
| def updateLineNumberAreaWidth(self, newBlockCount): |
| self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0) |
|
|
| 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(0) |
|
|
| def resizeEvent(self, event): |
| super().resizeEvent(event) |
| cr = self.contentsRect() |
| self.lineNumberArea.setGeometry( |
| QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height()) |
| ) |
|
|
| def setText(self, text): |
| """Backward compatibility method for setText() calls.""" |
| self.setPlainText(text) |
|
|