From 857b1954051b6d04387958ea005413c51417056e Mon Sep 17 00:00:00 2001 From: Cristian Maureira-Fredes Date: Mon, 28 Jan 2019 13:33:55 +0100 Subject: Add codeeditor example Based on Qt's Code Editor example Change-Id: I17ba0dfbafcda5a599cd2ef051e842cdd4b6e305 Reviewed-by: Friedemann Kleint --- examples/widgets/codeeditor/codeeditor.py | 141 ++++++++++++++++++++++++++++++ examples/widgets/codeeditor/main.py | 52 +++++++++++ 2 files changed, 193 insertions(+) create mode 100644 examples/widgets/codeeditor/codeeditor.py create mode 100644 examples/widgets/codeeditor/main.py diff --git a/examples/widgets/codeeditor/codeeditor.py b/examples/widgets/codeeditor/codeeditor.py new file mode 100644 index 000000000..331069f4a --- /dev/null +++ b/examples/widgets/codeeditor/codeeditor.py @@ -0,0 +1,141 @@ +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +from PySide2.QtCore import Slot, Qt, QRect, QSize +from PySide2.QtGui import QColor, QPainter, QTextFormat +from PySide2.QtWidgets import QPlainTextEdit, QWidget, QTextEdit + + +class LineNumberArea(QWidget): + def __init__(self, editor): + QWidget.__init__(self, editor) + self.codeEditor = editor + + def sizeHint(self): + return QSize(self.codeEditor.line_number_area_width(), 0) + + def paintEvent(self, event): + self.codeEditor.lineNumberAreaPaintEvent(event) + + +class CodeEditor(QPlainTextEdit): + def __init__(self): + QPlainTextEdit.__init__(self) + self.line_number_area = LineNumberArea(self) + + self.blockCountChanged[int].connect(self.update_line_number_area_width) + self.updateRequest[QRect, int].connect(self.update_line_number_area) + self.cursorPositionChanged.connect(self.highlight_current_line) + + self.update_line_number_area_width(0) + self.highlight_current_line() + + def line_number_area_width(self): + digits = 1 + max_num = max(1, self.blockCount()) + while max_num >= 10: + max_num *= 0.1 + digits += 1 + + space = 3 + self.fontMetrics().width('9') * digits + return space + + def resizeEvent(self, e): + super().resizeEvent(e) + cr = self.contentsRect() + width = self.line_number_area_width() + rect = QRect(cr.left(), cr.top(), width, cr.height()) + self.line_number_area.setGeometry(rect) + + def lineNumberAreaPaintEvent(self, event): + painter = QPainter(self.line_number_area) + painter.fillRect(event.rect(), Qt.lightGray) + block = self.firstVisibleBlock() + block_number = block.blockNumber() + offset = self.contentOffset() + top = self.blockBoundingGeometry(block).translated(offset).top() + bottom = top + self.blockBoundingRect(block).height() + + while block.isValid() and top <= event.rect().bottom(): + if block.isVisible() and bottom >= event.rect().top(): + number = str(block_number + 1) + painter.setPen(Qt.black) + width = self.line_number_area.width() + height = self.fontMetrics().height() + painter.drawText(0, top, width, height, Qt.AlignRight, number) + + block = block.next() + top = bottom + bottom = top + self.blockBoundingRect(block).height() + block_number += 1 + + @Slot() + def update_line_number_area_width(self, newBlockCount): + self.setViewportMargins(self.line_number_area_width(), 0, 0, 0) + + @Slot() + def update_line_number_area(self, rect, dy): + if dy: + self.line_number_area.scroll(0, dy) + else: + width = self.line_number_area.width() + self.line_number_area.update(0, rect.y(), width, rect.height()) + + if rect.contains(self.viewport().rect()): + self.update_line_number_area_width(0) + + @Slot() + def highlight_current_line(self): + extra_selections = [] + + if not self.isReadOnly(): + selection = QTextEdit.ExtraSelection() + + line_color = QColor(Qt.yellow).lighter(160) + selection.format.setBackground(line_color) + + selection.format.setProperty(QTextFormat.FullWidthSelection, True) + + selection.cursor = self.textCursor() + selection.cursor.clearSelection() + + extra_selections.append(selection) + + self.setExtraSelections(extra_selections) diff --git a/examples/widgets/codeeditor/main.py b/examples/widgets/codeeditor/main.py new file mode 100644 index 000000000..14c2e0826 --- /dev/null +++ b/examples/widgets/codeeditor/main.py @@ -0,0 +1,52 @@ +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import sys +from PySide2.QtWidgets import QApplication +from codeeditor import CodeEditor + +"""PySide2 port of the widgets/codeeditor example from Qt5""" + +if __name__ == "__main__": + app = QApplication([]) + editor = CodeEditor() + editor.setWindowTitle("Code Editor Example") + editor.show() + sys.exit(app.exec_()) -- cgit v1.2.3