modules/pmg_tk/PMGApp.py (274 lines of code) (raw):
#A* -------------------------------------------------------------------
#B* This file contains source code for the PyMOL computer program
#C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
#D* -------------------------------------------------------------------
#E* It is unlawful to modify or remove this copyright notice.
#F* -------------------------------------------------------------------
#G* Please see the accompanying LICENSE file for further information.
#H* -------------------------------------------------------------------
#I* Additional authors of this source file include:
#-*
#-* NOTE: Based on code by John E. Grayson which was in turn
#-* based on code written by Doug Hellmann.
#Z* -------------------------------------------------------------------
from __future__ import print_function
import sys
import os
from glob import glob
import re
import traceback
import Pmw
if sys.version_info[0] == 2:
import Queue
from Tkinter import *
from tkFileDialog import *
import tkMessageBox
else:
import queue as Queue
from tkinter import *
from tkinter.filedialog import *
import tkinter.messagebox as tkMessageBox
try:
# monkey patch Pmw's error message box
def _reporterror(func, args):
import pymol
exc_type, exc_value, exc_traceback = sys.exc_info()
msg = "Sorry this command was not successful at this time"
if issubclass(exc_type, (pymol.cmd.QuietException)):
tkMessageBox.showerror('Error', msg)
elif issubclass(exc_type, (pymol.CmdException)):
tkMessageBox.showerror(getattr(exc_value, 'label', 'Error'), str(exc_value.message).strip() or msg)
else:
_reporterror.orig(func, args)
PmwBase = sys.modules[Pmw.MegaWidget.__module__]
_reporterror.orig = PmwBase._reporterror
PmwBase._reporterror = _reporterror
del PmwBase
except Exception as e:
print('monkey patching _reporterror failed:', e)
class PMGApp(Pmw.MegaWidget):
def initOS(self):
# Initialize platform-specific options
if sys.platform == 'darwin':
self.initializeTk_mac()
elif sys.platform[:3] == 'win':
self.initializeTk_win32()
elif sys.platform[:5] == 'linux':
self.initializeTk_unix()
else:
self.initializeTk_unix()
# self.root.tk.call('tk','scaling',1)
# try to get the windows properly aligned...
osFrame = { 'win32' : (4,60), 'irix' : (0,41),
'darwin': (0,51), 'cygwin' : (0,60),
'linux' : (0,31), 'linux2' : (0,31) }
self.frameXAdjust, self.frameYAdjust = osFrame.get(sys.platform, (0, 51))
def initializeTk_win32(self):
pass
def initializeTk_mac(self):
pass
def initializeTk_unix(self):
pass
def getLoadableFileTypes(self):
return [("All Readable","*.pdb"),
("All Readable","*.pdb1"),
("All Readable","*.ccp4"),
("All Readable","*.xplor"),
("All Readable","*.mol"),
("All Readable","*.mol2"),
("All Readable","*.sdf"),
("All Readable","*.xyz"),
("All Readable","*.r3d"),
("All Readable","*.cc1"),
("All Readable","*.cc2"),
("All Readable","*.ent"),
("All Readable","*.dat"),
("All Readable","*.out"),
("All Readable","*.mmd"),
("All Readable","*.mmod"),
("All Readable","*.pse"),
("All Readable","*.psw"),
("All Readable","*.phi"),
("All Readable","*.fld"),
("All Readable","*.grd"),
("All Readable","*.o"),
("All Readable","*.omap"),
("All Readable","*.brix"),
("All Readable","*.dx"),
("All Readable","*.pqr"),
("All Readable","*.p5m"),
("All Readable","*.p1m"),
("All Readable","*.cube"),
("All Readable","*.cif"),
("All Readable","*.moe"), # proprietary format
("All Readable","*.mae"), # proprietary format
("All Readable","*.maegz"), # proprietary format
("All Readable","*.cms"), # proprietary format
("All Readable","*.idx"), # proprietary format
("All Readable","*.fasta"),
("All Readable","*.aln"),
("All Readable","*.acnt"),
("All Readable","*.mtz"),
("All Readable","*.vis"),
("All Readable","*.psf"),
("All Readable","*.pdbml"),
("All Readable","*.xml"),
("All Readable","*.xml.gz"),
("All Readable","*.pdbqt"),
("All Readable","*.cml"),
("All Readable","*.mmtf"),
("PDB File","*.pdb"),
("PDB1 File","*.pdb1"),
("All Files","*.*"),
("All Files","*"),
("PDB File","*.ent"),
("PyMOL Session","*.pse"),
("PyMOL Show","*.psw"),
("CCP4 Map","*.ccp4"),
("XPLOR Map","*.xplor"),
("MOL2/Multi-MOL2","*.mol2"),
("Macromodel File","*.dat"),
("Macromodel File","*.out"),
("Macromodel File","*.mmd"),
("Macromodel File","*.mmod"),
# ("MTZ Reflection File","*.mtz"),
("BRIX/O Map","*.o"),
("BRIX/O Map","*.omap"),
("BRIX/O Map","*.brix"),
("CIF","*.cif"),
("Gaussian Cube Map","*.cube"),
("DX Map","*.dx"),
("AVS (MEAD) Field","*.fld"),
("MOL File","*.mol"),
("MOE File","*.moe"), # proprietary format
("MAE File","*.mae"), # proprietary format
("MAE File","*.maegz"), # proprietary format
("MAE File","*.cms"), # proprietary format
("Desmond Trajectory","*.idx"), # proprietary format
("VIS File","*.vis"),
("ChemPy Model","*.pkl"),
("Raster3D Scene","*.r3d"),
("SDF File","*.sdf"),
("ChemDraw3D File","*.cc1"),
("ChemDraw3D File","*.cc2"),
("XYZ File","*.xyz"),
("Fasta File","*.fasta"),
("CLUSTAL file","*.aln"),
("ACNT Map","*.acnt"),
("Protein Structure File","*.psf"),
("PDBML","*.pdbml"),
("PDBML","*.xml"),
("PDBML","*.xml.gz"),
("PDBQT","*.pdbqt"),
("Chemical Markup Language","*.cml"),
("MMTF","*.mmtf"),
("MMTF","*.mmtf.gz"),
]
def initializeTk_colors_common(self):
#self.root.option_add('*background', 'grey') #let system decide
self.root.option_add('*foreground', 'black')
self.root.option_add('*EntryField.Entry.background', 'white')
self.root.option_add('*Entry.background', 'white')
self.root.option_add('*MessageBar.Entry.background', 'gray85')
self.root.option_add('*Listbox*background', 'white')
self.root.option_add('*Listbox*selectBackground', 'dark slate blue')
self.root.option_add('*Listbox*selectForeground', 'white')
def quit_app(self):
self.pymol.cmd.log_close()
self.pymol.cmd.quit() # avoid logging this - it's inconvenient...
def flush_fifo_once(self):
# flush the external GUI fifo command queue
while not self.fifo.empty():
try:
cmmd = self.fifo.get(0)
if isinstance(cmmd, str):
exec(cmmd)
else:
cmmd()
except:
traceback.print_exc()
def flush_fifo(self):
self.flush_fifo_once()
if self.allow_after:
self.root.after(20,self.flush_fifo) # 50X a second
def run(self,poll=0):
# this call to mainloop needs to be replaced with something revocable
self.flush_fifo_once()
keep_alive = 1
if poll:
import time
while keep_alive:
self.root.update()
time.sleep(0.05)
else:
self.root.mainloop()
self.quit_app()
def execute(self,cmmd):
self.fifo.put(cmmd)
def my_show(self,win,center=1):
if sys.platform!='linux2':
win.show()
else: # autocenter, deiconify, and run mainloop
# this is a workaround for a bug in the
# interaction between Tcl/Tk and common Linux
# window managers (namely KDE/Gnome) which causes
# an annoying 1-2 second delay in opening windows!
if center:
tw = win.winfo_reqwidth()+100
th = win.winfo_reqheight()+100
vw = win.winfo_vrootwidth()
vh = win.winfo_vrootheight()
x = max(0,(vw-tw)/2)
y = max(0,(vh-th)/2)
win.geometry(newGeometry="+%d+%d"%(x,y))
win.deiconify()
def my_withdraw(self,win):
if sys.platform!='linux2':
win.withdraw()
else:
win.destroy()
def _initializePlugins(self):
from pymol.plugins import legacysupport
return legacysupport.initializePlugins(self)
def addSkinMenuItems(self,menuBar,menuName):
if not hasattr(self,'skinNameList'):
# find installed skins
skin_pattern = re.sub(r"[\/\\][^\/\\]*$","/skins/*/__init__.py*",__file__)
raw_list = glob(skin_pattern)
unique = {}
for a in raw_list:
key = re.sub(r"[\/\\]__init__\.py.*$","",a)
unique[re.sub(r".*[\/\\]","",key)] = 1
name_list = list(unique.keys())
name_list.sort()
self.skinNameList = name_list
if hasattr(self,'skinNameList'):
for name in self.skinNameList:
caps_name = name.capitalize()
menuBar.addmenuitem(menuName, 'command', name,
label=caps_name,
command=lambda s=self,n=name:s.setSkin(n))
def setSkin(self,skin,run=1):
if isinstance(skin,str):
inv = sys.modules.get("pymol.invocation",None)
if inv!=None:
module_path = inv.options.gui +".skins."+ skin
__import__(inv.options.gui +".skins."+ skin)
skin = sys.modules[module_path].__init__(self)
if skin != self.skin:
if self.skin != None:
self.skin.takedown()
self.skin = skin
if run:
self.runSkin()
def runSkin(self):
if self.skin != None:
self.skin.setup()
def __init__(self, pymol_instance, skin):
# prevent overloading
self.initializePlugins = self._initializePlugins
self.allow_after = 1 # easy switch for troubleshooting threads
self.pymol = pymol_instance
if self.pymol._ext_gui != None:
raise RuntimeError # only one PMGApp should ever be instantiated
else:
# create a FIFO so that PyMOL can send code to be executed by the GUI thread
self.fifo = Queue.Queue(0)
# create a pymol global so that PyMOL can find the external GUI
self.pymol._ext_gui = self
self.skin = None
# initialize Tcl/Tk
self.root = Tk() # creates the root window for the application
# color scheme
self.initializeTk_colors_common()
# operating-system dependencies
self.initOS()
# Python megawigit initialization
Pmw.initialise(self.root)
# Initialize the base class
Pmw.MegaWidget.__init__(self, parent=self.root)
# read the command line arguments regarding:
# - the size of the root window
# - the skin to use
inv = sys.modules.get("pymol.invocation",None)
if inv != None:
if skin == None:
skin = inv.options.skin
self.frameWidth = inv.options.win_x + 220
self.frameXPos = inv.options.win_px - self.frameXAdjust
self.frameHeight = inv.options.ext_y
self.frameYPos = inv.options.win_py - (
self.frameHeight + self.frameYAdjust)
self.setSkin(skin,run=0)
# define the size of the root window
import platform
if sys.platform == 'darwin' and platform.mac_ver()[0] >= '10.9':
# let OS X Maverics place the window automatically, to avoid
# off-screen placement in multi-monitor setup
self.root.geometry('%dx%d' % (self.frameWidth, self.frameHeight))
else:
self.root.geometry('%dx%d+%d+%d' % (
self.frameWidth, self.frameHeight, self.frameXPos, self.frameYPos))
# activate polling on the fifo
if self.allow_after:
self.root.after(1000,self.flush_fifo)
# and let 'er rip
self.runSkin()