""" qtgui/modelColourGui.py: CCP4MG Molecular Graphics Program Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009-2010 University of York This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, modified in accordance with the provisions of the license to address the requirements of UK law. You should have received a copy of the modified GNU Lesser General Public License along with this library. If not, copies may be downloaded from http://www.ccp4.ac.uk/ccp4license.php 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 Lesser General Public License for more details. """ from PyQt4 import QtGui,QtCore from global_definitions import * import guiUtils import MGSimpleDialog,mgWidgets #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class ModelColourEditor(QtGui.QDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent,MolData=''): #------------------------------------------------------------------- QtGui.QDialog.__init__(self,parent) self.MolData = MolData self.saveGui = None #print "ModelColourEditor.__init__ MolData",self.MolData,self.parent self.setObjectName(parent.objectName()+'colour_editor') self.setWindowTitle('Edit colour scheme for '+MolData) layout = QtGui.QVBoxLayout() scheme_frame = QtGui.QFrame() scheme_frame.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Plain) scheme_layout = QtGui.QHBoxLayout() import selectionBrowser self.list_widget = selectionBrowser.ModelInfoTree(sets=[data(self.MolData).name_label,'generic'],info='user_colour_schemes',parent=self) self.list_widget.setObjectName('list') self.list_widget.setToolTip('Saved colour schemes') self.list_widget.setFixedHeight(100) self.connect(self.list_widget,QtCore.SIGNAL('doubleClicked(QModelIndex)'),self.restore) scheme_layout.addWidget(self.list_widget) buttons = QtGui.QDialogButtonBox(QtCore.Qt.Vertical) #button_layout = QtGui.QVBoxLayout() restore_widget = QtGui.QPushButton('Restore') restore_widget.setToolTip('Restore the selected colour scheme') self.connect(restore_widget,QtCore.SIGNAL('released()'),self.restore) buttons.addButton(restore_widget,QtGui.QDialogButtonBox.ActionRole) #button_layout.addWidget(restore_widget) delete_widget = QtGui.QPushButton('Delete') delete_widget.setToolTip('Delete the selected colour scheme') self.connect(delete_widget,QtCore.SIGNAL('released()'),self.openDeleteGui) buttons.addButton(delete_widget,QtGui.QDialogButtonBox.ActionRole) #button_layout.addWidget(delete_widget) #save_widget = QtGui.QPushButton('Save') #save_widget.setToolTip('Save the current colour scheme') #self.connect(save_widget,QtCore.SIGNAL('released()'),self.openSaveGui) #buttons.addButton(QtGui.QDialogButtonBox.Save) #button_layout.addWidget(save_widget) scheme_layout.addWidget(buttons) scheme_frame.setLayout(scheme_layout) layout.addWidget(scheme_frame) edit_frame = QtGui.QFrame() edit_frame.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Plain) edit_layout = QtGui.QVBoxLayout() line_layout = QtGui.QHBoxLayout() widget = QtGui.QLabel('Default colour',self) line_layout.addWidget(widget) widget = mgWidgets.mgColourCombo(self,'grey') widget.setObjectName('default_colour') widget.setToolTip('Colour any non-selected atoms') line_layout.addWidget(widget) line_layout.addStretch() edit_layout.addLayout(line_layout) self.exFrame = mgWidgets.extendingFrame(self,widget=ColourEditorLine,ifClose=1,ifClear=1,ifSave=1,width=0) self.exFrame.show() edit_layout.addWidget(self.exFrame) edit_frame.setLayout(edit_layout) layout.addWidget(edit_frame) self.setLayout(layout) self.connect(self.exFrame,QtCore.SIGNAL('accepted()'),self.apply) self.connect(self.exFrame,QtCore.SIGNAL('close()'),self.close) self.connect(self.exFrame,QtCore.SIGNAL('save'),self.openSaveGui) self.list_widget.populate() self.connect(MAINWINDOW(),QtCore.SIGNAL('atomContextMenu'),self.atomPickMenu) layout.setStretch(0,0) layout.setStretch(1,1) def Close(self): #print 'ModelColourEditor.close',self # This disconnect should not be necessary by reports of warning messages with # atomPickMenu being called although underlying C++ object does not exists self.disconnect(MAINWINDOW(),QtCore.SIGNAL('atomContextMenu'),self.atomPickMenu) MGSimpleDialog.MGSimpleDialog.Close(self) #---------------------------------------------------------------------- def apply(self): #---------------------------------------------------------------------- self.emit(QtCore.SIGNAL('apply')) #---------------------------------------------------------------------- def openSaveGui(self): #---------------------------------------------------------------------- if not self.saveGui: import selectionBrowser self.saveGui = selectionBrowser.ModelInfoSave(parent=self,info='user_colour_schemes', sets=[self.MolData,'generic']) self.saveGui.setWindowTitle('Save colour scheme') self.connect(self.saveGui,QtCore.SIGNAL('save'),self.save) self.saveGui.populate() self.saveGui.show() self.saveGui.raise_() #---------------------------------------------------------------------- def save(self): #---------------------------------------------------------------------- set,key = self.saveGui.selectedItem() if not key: MGGUI().WarningMessage('Please enter a name for the saved colour scheme') return pars = self.getParams() if not pars.has_key('colour_rules'): MGGUI().WarningMessage('Error retrieving colour rules - nothing saved') return status=MODELINFO().add_info(set=set,info='user_colour_schemes', key=key,value=pars['colour_rules']) if status: MGGUI().WarningMessage('Error saving colour scheme '+key) else: #self.loadSchemes(self.list_widget) self.list_widget.populate() self.saveGui.close() #---------------------------------------------------------------------- def openDeleteGui(self): #---------------------------------------------------------------------- set,colour_scheme = self.list_widget.selectedItem() if not colour_scheme: return import selectionBrowser gui = selectionBrowser.ModelInfoDelete(self,set=set,label=colour_scheme,info='user_colour_schemes') self.connect(gui,QtCore.SIGNAL('deleted'),self.list_widget.populate) #----------------------------------------------------------------------- def restore(self): #----------------------------------------------------------------------- # Emit a restore(colour_scheme) signal set,colour_scheme = self.list_widget.selectedItem() if not colour_scheme: return self.emit(QtCore.SIGNAL('restore_colour_scheme(PyQt_PyObject)'),[colour_scheme,set]) status,defn = MODELINFO().get_info(set=[set],key=colour_scheme,info='user_colour_schemes') #print "colourEditor.restore",status,defn if not status and defn.has_key(colour_scheme): self.setParams({ 'colour_rules' : defn[colour_scheme] }) #---------------------------------------------------------------------- def get(self,name=''): #---------------------------------------------------------------------- if ['save_to','save_label'].count(name): if not self.saveGui: return '' widget = self.saveGui.findChild(QtGui.QWidget,name) if not widget: return '' return str(widget.currentText()) else: return '' #---------------------------------------------------------------------- def setParams(self,params={},rules=[]): #---------------------------------------------------------------------- #print "ModelColourEditor.setParams",params import types molobj = data(self.MolData) if not molobj: return if params.has_key('colour_rules') and len(params['colour_rules'])>0: self.findChild(mgWidgets.mgColourCombo,'default_colour').set_colour(params['colour_rules'][0][0]) expars = { 'colour' : [], 'selection_command' : [] } for item in params['colour_rules'][1:]: # Beware, selection should not be in list format, but just in case.. com = '' if isinstance(item[1],types.ListType): rv = molobj.list_to_command(item[1]) if not rv[0]: com = rv[1] else: com = item[1] expars['colour'].append(item[0]) expars['selection_command'].append(com) #print "ModelColourEditor.setParams expars",expars self.exFrame.setParams(expars) #---------------------------------------------------------------------- def getParams(self): #---------------------------------------------------------------------- molobj = data(self.MolData) if not molobj: return {} pars = {} default_colour = self.findChild(mgWidgets.mgColourCombo,'default_colour').get_colour() expars = self.exFrame.getParams({'selection_command':[],'colour':[]}) rules = [[default_colour,'']] for ii in range(0,len(expars['colour'])): rv = molobj.command_to_list(expars['selection_command'][ii]) if not rv[0]: com = rv[1] else: com = '' rules.append([expars['colour'][ii],com]) #print "ModelColourEditor.getParams rules",rules return {'colour_rules':rules} #---------------------------------------------------------------------- def loadSchemes(self,widget=None,blank=0): #---------------------------------------------------------------------- if not widget: return widget.clear() keys = [] if blank: widget.addItem('') if self.MolData: retval,defn = MODELINFO().get_info(set =data(self.MolData).name_label,info='user_colour_schemes') #print "ModelColourEditor.loadSchemes",retval,defn if not retval: keys.extend(defn.keys()) retval,defn = MODELINFO().get_info(set ='generic',info='user_colour_schemes') #print "ModelColourEditor.loadSchemes",retval,defn if not retval: keys.extend(defn.keys()) for item in keys: widget.addItem(item) #---------------------------------------------------------------------- def atomPickMenu(self,pickevent=None): #---------------------------------------------------------------------- if not self.isVisible(): return dobj = pickevent.getDataObj() if not dobj: return if not dobj.name == self.MolData: return menu = pickevent.getContextMenu() if not menu: return name = str(self.objectName()) guiUtils.populateMenu(self,menu,[['Colour this',name+'range_2',name+'atom',name+'residue',name+'range_1',name+'SSE',name+'chain']],self.getActionDef,info = { 'pickevent' : pickevent } ) #---------------------------------------------------------------------- def getActionDef(self,name,**info): #---------------------------------------------------------------------- #print "ModelColourEditor.getActionDef",name,info name = name[len(str(self.objectName())):] pickevent=info.get('pickevent','') if not pickevent: return args = [name,pickevent.getLabel(format='unique')] if name == 'atom': return dict ( text = 'Atom', tip = 'Colour the selected atom', slot = [self.colourPickedAtom,args], deleteLater = 1, ) if name == 'residue': return dict ( text = 'Residue', tip = 'Colour the selected residue', slot = [self.colourPickedAtom,args], deleteLater = 1, ) if name == 'chain': return dict ( text = 'Chain', tip = 'Colour the selected chain', slot = [self.colourPickedAtom,args], deleteLater = 1, ) if name == 'SSE': return dict ( text = 'Secondary structure', tip = 'Colour the selected secondary structure', slot = [self.colourPickedAtom,args], deleteLater = 1, ) if name == 'range_1': return dict ( text = 'Start range', tip = 'Select first residue in a range', slot = [self.colourPickedAtom,args], deleteLater = 1, ) if name == 'range_2': if not hasattr(self,'colourPickedRangeStart'): return {} return dict ( text = 'Range from '+self.colourPickedRangeStart, tip = 'Select end residue in a range', slot = [self.colourPickedAtom,args], deleteLater = 1, ) else: return {} #---------------------------------------------------------------------- def colourPickedAtom(self,args=[]): #---------------------------------------------------------------------- #print "ModelColourEditor.colourPickedAtom",args name,atom_id = args if name == 'atom': selection = atom_id if ['residue','range_1'].count(name): selection= data(self.MolData).convertAtomID (out = 'residue', atomID =atom_id ) elif ['chain'].count(name): selection= data(self.MolData).convertAtomID (out = 'chain', atomID =atom_id ) elif name == 'range_2': res2 = data(self.MolData).convertAtomID (out = 'residue', atomID =atom_id ) # Try to get these the right way round nr1,pr1 = data(self.MolData).interpretResidueID(self.colourPickedRangeStart) nr2,pr2 = data(self.MolData).interpretResidueID(res2) import string if nr1==1 and nr2==1: if pr1.index < pr2.index: selection = self.colourPickedRangeStart + '-' + string.split(res2,'/')[-1] else: selection = res2 + '-' + string.split(self.colourPickedRangeStart,'/')[-1] else: selection = self.colourPickedRangeStart + '-' + string.split(res2,'/')[-1] del self.colourPickedRangeStart elif name == 'SSE': selection = data(self.MolData).getSSE(atom_name=atom_id) #print "colourPickedAtom selection",selection if name == 'range_1': self.colourPickedRangeStart = selection return else: self.exFrame.addLine() self.exFrame.setParams(params = { 'selection_command': [ selection] }, index=self.exFrame.getNofLines()-1) self.apply() #----------------------------------------------------------------------- #----------------------------------------------------------------------- #----------------------------------------------------------------------- class ColourEditorLine(QtGui.QWidget): #----------------------------------------------------------------------- #----------------------------------------------------------------------- #----------------------------------------------------------------------- def __init__(self,parent=None): QtGui.QWidget.__init__(self,parent) #print "ColourEditorLine parent",parent,parent.parent() layout = QtGui.QHBoxLayout() layout.setContentsMargins(0,0,0,0) layout.setSpacing(0) abstractModel = data(self.window().MolData).treeModel self.seleCombo = mgWidgets.mgSelectionCombo(self,abstractModel,selectionWidgets=['namedSelection','neighb','buried','secStr','resType','property']) self.seleCombo.setObjectName('selection_command') self.seleCombo.setToolTip('Select atoms to be coloured') #self.connect(self.seleCombo,QtCore.SIGNAL('changed'),self.window().apply) layout.addWidget(self.seleCombo) # There must be better way of doing this! self.colourCombo = mgWidgets.mgColourCombo(self,'red',browser=1) self.colourCombo.setObjectName('colour') self.colourCombo.setToolTip('Colour of atoms') layout.addWidget(self.colourCombo) self.setLayout(layout) #----------------------------------------------------------------------- def setDefault(self): #----------------------------------------------------------------------- self.seleCombo.clear() self.colourCombo.setColour('red') #----------------------------------------------------------------------- def getParams(self): #----------------------------------------------------------------------- pars = {} pars['colour'] = self.colourCombo.get_colour() pars['selection_command'] = self.seleCombo.text() pars['selection_params'] = self.seleCombo.getParams() return pars #----------------------------------------------------------------------- def setParams(self,params={},**kw): #----------------------------------------------------------------------- params.update(kw) #print 'ColourEditorLine.setParams',params if params.has_key('colour'): self.colourCombo.set_colour(params['colour']) if params.has_key('selection_command'): self.seleCombo.setText(params['selection_command']) if params.has_key('selection_params'): self.seleCombo.setParams(params['selection_params']) #----------------------------------------------------------------------- #----------------------------------------------------------------------- #----------------------------------------------------------------------- class ColourBlendLine(QtGui.QWidget): #----------------------------------------------------------------------- #----------------------------------------------------------------------- #----------------------------------------------------------------------- def __init__(self,parent=None): QtGui.QWidget.__init__(self,parent) #print "ColourBlendLine parent",parent; layout = QtGui.QHBoxLayout() layout.setContentsMargins(0,0,0,0) layout.setSpacing(0) abstractModel = data(parent.MolData).treeModel widget = mgWidgets.mgSelectionCombo(self,abstractModel,modelGroups=['peptide','nucleic']) widget.setObjectName('selection_command') widget.setToolTip('Select range of residues') layout.addWidget(widget) # There must be better way of doing this! widget = mgWidgets.mgColourCombo(self,'blue') widget.setObjectName('colour_1') widget.setToolTip('Colour of first residue/SSE in range') layout.addWidget(widget) widget = mgWidgets.mgColourCombo(self,'red') widget.setObjectName('colour_2') widget.setToolTip('Colour of last residue/SSE in range') layout.addWidget(widget) widget= QtGui.QComboBox(self) widget.setObjectName('direction') for item in ['anti-clockwise','clockwise']: widget.addItem(item) widget.setToolTip('Direction around colour wheel between first and last colour') layout.addWidget(widget) self.setLayout(layout) #----------------------------------------------------------------------- def setDefault(self): #----------------------------------------------------------------------- self.findChild(QtGui.QWidget,'selection_command').clear() self.findChild(QtGui.QWidget,'colour_1').setColour('blue') self.findChild(QtGui.QWidget,'colour_2').setColour('red') self.findChild(QtGui.QWidget,'direction').setCurrentIndex(0) #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class colourBlendGui(QtGui.QDialog): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def __init__(self,parent=None,MolData=''): #---------------------------------------------------------------------- QtGui.QDialog.__init__(self,parent) #print "colourBlendGui MolData",MolData self.setObjectName(parent.objectName()+'colour_blend') self.setWindowTitle('Colour blend through model for '+MolData) self.MolData = MolData layout = QtGui.QVBoxLayout() line_layout = QtGui.QHBoxLayout() widget = QtGui.QCheckBox('Colour secondary structure with turns',self) widget.setObjectName('group') widget.setToolTip('Colour each helix/stand one colour') line_layout.addWidget(widget) widget = mgWidgets.mgColourCombo(self,'grey') widget.setObjectName('default_colour') widget.setToolTip('Colour for regions not helix/strand') line_layout.addWidget(widget) line_layout.addStretch() layout.addLayout(line_layout) self.exFrame = mgWidgets.extendingFrame(self,widget=ColourBlendLine,width=0,ifClose=1) layout.addWidget(self.exFrame) #layout.addStretch() self.exFrame.show() self.setLayout(layout) self.connect(self.exFrame,QtCore.SIGNAL('accepted()'),guiUtils.partial(self.emit,QtCore.SIGNAL('accepted()'))) self.connect(self.exFrame,QtCore.SIGNAL('close()'),self.close) #---------------------------------------------------------------------- def setParams(self,params={}): #---------------------------------------------------------------------- #print "colourBlendGui.setParams",params if params.has_key('group'): self.findChild( QtGui.QCheckBox,'group').setChecked(params.get('group')=='SSE') if params.has_key('default_colour'): self.findChild(mgWidgets.mgColourCombo,'default_colour').set_colour(params['default_colour']) # Slight complication that model_colour class treats colours as one # list of [colour1,colour2] but extendingFrame widget expects each # column (ie the colour1 and colour2 columns) as separate list colour_1 = [] colour_2 = [] pars = {} if params.has_key("colours"): for col1,col2 in params['colours']: colour_1.append(col1) colour_2.append(col2) pars['colour_1'] = colour_1 pars['colour_2'] = colour_2 #print "colourBlendGui.setParams",params for item in ['selection_command','direction']: #print "colourBlendGui.setParams",item,params.has_key(item) if params.has_key(item): pars[item]=params[item] self.exFrame.setParams(pars) #---------------------------------------------------------------------- def getParams(self): #---------------------------------------------------------------------- pars = {} if self.findChild( QtGui.QCheckBox,'group').isChecked(): pars['group'] = 'SSE' else: pars['group'] = 'residue' pars['default_colour'] = self.findChild(mgWidgets.mgColourCombo,'default_colour').get_colour() pars.update(self.exFrame.getParams({'selection_command':[],'colour_1':[],'colour_2': [], 'direction':[]})) cols = [] for ii in range(0,len(pars['colour_1'])): cols.append([pars['colour_1'][ii],pars['colour_2'][ii]]) pars['colours'] = cols del pars['colour_1'],pars['colour_2'] return pars #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class colourInterfaceGui(QtGui.QDialog): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def __init__(self,parent=None,MolData=''): #---------------------------------------------------------------------- QtGui.QDialog.__init__(self,parent) #print "colourBlendGui MolData",MolData self.setObjectName(parent.objectName()+'colour_interface') self.setWindowTitle('Colour interface for '+MolData) self.MolData = MolData layout = QtGui.QVBoxLayout() line_layout = QtGui.QHBoxLayout() widget = QtGui.QLabel('Colour',self) line_layout.addWidget(widget) group = QtGui.QButtonGroup(self) widget = QtGui.QRadioButton('atoms',self) widget.setObjectName('atom_buried') group.addButton(widget) line_layout.addWidget(widget) widget = QtGui.QRadioButton('residues by buried area',self) widget.setObjectName('res_buried') widget.setChecked(1) group.addButton(widget) line_layout.addWidget(widget) line_layout.addStretch(5) layout.addLayout(line_layout) line_layout = QtGui.QHBoxLayout() widget = mgWidgets.mgSelectionCombo(self,multi=1,selectionWidgets=['namedSelection','neighb','chains']) widget.setObjectName('interface_selection') line_layout.addWidget(widget) layout.addLayout(line_layout) line_layout = QtGui.QHBoxLayout() widget = QtGui.QPushButton('Apply',self) self.connect(widget,QtCore.SIGNAL('released()'),guiUtils.partial(self.emit,QtCore.SIGNAL('accepted()'))) line_layout.addStretch(5) line_layout.addWidget(widget) line_layout.addStretch(5) layout.addLayout(line_layout) line_layout = QtGui.QHBoxLayout() self.setLayout(layout) #---------------------------------------------------------------------- def getParams(self): #---------------------------------------------------------------------- params = {} if self.findChild(QtGui.QRadioButton,'res_buried').isChecked(): params['interface_style']='RESIDUE' else: params['interface_style']='ATOM' params['interface_selection'] = self.findChild(mgWidgets.mgSelectionCombo,'interface_selection').text() params['interface_MolMata_name'] = self.findChild(mgWidgets.mgSelectionCombo,'interface_selection').getCurrentDataObj().name return params #---------------------------------------------------------------------- def setParams(self,params={},**kw): #---------------------------------------------------------------------- params.update(kw) if params.has_key('interface_style'): if params['interface_style'] == 'RESIDUE': self.findChild(QtGui.QRadioButton,'res_buried').setChecked(1) elif params['interface_style'] == 'ATOM': self.findChild(QtGui.QRadioButton,'atom_buried').setChecked(1) if params.has_key('interface_seletion'): self.findChild(mgWidgets.mgSelectionCombo,'interface_selection').setText(params['interface_selection']) self.findChild(mgWidgets.mgSelectionCombo,'interface_MolData_name').setCurrentDataObj(params['interface_MolData_name'])