# -*- coding: utf-8 -*- # # AWL simulator - GUI edit widget # # Copyright 2012-2014 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # from __future__ import division, absolute_import, print_function, unicode_literals from awlsim.common.compat import * from awlsim.gui.util import * from awlsim.gui.cpuwidget import * def _setFontParams(font): font.setFamily("courier") font.setPointSize(10) font.setKerning(False) font.setFixedPitch(True) font.setStyleHint(QFont.TypeWriter, QFont.PreferBitmap) class EditSubWidget(QWidget): needRepaint = Signal(QPaintEvent) wasScrolled = Signal(QWheelEvent) contextMenuReq = Signal(QPoint) def __init__(self, editWidget): QWidget.__init__(self, editWidget) self.editWidget = editWidget def paintEvent(self, ev): self.needRepaint.emit(ev) ev.accept() def wheelEvent(self, ev): self.wasScrolled.emit(ev) def getPainter(self): p = QPainter(self) font = p.font() _setFontParams(font) p.setFont(font) return p def contextMenuEvent(self, ev): QWidget.contextMenuEvent(self, ev) self.contextMenuReq.emit(ev.globalPos()) class HeaderSubWidget(EditSubWidget): def __init__(self, editWidget): EditSubWidget.__init__(self, editWidget) def sizeHint(self): return QSize(0, self.editWidget.headerHeight()) class LineNumSubWidget(EditSubWidget): def __init__(self, editWidget): EditSubWidget.__init__(self, editWidget) def sizeHint(self): return QSize(self.editWidget.lineNumWidgetWidth(), 0) class CpuStatsSubWidget(EditSubWidget): def __init__(self, editWidget): EditSubWidget.__init__(self, editWidget) def sizeHint(self): return QSize(self.editWidget.cpuStatsWidgetWidth(), 0) def getBanner(self, showFlg): ret = [] if showFlg & CpuStatsEntry.SHOW_NER: ret.append("/FC") if showFlg & CpuStatsEntry.SHOW_VKE: ret.append("RLO") if showFlg & CpuStatsEntry.SHOW_STA: ret.append("STA") if showFlg & CpuStatsEntry.SHOW_OR: ret.append("OR") if showFlg & CpuStatsEntry.SHOW_OS: ret.append("OS") if showFlg & CpuStatsEntry.SHOW_OV: ret.append("OV") if showFlg & CpuStatsEntry.SHOW_A0: ret.append("CC0") if showFlg & CpuStatsEntry.SHOW_A1: ret.append("CC1") if showFlg & CpuStatsEntry.SHOW_BIE: ret.append("BR") if showFlg & CpuStatsEntry.SHOW_STW: ret.append("STW ") if showFlg & CpuStatsEntry.SHOW_ACCU1: ret.append("ACCU 1 ") if showFlg & CpuStatsEntry.SHOW_ACCU2: ret.append("ACCU 2 ") if showFlg & CpuStatsEntry.SHOW_ACCU3: ret.append("ACCU 3 ") if showFlg & CpuStatsEntry.SHOW_ACCU4: ret.append("ACCU 4 ") if showFlg & CpuStatsEntry.SHOW_AR1: ret.append("AR 1 ") if showFlg & CpuStatsEntry.SHOW_AR2: ret.append("AR 2 ") if showFlg & CpuStatsEntry.SHOW_DBREG: ret.append("DB ") if showFlg & CpuStatsEntry.SHOW_DIREG: ret.append("DI ") return " ".join(ret) class CpuStatsEntry(object): EnumGen.start SHOW_NER = EnumGen.bitmask SHOW_VKE = EnumGen.bitmask SHOW_STA = EnumGen.bitmask SHOW_OR = EnumGen.bitmask SHOW_OS = EnumGen.bitmask SHOW_OV = EnumGen.bitmask SHOW_A0 = EnumGen.bitmask SHOW_A1 = EnumGen.bitmask SHOW_BIE = EnumGen.bitmask SHOW_STW = EnumGen.bitmask SHOW_ACCU1 = EnumGen.bitmask SHOW_ACCU2 = EnumGen.bitmask SHOW_ACCU3 = EnumGen.bitmask SHOW_ACCU4 = EnumGen.bitmask SHOW_AR1 = EnumGen.bitmask SHOW_AR2 = EnumGen.bitmask SHOW_DBREG = EnumGen.bitmask SHOW_DIREG = EnumGen.bitmask EnumGen.end def __init__(self, stamp, insnDumpMsg): self.stamp = stamp self.insnDumpMsg = insnDumpMsg self.obsolete = False self.pruned = False def getText(self, showFlg): if self.pruned: return "[ ... ]" insnDumpMsg = self.insnDumpMsg ret = [] if showFlg & self.SHOW_NER: ret.append("%d " % ((insnDumpMsg.stw >> 0) & 1)) if showFlg & self.SHOW_VKE: ret.append("%d " % ((insnDumpMsg.stw >> 1) & 1)) if showFlg & self.SHOW_STA: ret.append("%d " % ((insnDumpMsg.stw >> 2) & 1)) if showFlg & self.SHOW_OR: ret.append("%d " % ((insnDumpMsg.stw >> 3) & 1)) if showFlg & self.SHOW_OS: ret.append("%d " % ((insnDumpMsg.stw >> 4) & 1)) if showFlg & self.SHOW_OV: ret.append("%d " % ((insnDumpMsg.stw >> 5) & 1)) if showFlg & self.SHOW_A0: ret.append("%d " % ((insnDumpMsg.stw >> 6) & 1)) if showFlg & self.SHOW_A1: ret.append("%d " % ((insnDumpMsg.stw >> 7) & 1)) if showFlg & self.SHOW_BIE: ret.append("%d " % ((insnDumpMsg.stw >> 8) & 1)) if showFlg & self.SHOW_STW: stw = [] for i in range(S7StatusWord.NR_BITS - 1, -1, -1): stw.append('1' if ((insnDumpMsg.stw >> i) & 1) else '0') if i % 4 == 0 and i: stw.append('_') ret.append("".join(stw)) if showFlg & self.SHOW_ACCU1: ret.append("%08X" % insnDumpMsg.accu1) if showFlg & self.SHOW_ACCU2: ret.append("%08X" % insnDumpMsg.accu2) if showFlg & self.SHOW_ACCU3: ret.append("%08X" % insnDumpMsg.accu3) if showFlg & self.SHOW_ACCU4: ret.append("%08X" % insnDumpMsg.accu4) if showFlg & self.SHOW_AR1: ret.append("%08X" % insnDumpMsg.ar1) if showFlg & self.SHOW_AR2: ret.append("%08X" % insnDumpMsg.ar2) if showFlg & self.SHOW_DBREG: if insnDumpMsg.db: dbreg = str(insnDumpMsg.db) dbreg += " " * (5 - len(dbreg)) ret.append(dbreg) else: ret.append("-- ") if showFlg & self.SHOW_DIREG: if insnDumpMsg.db: direg = str(insnDumpMsg.db) direg += " " * (5 - len(direg)) ret.append(direg) else: ret.append("-- ") return " ".join(ret) class CheckAction(QAction): def __init__(self, name, toggleCallback=None, parent=None): QAction.__init__(self, name, parent) self.setCheckable(True) if toggleCallback: self.toggled.connect(toggleCallback) class CpuStatsContextMenu(QMenu): closed = Signal() def __init__(self, parent=None): QMenu.__init__(self, parent) itemsMenu = QMenu("Online items", self) self.__action_NER = CheckAction("Status bit: /FC (/ER)", self.__actionToggled, self) itemsMenu.addAction(self.__action_NER) self.__action_VKE = CheckAction("Status bit: RLO (VKE)", self.__actionToggled, self) itemsMenu.addAction(self.__action_VKE) self.__action_STA = CheckAction("Status bit: STA", self.__actionToggled, self) itemsMenu.addAction(self.__action_STA) self.__action_OR = CheckAction("Status bit: OR", self.__actionToggled, self) itemsMenu.addAction(self.__action_OR) self.__action_OS = CheckAction("Status bit: OS", self.__actionToggled, self) itemsMenu.addAction(self.__action_OS) self.__action_OV = CheckAction("Status bit: OV", self.__actionToggled, self) itemsMenu.addAction(self.__action_OV) self.__action_A0 = CheckAction("Status bit: CC0 (A0)", self.__actionToggled, self) itemsMenu.addAction(self.__action_A0) self.__action_A1 = CheckAction("Status bit: CC1 (A1)", self.__actionToggled, self) itemsMenu.addAction(self.__action_A1) self.__action_BIE = CheckAction("Status bit: BR (BIE)", self.__actionToggled, self) itemsMenu.addAction(self.__action_BIE) self.__action_STW = CheckAction("Full status word", self.__actionToggled, self) itemsMenu.addAction(self.__action_STW) self.__action_accu1 = CheckAction("Accu 1", self.__actionToggled, self) itemsMenu.addAction(self.__action_accu1) self.__action_accu2 = CheckAction("Accu 2", self.__actionToggled, self) itemsMenu.addAction(self.__action_accu2) self.__action_accu3 = CheckAction("Accu 3", self.__actionToggled, self) itemsMenu.addAction(self.__action_accu3) self.__action_accu4 = CheckAction("Accu 4", self.__actionToggled, self) itemsMenu.addAction(self.__action_accu4) self.__action_ar1 = CheckAction("AR 1", self.__actionToggled, self) itemsMenu.addAction(self.__action_ar1) self.__action_ar2 = CheckAction("AR 2", self.__actionToggled, self) itemsMenu.addAction(self.__action_ar2) self.__action_db = CheckAction("DB register", self.__actionToggled, self) itemsMenu.addAction(self.__action_db) self.__action_di = CheckAction("DI register", self.__actionToggled, self) itemsMenu.addAction(self.__action_di) self.addMenu(itemsMenu) def setShowFlags(self, showFlg): self.__action_NER.setChecked(bool(showFlg & CpuStatsEntry.SHOW_NER)) self.__action_VKE.setChecked(bool(showFlg & CpuStatsEntry.SHOW_VKE)) self.__action_STA.setChecked(bool(showFlg & CpuStatsEntry.SHOW_STA)) self.__action_OR.setChecked(bool(showFlg & CpuStatsEntry.SHOW_OR)) self.__action_OS.setChecked(bool(showFlg & CpuStatsEntry.SHOW_OS)) self.__action_OV.setChecked(bool(showFlg & CpuStatsEntry.SHOW_OV)) self.__action_A0.setChecked(bool(showFlg & CpuStatsEntry.SHOW_A0)) self.__action_A1.setChecked(bool(showFlg & CpuStatsEntry.SHOW_A1)) self.__action_BIE.setChecked(bool(showFlg & CpuStatsEntry.SHOW_BIE)) self.__action_STW.setChecked(bool(showFlg & CpuStatsEntry.SHOW_STW)) self.__action_accu1.setChecked(bool(showFlg & CpuStatsEntry.SHOW_ACCU1)) self.__action_accu2.setChecked(bool(showFlg & CpuStatsEntry.SHOW_ACCU2)) self.__action_accu3.setChecked(bool(showFlg & CpuStatsEntry.SHOW_ACCU3)) self.__action_accu4.setChecked(bool(showFlg & CpuStatsEntry.SHOW_ACCU4)) self.__action_ar1.setChecked(bool(showFlg & CpuStatsEntry.SHOW_AR1)) self.__action_ar2.setChecked(bool(showFlg & CpuStatsEntry.SHOW_AR2)) self.__action_db.setChecked(bool(showFlg & CpuStatsEntry.SHOW_DBREG)) self.__action_di.setChecked(bool(showFlg & CpuStatsEntry.SHOW_DIREG)) def getShowFlags(self): showFlg = 0 if self.__action_NER.isChecked(): showFlg |= CpuStatsEntry.SHOW_NER if self.__action_VKE.isChecked(): showFlg |= CpuStatsEntry.SHOW_VKE if self.__action_STA.isChecked(): showFlg |= CpuStatsEntry.SHOW_STA if self.__action_OR.isChecked(): showFlg |= CpuStatsEntry.SHOW_OR if self.__action_OS.isChecked(): showFlg |= CpuStatsEntry.SHOW_OS if self.__action_OV.isChecked(): showFlg |= CpuStatsEntry.SHOW_OV if self.__action_A0.isChecked(): showFlg |= CpuStatsEntry.SHOW_A0 if self.__action_A1.isChecked(): showFlg |= CpuStatsEntry.SHOW_A1 if self.__action_BIE.isChecked(): showFlg |= CpuStatsEntry.SHOW_BIE if self.__action_STW.isChecked(): showFlg |= CpuStatsEntry.SHOW_STW if self.__action_accu1.isChecked(): showFlg |= CpuStatsEntry.SHOW_ACCU1 if self.__action_accu2.isChecked(): showFlg |= CpuStatsEntry.SHOW_ACCU2 if self.__action_accu3.isChecked(): showFlg |= CpuStatsEntry.SHOW_ACCU3 if self.__action_accu4.isChecked(): showFlg |= CpuStatsEntry.SHOW_ACCU4 if self.__action_ar1.isChecked(): showFlg |= CpuStatsEntry.SHOW_AR1 if self.__action_ar2.isChecked(): showFlg |= CpuStatsEntry.SHOW_AR2 if self.__action_db.isChecked(): showFlg |= CpuStatsEntry.SHOW_DBREG if self.__action_di.isChecked(): showFlg |= CpuStatsEntry.SHOW_DIREG return showFlg def __actionToggled(self, newState): self.closed.emit() class EditWidget(QPlainTextEdit): codeChanged = Signal() visibleRangeChanged = Signal() __aniChars = ( ' ', '.', 'o', '0', 'O', '0', 'o', '.' ) def __init__(self, mainWidget): QPlainTextEdit.__init__(self, mainWidget) self.mainWidget = mainWidget self.__aniTimer = QTimer(self) self.__aniTimer.setSingleShot(False) self.__aniTimer.timeout.connect(self.__animation) self.__updateFonts() self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setLineWrapMode(QPlainTextEdit.NoWrap) self.setTabStopWidth(self.tabStopWidth() // 2) self.headerWidget = HeaderSubWidget(self) self.lineNumWidget = LineNumSubWidget(self) self.cpuStatsWidget = CpuStatsSubWidget(self) self.__source = AwlSource(name = "Unnamed source") self.__needSourceUpdate = True self.__runStateCopy = CpuWidget.STATE_STOP self.__nextHdrUpdate = 0 self.__hdrAniStat = 0 self.__cpuStatsMenu = CpuStatsContextMenu(self) self.__cpuStatsMask = 0 self.enableCpuStats(enabled=False, force=True) self.setCpuStatsMask(CpuStatsEntry.SHOW_VKE |\ CpuStatsEntry.SHOW_STA |\ CpuStatsEntry.SHOW_ACCU1 |\ CpuStatsEntry.SHOW_ACCU2) self.resetCpuStats(True) self.__textChangeBlocked = 0 self.textChanged.connect(self.__textChanged) self.blockCountChanged.connect(self.__updateMargins) self.updateRequest.connect(self.__updateExtraWidgets) self.headerWidget.needRepaint.connect(self.__repaintHeaderWidget) self.lineNumWidget.needRepaint.connect(self.__repaintLineNumWidget) self.cpuStatsWidget.needRepaint.connect(self.__repaintCpuStatsWidget) self.headerWidget.wasScrolled.connect(self.__forwardWheelEvent) self.headerWidget.contextMenuReq.connect(self.__cpuStatsContextMenuPopup) self.lineNumWidget.wasScrolled.connect(self.__forwardWheelEvent) self.cpuStatsWidget.wasScrolled.connect(self.__forwardWheelEvent) self.cpuStatsWidget.contextMenuReq.connect(self.__cpuStatsContextMenuPopup) self.__cpuStatsMenu.closed.connect(self.__cpuStatsContextMenuClosed) def setSource(self, source): self.__textChangeBlocked += 1 try: self.__source = source.dup() self.__source.sourceBytes = b"" sourceBytes = source.sourceBytes try: sourceText = sourceBytes.decode(AwlParser.TEXT_ENCODING, errors="strict") except UnicodeError: MessageBox.error(self, "The AWL/STL code contains " "non-%s-characters. These were ignored and stripped " "from the code." % AwlParser.TEXT_ENCODING) sourceText = sourceBytes.decode(AwlParser.TEXT_ENCODING, errors="ignore") self.setPlainText(sourceText) self.resetCpuStats() finally: self.__textChangeBlocked -= 1 self.__needSourceUpdate = True def __updateSource(self): sourceText = self.toPlainText() # Convert to DOS-style line endings sourceText = "\r\n".join(sourceText.splitlines()) + "\r\n" # Convert to binary try: sourceBytes = sourceText.encode(AwlParser.TEXT_ENCODING, errors="strict") self.__source.sourceBytes = sourceBytes except UnicodeError: MessageBox.error(self, "The AWL/STL code contains " "non-%s-characters. These were ignored and stripped " "from the code." % AwlParser.TEXT_ENCODING) sourceBytes = sourceText.encode(AwlParser.TEXT_ENCODING, errors="ignore") self.__source.sourceBytes = sourceBytes self.setSource(self.__source) self.__needSourceUpdate = False def getSource(self): if self.__needSourceUpdate: self.__updateSource() return self.__source def runStateChanged(self, newState): self.__runStateCopy = newState if newState == CpuWidget.STATE_INIT: self.resetCpuStats() if newState == CpuWidget.STATE_RUN: self.__aniTimer.start(200) else: self.__aniTimer.stop() if self.__cpuStatsEnabled: self.cpuStatsWidget.update() self.headerWidget.update() def __eachVisibleLine(self): block = self.firstVisibleBlock() top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top() bottom = top + self.blockBoundingRect(block).height() while block.isValid() and\ block.isVisible() and\ top <= self.viewport().rect().bottom(): yield (block.blockNumber() + 1, top) block = block.next() top = bottom bottom = top + self.blockBoundingRect(block).height() def getVisibleLineRange(self): firstVisibleLine = lastVisibleLine = 0 for lineNr, yOffset in self.__eachVisibleLine(): if firstVisibleLine == 0 or\ lineNr < firstVisibleLine: firstVisibleLine = lineNr if lineNr > lastVisibleLine: lastVisibleLine = lineNr return firstVisibleLine, lastVisibleLine def __updateFonts(self): fmt = self.currentCharFormat() font = fmt.font() _setFontParams(font) fmt.setFont(font) self.setCurrentCharFormat(fmt) font = self.font() _setFontParams(font) self.setFont(font) self.__charHeight = self.fontMetrics().height() self.setTabStopWidth(self.fontMetrics().width("X") * 8) def enableCpuStats(self, enabled=True, force=False): if force or enabled != self.__cpuStatsEnabled: self.__cpuStatsEnabled = enabled self.__updateMargins() self.__updateGeo() def setCpuStatsMask(self, newMask): self.__cpuStatsMask = newMask if self.__cpuStatsEnabled: self.__updateMargins() self.__updateGeo() def __cpuStatsContextMenuPopup(self, globalPos): if self.__cpuStatsEnabled: self.__cpuStatsMenu.setShowFlags(self.__cpuStatsMask) self.__cpuStatsMenu.popup(globalPos) def __cpuStatsContextMenuClosed(self): self.setCpuStatsMask(self.__cpuStatsMenu.getShowFlags()) def resetCpuStats(self, force=False): if not force and not self.__lineCpuStats: return self.__lineCpuStats = { } self.__cpuStatsCount = 0 self.__cpuStatsUpdate = 1 self.__cpuStatsStamp = 0 self.__updateMargins() self.headerWidget.update() self.cpuStatsWidget.update() def updateCpuStats_afterInsn(self, insnDumpMsg): # insnDumpMsg => AwlSimMessage_INSNDUMP instance if not self.__cpuStatsEnabled: return if insnDumpMsg.sourceId != self.__source.identHash: # Discard old messages that were still in the queue. return # Save the instruction dump self.__lineCpuStats[insnDumpMsg.lineNr] =\ CpuStatsEntry(self.__cpuStatsStamp, insnDumpMsg) # Update the stats widget self.__cpuStatsCount += 1 if self.__cpuStatsCount >= self.__cpuStatsUpdate: self.__cpuStatsCount = 0 self.__cpuStatsUpdate = 128 self.cpuStatsWidget.update() # First instruction in cycle? if insnDumpMsg.serial == 0: # Update the 'obsolete'-flag based on the timestamp for ent in self.__lineCpuStats.values(): ent.obsolete = (ent.stamp != self.__cpuStatsStamp) # Advance the timestamp self.__cpuStatsStamp += 1 def __pruneInvisibleCpuStats(self): firstLine, lastLine = self.getVisibleLineRange() for line, stats in self.__lineCpuStats.items(): if line < firstLine or line > lastLine: stats.pruned = True stats.obsolete = True def __animation(self): self.__hdrAniStat = (self.__hdrAniStat + 1) %\ len(self.__aniChars) self.headerWidget.update() def __forwardWheelEvent(self, ev): self.wheelEvent(ev) def lineNumWidgetWidth(self): digi, bcnt = 1, self.blockCount() while bcnt > 9: digi, bcnt = digi + 1, bcnt // 10 digi += 1 # colon metr = self.lineNumWidget.fontMetrics() return 5 + 5 + metr.width("_" * digi) def cpuStatsWidgetWidth(self): if not self.__cpuStatsEnabled: return 0 metr = self.cpuStatsWidget.fontMetrics() return 5 + 5 + metr.width(self.cpuStatsWidget.getBanner(self.__cpuStatsMask).replace(" ", "_")) def headerHeight(self): return 5 + 5 + self.__charHeight def __updateMargins(self): self.setViewportMargins(self.lineNumWidgetWidth(), self.headerHeight(), self.cpuStatsWidgetWidth(), 0) def sizeHint(self): sh = QPlainTextEdit.sizeHint(self) sh.setWidth(650 +\ self.lineNumWidgetWidth() +\ self.cpuStatsWidgetWidth()) return sh def __updateHeaderWidgetGeo(self): cont = self.contentsRect() rect = QRect(cont.left(), cont.top(), cont.width(), self.headerHeight()) self.headerWidget.setGeometry(rect) def __updateLineNumWidgetGeo(self): cont = self.contentsRect() rect = QRect(cont.left(), cont.top() + self.headerHeight(), self.lineNumWidgetWidth(), cont.height()) self.lineNumWidget.setGeometry(rect) def __updateCpuStatsWidgetGeo(self): if self.__cpuStatsEnabled: vp, cont = self.viewport(), self.contentsRect() rect = QRect(vp.width() + self.lineNumWidgetWidth(), cont.top() + self.headerHeight(), self.cpuStatsWidgetWidth(), cont.height()) self.cpuStatsWidget.setGeometry(rect) self.cpuStatsWidget.show() else: self.cpuStatsWidget.hide() def __updateGeo(self): self.__updateHeaderWidgetGeo() self.__updateLineNumWidgetGeo() self.__updateCpuStatsWidgetGeo() def __updateExtraWidgets(self, rect, dy): if dy: self.headerWidget.scroll(0, dy) self.lineNumWidget.scroll(0, dy) self.cpuStatsWidget.scroll(0, dy) self.__pruneInvisibleCpuStats() self.visibleRangeChanged.emit() return self.headerWidget.update(0, rect.y(), self.headerWidget.width(), rect.height()) self.lineNumWidget.update(0, rect.y(), self.lineNumWidget.width(), rect.height()) self.cpuStatsWidget.update(0, rect.y(), self.cpuStatsWidget.width(), rect.height()) if rect.contains(self.viewport().rect()): self.__updateMargins() def resizeEvent(self, ev): QPlainTextEdit.resizeEvent(self, ev) self.__updateGeo() __runStateToText = { CpuWidget.STATE_STOP : "-- CPU STOPPED --", CpuWidget.STATE_INIT : "Initializing simulator...", CpuWidget.STATE_LOAD : "Loading code...", } def __repaintHeaderWidget(self, ev): p = self.headerWidget.getPainter() p.fillRect(ev.rect(), Qt.lightGray) if self.__runStateCopy == CpuWidget.STATE_RUN: runText = self.__aniChars[self.__hdrAniStat] else: runText = self.__runStateToText[self.__runStateCopy] metr = self.headerWidget.fontMetrics() p.drawText(5, 5, metr.width(runText.replace(" ", "_")), self.headerWidget.height(), Qt.AlignLeft, runText) if self.__cpuStatsEnabled: # Map the starting point pt = self.cpuStatsWidget.mapToGlobal(QPoint(0, 0)) pt = self.headerWidget.mapFromGlobal(pt) p.drawText(pt.x() + 5, 5, self.headerWidget.width() - pt.x() - 5, self.headerWidget.height(), Qt.AlignLeft, self.cpuStatsWidget.getBanner(self.__cpuStatsMask)) def __repaintLineNumWidget(self, ev): p = self.lineNumWidget.getPainter() rect = ev.rect() p.fillRect(rect, Qt.lightGray) rect.setLeft(rect.left() + rect.width() - 3) rect.setWidth(3) p.fillRect(rect, Qt.white) p.setPen(Qt.black) for lineNr, yOffset in self.__eachVisibleLine(): p.drawText(-5, yOffset, self.lineNumWidget.width(), self.__charHeight, Qt.AlignRight, "%d:" % lineNr) def __repaintCpuStatsWidget(self, ev): p = self.cpuStatsWidget.getPainter() rect = ev.rect() p.fillRect(rect, Qt.lightGray) rect.setWidth(3) p.fillRect(rect, Qt.white) for lineNr, yOffset in self.__eachVisibleLine(): statsEnt = self.__lineCpuStats.get(lineNr) if statsEnt: if statsEnt.obsolete: p.setPen(Qt.darkGray) else: p.setPen(Qt.black) p.drawText(5, yOffset, self.cpuStatsWidget.width(), self.__charHeight, Qt.AlignLeft, statsEnt.getText(self.__cpuStatsMask)) def __textChanged(self): self.__updateFonts() if self.__textChangeBlocked: return self.__needSourceUpdate = True self.codeChanged.emit() self.resetCpuStats()