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()