Source code for ccpn.ui.gui.widgets.SequenceWidget
"""
This file contains the SequenceModule module
GWV: modified 1-9/12/2016
GWV: 13/04/2017: Disconnected from Sequence Graph; Needs refactoring
GWV: 22/4/2018: New handling of colours
"""
#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (http://www.ccpn.ac.uk) 2014 - 2021"
__credits__ = ("Ed Brooksbank, Joanna Fox, Victoria A Higman, Luca Mureddu, Eliza Płoskoń",
"Timothy J Ragan, Brian O Smith, Gary S Thompson & Geerten W Vuister")
__licence__ = ("CCPN licence. See http://www.ccpn.ac.uk/v3-software/downloads/license")
__reference__ = ("Skinner, S.P., Fogh, R.H., Boucher, W., Ragan, T.J., Mureddu, L.G., & Vuister, G.W.",
"CcpNmr AnalysisAssign: a flexible platform for integrated NMR analysis",
"J.Biomol.Nmr (2016), 66, 111-124, http://doi.org/10.1007/s10858-016-0060-y")
#=========================================================================================
# Last code modification
#=========================================================================================
__modifiedBy__ = "$modifiedBy: Ed Brooksbank $"
__dateModified__ = "$dateModified: 2021-09-28 17:41:56 +0100 (Tue, September 28, 2021) $"
__version__ = "$Revision: 3.0.4 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: CCPN $"
__date__ = "$Date: 2017-04-07 10:28:41 +0000 (Fri, April 07, 2017) $"
#=========================================================================================
# Start of code
#=========================================================================================
import typing
from PyQt5 import QtCore, QtGui, QtWidgets
from collections.abc import Iterable
from ccpn.core.Chain import Chain
from ccpn.core.Residue import Residue
from ccpn.core.NmrResidue import NmrResidue
from ccpn.core.NmrChain import NmrChain
from ccpn.core.lib.Notifiers import Notifier
from ccpn.ui.gui.guiSettings import getColours
from ccpn.ui.gui.guiSettings import GUICHAINLABEL_TEXT, \
GUICHAINRESIDUE_DRAGENTER, GUICHAINRESIDUE_DRAGLEAVE, \
GUICHAINRESIDUE_UNASSIGNED, GUICHAINRESIDUE_ASSIGNED, \
GUICHAINRESIDUE_POSSIBLE, GUICHAINRESIDUE_WARNING, \
SEQUENCEMODULE_DRAGMOVE, SEQUENCEMODULE_TEXT, BORDERNOFOCUS, BORDERFOCUS
from ccpn.ui.gui.widgets.Base import Base
# from ccpn.ui.gui.guiSettings import fixedWidthFont, fixedWidthLargeFont, helvetica8
# from ccpn.ui.gui.guiSettings import textFontHugeSpacing as fontSpacing
from ccpn.ui.gui.modules.CcpnModule import CcpnModule
from ccpn.ui.gui.widgets.MessageDialog import showYesNo
from ccpn.util.Logging import getLogger
from ccpn.ui.gui.widgets.MessageDialog import progressManager, showWarning
from ccpn.ui.gui.widgets.Frame import Frame
from ccpn.ui.gui.widgets.Font import setWidgetFont, getFontHeight
[docs]class SequenceWidget():
"""
The module displays all chains in the project as one-letter amino acids. The one letter residue
sequence codes are all instances of the GuiChainResidue class and the style applied to a residue
indicates its assignment state and, when coupled with the Sequence Graph module, indicates if a
stretch of residues matches a given stretch of connected NmrResidues. The QGraphicsScene and
QGraphicsView instances provide the canvas on to which the amino acids representations are drawn.
"""
# includeSettingsWidget = False
# maxSettingsState = 2 # states are defined as: 0: invisible, 1: both visible, 2: only settings visible
# settingsPosition = 'left'
#
# _alreadyOpened = False
# _onlySingleInstance = True
# _currentModule = None
#
# className = 'SequenceModule'
def __init__(self, moduleParent=None, parent=None, mainWindow=None, name='Sequence', chains=None):
#CcpnModule.__init__(self, size=(10, 30), name='Sequence', closable=False)
#TODO: make closable
# CcpnModule.__init__(self, mainWindow=mainWindow, name=name)
# super(SequenceModule, self).__init__(setLayout=True)
self.moduleParent = moduleParent
self._parent = parent
self.mainWindow = mainWindow
self.project = mainWindow.application.project
#self.label.hide()
self._chains = chains or []
# self.setAcceptDrops(True)
self._parent.setAcceptDrops(True)
self.scrollArea = QtWidgets.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.scene = QtWidgets.QGraphicsScene(self._parent)
self.scrollContents = QtWidgets.QGraphicsView(self.scrollArea.scene, self._parent)
self.scrollContents.setAcceptDrops(True)
self.scrollContents.setInteractive(True)
self.scrollContents.setAlignment(QtCore.Qt.AlignTop)
self.scrollContents.setGeometry(QtCore.QRect(0, 0, 380, 1000))
self.horizontalLayout2 = QtWidgets.QHBoxLayout(self.scrollContents)
self.scrollArea.setWidget(self.scrollContents)
self.colours = getColours()
# self.setStyleSheet("""QScrollArea QScrollBar::horizontal {max-height: 20px;}
# QScrollArea QScrollBar::vertical{max-width:20px;}
# """)
self.residueCount = 0
# self.mainWidget.layout().addWidget(self.scrollArea)
self._parent.layout().addWidget(self.scrollArea)
# connect graphics scene dragMoveEvent to CcpnModule dragMoveEvent - required for drag-and-drop
# assignment routines.
self.scrollArea.scene.dragMoveEvent = self._dragMoveEvent
self.scrollArea.scene.dropEvent = self._dropEvent
self.chainLabels = []
self._highlight = None
self._initialiseChainLabels()
#GWV: removed fixed height restrictions but maximum height instead
#self.setFixedHeight(2*self.widgetHeight)
#self.scrollContents.setFixedHeight(2*self.widgetHeight)
# self._parent.setMaximumHeight(100)
# self.scrollContents.setMaximumHeight(100)
self._setFocusColour()
#GWV: explicit intialisation to prevent crashes
self._chainNotifier = None
self._residueNotifier = None
self._chainDeleteNotifier = None
self._registerNotifiers()
# TODO:ED add highlight if an nmrChain already selected
# generate a create graph event? and let the response populate the module
def _setFocusColour(self, focusColour=None, noFocusColour=None):
"""Set the focus/noFocus colours for the widget
"""
focusColour = getColours()[BORDERFOCUS]
noFocusColour = getColours()[BORDERNOFOCUS]
styleSheet = "QGraphicsView { " \
"border: 1px solid;" \
"border-radius: 1px;" \
"border-color: %s;" \
"} " \
"QGraphicsView:focus { " \
"border: 1px solid %s; " \
"border-radius: 1px; " \
"}" % (noFocusColour, focusColour)
self.scrollArea.setStyleSheet(styleSheet)
def _getGuiItem(self, scene):
for item in scene.items():
if item.isUnderMouse() and item != self._highlight:
if hasattr(item, 'residue'):
# self._highlight.setPlainText(item.toPlainText())
return item
else:
return None
def _dragMoveEvent(self, event):
pos = event.scenePos()
pos = QtCore.QPointF(pos.x(), pos.y() - 25) # WB: TODO: -25 is a hack to take account of scrollbar height
item = self._getGuiItem(self.scrollArea.scene)
if item:
# _highlight is an overlay of the guiNmrResidue but with a highlight colour
self._highlight.setHtml('<div style="color: %s; text-align: center;"><strong>' % self.colours[SEQUENCEMODULE_DRAGMOVE] +
item.toPlainText() + '</strong></div>')
self._highlight.setPos(item.pos())
else:
self._highlight.setPlainText('')
event.accept()
def _dropEvent(self, event):
self._highlight.setPlainText('')
data, dataType = _interpretEvent(event)
if dataType == 'pids':
# check that the drop event contains the correct information
# if isinstance(data, Iterable) and len(data) == 2:
# nmrChain = self.mainWindow.project.getByPid(data[0])
# nmrResidue = self.mainWindow.project.getByPid(data[1])
# if isinstance(nmrChain, NmrChain) and isinstance(nmrResidue, NmrResidue):
# if nmrResidue.nmrChain == nmrChain:
# self._processNmrChains(data, event)
if isinstance(data, Iterable):
for dataItem in data:
obj = self.mainWindow.project.getByPid(dataItem)
if isinstance(obj, NmrChain) or isinstance(obj, NmrResidue):
self._processNmrChains(obj)
def _processNmrChains(self, data: typing.Union[NmrChain, NmrResidue]):
"""
Processes a list of NmrResidue Pids and assigns the residue onto which the data is dropped and
all succeeding residues according to the length of the list.
"""
guiRes = self._getGuiItem(self.scrollArea.scene)
#self.scene.itemAt(event.scenePos())
# if not hasattr(guiRes, 'residue'):
# return
if isinstance(data, NmrChain):
nmrChain = data #self.mainWindow.project.getByPid(data)
selectedNmrResidue = nmrChain.nmrResidues[0]
elif isinstance(data, NmrResidue):
selectedNmrResidue = data
nmrChain = data.nmrChain
else:
return
# selectedNmrResidue = self.mainWindow.project.getByPid(data[1]) # ejb - new, pass in selected nmrResidue
residues = [guiRes.residue]
# toAssign = [nmrResidue for nmrResidue in nmrChain.nmrResidues if '-1' not in nmrResidue.sequenceCode]
toAssign = nmrChain.mainNmrResidues
chainRes = guiRes.residue
if toAssign:
if isinstance(data, NmrChain):
selectedNmrResidue = toAssign[0]
residues = [chainRes]
idStr = 'nmrChain: %s to residue: %s' % (toAssign[0].nmrChain.id, residues[0].id)
else:
try:
selectedNmrResidue = selectedNmrResidue.mainNmrResidue
# get the connected nmrResidues
if selectedNmrResidue in toAssign:
indL = indR = toAssign.index(selectedNmrResidue)
while toAssign[indL].previousNmrResidue and indL > 0 and chainRes:
indL -= 1
chainRes = chainRes.previousResidue
endRes = chainRes
while toAssign[indR].nextNmrResidue and indR < len(toAssign) and endRes:
indR += 1
endRes = endRes.nextResidue
toAssign = toAssign[indL:indR + 1]
else:
showWarning('Sequence Graph', 'nmrResidue %s does not belong to nmrChain' % str(selectedNmrResidue.pid))
return
# # get the first residue of the chain
# leftAssignNum = toAssign.index(selectedNmrResidue)
# for resLeft in range(leftAssignNum):
# if not selectedNmrResidue.previousNmrResidue:
# break
# leftAssignNum -= 1
# chainRes = chainRes.previousResidue
#
# endRes = chainRes
# for resRight in range(len(toAssign) - 1):
# endRes = endRes.nextResidue
except Exception as es:
showWarning('Sequence Graph', str(es))
return
if not chainRes:
showWarning('Sequence Graph', 'Too close to the start of the chain')
return
if not endRes:
showWarning('Sequence Graph', 'Too close to the end of the chain')
return
residues = [chainRes]
idStr = 'nmrChain: %s;\nnmrResidue: %s to residue: %s' % (toAssign[0].nmrChain.id, selectedNmrResidue.id, guiRes.residue.id)
result = showYesNo('Assignment', 'Assign %s?' % idStr)
if result:
with progressManager(self.mainWindow, 'Assigning %s' % idStr):
update = False
if nmrChain.id == '@-':
# assume that it is the only one
try:
nmrChain.assignSingleResidue(selectedNmrResidue, residues[0])
update = True
except Exception as es:
showWarning('Sequence Graph', str(es))
return
else:
# toAssign is the list of mainNmrResidues of the chain
for ii in range(len(toAssign) - 1):
resid = residues[ii]
next = resid.nextResidue #TODO:ED may not have a .nextResidue
residues.append(next)
try:
nmrChain.assignConnectedResidues(residues[0])
update = True
except Exception as es:
showWarning('Sequence Graph', str(es))
# highlight the new items in the chain
if update:
thisChain = residues[0].chain
for chainLabel in self.chainLabels:
if chainLabel.chain == thisChain:
for ii, res in enumerate(residues):
guiResidue = chainLabel.residueDict.get(res.sequenceCode)
guiResidue._setStyleAssigned()
break
[docs] def populateFromSequenceGraphs(self):
"""
Take the selected chain from the first opened sequenceGraph and highlight in module
"""
# get the list of open sequenceGraphs
# self.moduleParent.predictSequencePosition(self.moduleParent.predictedStretch)
return
# from ccpn.AnalysisAssign.modules.SequenceGraph import SequenceGraphModule
# seqGraphs = [sg for sg in SequenceGraphModule.getInstances()]
#
# if seqGraphs:
# try:
# seqGraphs[0].predictSequencePosition(seqGraphs[0].predictedStretch)
# except Exception as es:
# getLogger().warning('Error: no predictedStretch found: %s' % str(es))
def _clearStretches(self, chainNum):
"""
CCPN INTERNAL called in predictSequencePosition method of SequenceGraph.
Highlights regions on the sequence specified by the list of residues passed in.
"""
if self.chainLabels and chainNum in range(len(self.chainLabels)):
for res1 in self.chainLabels[chainNum].residueDict.values():
res1._styleResidue()
def _highlightPossibleStretches(self, chainNum, residues: typing.List[Residue]):
"""
CCPN INTERNAL called in predictSequencePosition method of SequenceGraph.
Highlights regions on the sequence specified by the list of residues passed in.
"""
# for res1 in self.chainLabels[chainNum].residueDict.values():
# res1._styleResidue()
try:
# self._clearStretches(chainNum)
guiResidues = []
_labelDict = self.chainLabels[chainNum].residueDict
for residue in residues:
guiResidue = _labelDict[residue.sequenceCode]
guiResidues.append(guiResidue)
if guiResidue.residue.nmrResidue is not None:
guiResidue._setStyleWarningAssigned()
else:
guiResidue._setStylePossibleAssigned()
except Exception as es:
getLogger().warning('_highlightPossibleStretches: %s' % str(es))
def _chainCallBack(self, data):
"""callback for chain notifier
"""
chain = data[Notifier.OBJECT]
self._addChainLabel(chain=chain)
def _addChainLabel(self, chain: Chain, placeholder=False, tryToUseSequenceCodes=False):
"""Creates and adds a GuiChainLabel to the sequence module.
"""
if len(self._chains) == 1 and len(self.chainLabels) == 1:
# first new chain created so get rid of placeholder label
self.chainLabels = []
self.scrollArea.scene.removeItem(self.chainLabel)
self.widgetHeight = 0
self.chainLabel = GuiChainLabel(self, self.mainWindow, self.scrollArea.scene, position=[0, self.widgetHeight],
chain=chain, placeholder=placeholder, tryToUseSequenceCodes=tryToUseSequenceCodes)
self.scrollArea.scene.addItem(self.chainLabel)
self.chainLabels.append(self.chainLabel)
self.widgetHeight += (0.8 * (self.chainLabel.boundingRect().height()))
def _addChainResidueCallback(self, data):
"""callback for residue change notifier
"""
residue = data[Notifier.OBJECT]
self._refreshChainLabels()
# residue = data[Notifier.OBJECT]
#
# if self.chainLabel.chain is not residue.chain: # they should always be equal if function just called as a notifier
# return
# number = residue.chain.residues.index(residue)
# self.chainLabel._addResidue(number, residue)
# self.populateFromSequenceGraphs()
def _deleteChainResidueCallback(self, data):
"""callback for residue change notifier
"""
residue = data[Notifier.OBJECT]
self._refreshChainLabels()
# if self.chainLabel.chain is not residue.chain: # they should always be equal if function just called as a notifier
# return
# number = residue.chain.residues.index(residue)
# self.chainLabel._addResidue(number, residue)
# self.populateFromSequenceGraphs()
def _registerNotifiers(self):
"""register notifiers
"""
self._chainNotifier = Notifier(self.project,
[Notifier.CREATE],
'Chain',
self._chainCallBack)
self._residueNotifier = Notifier(self.project,
[Notifier.CREATE, Notifier.CHANGE],
'Residue',
self._addChainResidueCallback,
onceOnly=True)
self._residueDeleteNotifier = Notifier(self.project,
[Notifier.DELETE],
'Residue',
self._deleteChainResidueCallback,
onceOnly=True)
self._chainDeleteNotifier = Notifier(self.project,
[Notifier.DELETE],
'Chain',
self._refreshChainLabels)
self._nmrResidueNotifier = Notifier(self.project,
[Notifier.CHANGE],
'NmrResidue',
self._refreshChainLabels,
onceOnly=True)
def _unRegisterNotifiers(self):
"""unregister notifiers
"""
if self._chainNotifier:
self._chainNotifier.unRegister()
self._chainNotifier = None
if self._residueNotifier:
self._residueNotifier.unRegister()
self._residueNotifier = None
if self._residueDeleteNotifier:
self._residueDeleteNotifier.unRegister()
self._residueDeleteNotifier = None
if self._chainDeleteNotifier:
self._chainDeleteNotifier.unRegister()
self._chainDeleteNotifier = None
if self._nmrResidueNotifier:
self._nmrResidueNotifier.unRegister()
self._nmrResidueNotifier = None
def _closeModule(self):
"""
CCPN-INTERNAL: used to close the module
"""
self._unRegisterNotifiers()
[docs] def close(self):
"""
Close the table from the commandline
"""
self._closeModule() # ejb - needed when closing/opening project
def _initialiseChainLabels(self):
"""initialise the chain label widgets
"""
for chainLabel in self.chainLabels:
for item in chainLabel.items:
self.scrollArea.scene.removeItem(item)
chainLabel.items = [] # probably don't need to do this
self.chainLabels = []
self.widgetHeight = 0 # dynamically calculated from the number of chains
if not self._chains:
self._addChainLabel(chain=None, placeholder=True)
else:
for chain in self._chains:
if not (chain._flaggedForDelete or chain.isDeleted):
self._addChainLabel(chain, tryToUseSequenceCodes=True)
if self._highlight:
self.scrollArea.scene.removeItem(self._highlight)
self._highlight = QtWidgets.QGraphicsTextItem()
self._highlight.setDefaultTextColor(QtGui.QColor(self.colours[SEQUENCEMODULE_TEXT]))
setWidgetFont(self._highlight, size='LARGE')
self._highlight.setPlainText('')
self.scrollArea.scene.addItem(self._highlight)
def _refreshChainLabels(self, data=None):
"""callback to refresh chains notifier
"""
self._initialiseChainLabels()
# highlight any predicted stretches
self.populateFromSequenceGraphs()
[docs]class GuiChainLabel(QtWidgets.QGraphicsTextItem):
"""
This class is acts as an anchor for each chain displayed in the Sequence Module.
On instantiation an instance of the GuiChainResidue class is created for each residue in the chain
along with a dictionary mapping Residue objects and GuiChainResidues, which is required for assignment.
"""
def __init__(self, sequenceWidget, mainWindow, scene, position, chain, placeholder=None, tryToUseSequenceCodes=False):
QtWidgets.QGraphicsTextItem.__init__(self)
self.sequenceWidget = sequenceWidget
self.mainWindow = mainWindow
self.scene = scene
self.chain = chain
self.project = mainWindow.application.project
self.items = [self] # keeps track of items specific to this chainLabel
self.colours = getColours()
self.setDefaultTextColor(QtGui.QColor(self.colours[GUICHAINLABEL_TEXT]))
# self.setFont(self.mainWindow.application._fontSettings.fixedWidthLargeFont)
setWidgetFont(self, size='LARGE')
self.setPos(QtCore.QPointF(position[0], position[1]))
if placeholder:
self.text = 'No Chains Selected'
else:
self.text = '%s:%s' % (chain.compoundName, chain.shortName)
self.setHtml('<div style=><strong>' + self.text + ' </strong></div>')
self.residueDict = {}
self.currentIndex = 0
self.labelPosition = self.boundingRect().width()
self.yPosition = position[1]
if chain:
# useSequenceCode = False
# if tryToUseSequenceCodes:
# # mark residues where sequence is multiple of 10 when you can
# # simple rules: sequenceCodes must be integers and consecutive
# prevCode = None
# for residue in chain.residues:
# try:
# code = int(residue.sequenceCode)
# if prevCode and code != (prevCode+1):
# break
# prevCode = code
# except: # not an integer
# break
# else:
# useSequenceCode = True
for idx, residue in enumerate(chain.residues):
self._addResidue(idx, residue)
def _addResidue(self, idx, residue):
"""
Add residue and optional sequenceCode for
"""
if idx % 10 == 9: # print out every 10
numberItem = QtWidgets.QGraphicsTextItem(residue.sequenceCode)
numberItem.setDefaultTextColor(QtGui.QColor(self.colours[GUICHAINLABEL_TEXT]))
# numberItem.setFont(self.mainWindow.application._fontSettings.helvetica8)
setWidgetFont(numberItem, size='SMALL')
_spacing = getFontHeight(size='LARGE')
# xPosition = self.labelPosition + (self.mainWindow.application._fontSettings.textFontHugeSpacing * self.currentIndex)
xPosition = self.labelPosition + (_spacing * self.currentIndex)
numberItem.setPos(QtCore.QPointF(xPosition, self.yPosition))
self.scene.addItem(numberItem)
self.items.append(numberItem)
self.currentIndex += 1
newResidue = GuiChainResidue(self, self.mainWindow, residue, self.scene,
self.labelPosition, self.currentIndex, self.yPosition)
self.scene.addItem(newResidue)
self.items.append(newResidue)
self.residueDict[residue.sequenceCode] = newResidue
self.currentIndex += 1
# WB: TODO: this used to be in some util library but the
# way drag and drop is done now has changed but
# until someone figures out how to do it the new
# way then we are stuck with the below
# (looks like only first part of if below is needed)
def _interpretEvent(event):
""" Interpret drop event and return (type, data)
"""
import json
from ccpn.util.Constants import ccpnmrJsonData
mimeData = event.mimeData()
if mimeData.hasFormat(ccpnmrJsonData):
jsonData = json.loads(mimeData.text())
pids = jsonData.get('pids')
if pids is not None:
# internal data transfer - series of pids
return (pids, 'pids')
# NBNB TBD add here slots for between-applications transfer, and other types as needed
elif event.mimeData().hasUrls():
filePaths = [url.path() for url in event.mimeData().urls()]
return (filePaths, 'urls')
elif event.mimeData().hasText():
return (event.mimeData().text(), 'text')
return (None, None)
[docs]class GuiChainResidue(QtWidgets.QGraphicsTextItem, Base):
fontSize = 20
def __init__(self, guiChainLabel, mainWindow, residue, scene, labelPosition, index, yPosition):
QtWidgets.QGraphicsTextItem.__init__(self)
Base._init(self, acceptDrops=True)
self.guiChainLabel = guiChainLabel
self.mainWindow = mainWindow
self.residue = residue
self.scene = scene
# self.setFont(self.mainWindow.application._fontSettings.fixedWidthLargeFont)
setWidgetFont(self, size='LARGE')
_spacing = getFontHeight(size='LARGE')
self.colours = getColours()
self.setDefaultTextColor(QtGui.QColor(self.colours[GUICHAINRESIDUE_UNASSIGNED]))
self.setPlainText(residue.shortName)
# position = labelPosition + (self.mainWindow.application._fontSettings.textFontHugeSpacing * index)
position = labelPosition + (_spacing * index)
self.setPos(QtCore.QPointF(position, yPosition))
self.residueNumber = residue.sequenceCode
self.setFlags(QtWidgets.QGraphicsItem.ItemIsSelectable | self.flags())
self._styleResidue()
# def mousePressEvent(self, ev):
# pass
def _styleResidue(self):
"""
A convenience function for applying the correct styling to GuiChainResidues depending on their state.
"""
try:
if self.residue.nmrResidue is not None:
self._setStyleAssigned()
else:
self._setStyleUnAssigned()
except:
# self.setHtml('<div style="color: %s; "text-align: center;">' % self.colours[GUICHAINRESIDUE_UNASSIGNED] + '</div')
getLogger().warning('GuiChainResidue has been deleted')
def _setStyleAssigned(self):
self.setHtml('<div style="color: %s; text-align: center;"><strong>' % self.colours[GUICHAINRESIDUE_ASSIGNED] +
self.residue.shortName + '</strong></div>')
def _setStyleUnAssigned(self):
self.setHtml('<div style="color: %s; "text-align: center;">' % self.colours[GUICHAINRESIDUE_UNASSIGNED] +
self.residue.shortName + '</div')
def _setStylePossibleAssigned(self):
self.setHtml('<div style="color: %s; "text-align: center;">' % self.colours[GUICHAINRESIDUE_POSSIBLE] +
self.residue.shortName + '</div')
def _setStyleWarningAssigned(self):
self.setHtml('<div style="color: %s; "text-align: center;">' % self.colours[GUICHAINRESIDUE_WARNING] +
self.residue.shortName + '</div')
def _setFontBold(self):
"""
Sets font to bold, necessary as QtWidgets.QGraphicsTextItems are used for display of residue
one letter codes.
"""
format = QtGui.QTextCharFormat()
format.setFontWeight(75)
self.textCursor().mergeCharFormat(format)