def fillInUI(self, parent): self.info = [ ("Helix", HELIX_COLOR, 'isHelix'), ("Strand", SHEET_COLOR, 'isSheet'), ("Other", OTHER_COLOR, None) ] header = Tkinter.Frame(parent) header.grid(row=0, column=0, sticky="nsew") parent.rowconfigure(0, weight=1) for i in range(len(self.info)): parent.columnconfigure(i, weight=1) from chimera.widgets import MoleculeScrolledListBox self.molListBox = MoleculeScrolledListBox(header, selectioncommand=lambda: self.configure( models=self.molListBox.getvalue()), listbox_selectmode="extended", labelpos="nw", label_text="Models") self.molListBox.grid(row=0, column=0, rowspan=len(self.info), sticky="nsew") for i in range(3): header.rowconfigure(i, weight=1) header.columnconfigure(0, weight=1) self.colorRibVar = Tkinter.IntVar(parent) self.colorRibVar.set(True) self.colorAtomVar = Tkinter.IntVar(parent) self.colorAtomVar.set(False) self.colorSurfVar = Tkinter.IntVar(parent) self.colorSurfVar.set(False) varFrame = Tkinter.Frame(parent) varFrame.grid(row=1, column=0) for i, info in enumerate([(self.colorRibVar, "Color ribbons"), (self.colorAtomVar, "Color atoms"), (self.colorSurfVar, "Color surfaces")]): var, text = info but = Tkinter.Checkbutton(varFrame, variable=var, text=text) but.grid(row=i, column=0, sticky='w') self.wells = [] self.actVars = [] from CGLtk.color.ColorWell import ColorWell from chimera.colorTable import getColorByName for row, ssInfo in enumerate(self.info): ssType, prefName, attrName = ssInfo rgba = prefs[prefName] if isinstance(rgba, basestring): rgba = getColorByName(rgba).rgba() well = ColorWell(header, color=rgba, noneOkay=True) self.wells.append(well) well.grid(row=row, column=2) actVar = Tkinter.IntVar(parent) actVar.set(True) self.actVars.append(actVar) Tkinter.Checkbutton(header, variable=actVar, text=ssType).grid(row=row, column=1, sticky='w')
def _menuCB(self, val): newNum = int(val) oldSettings = [] for well, entry in zip(self.wells, self.values): entry.invoke() oldSettings.append((well.rgba, float(entry.getvalue()))) well.grid_forget() well.destroy() entry.grid_forget() entry.destroy() import Pmw from CGLtk.color.ColorWell import ColorWell self.wells = [] self.values = [] scale = (len(oldSettings) - 1.0) / (newNum - 1.0) f = self.interpFrame for i in range(newNum): index = i * scale if index == int(index) \ or int(index) >= len(oldSettings): color, value = oldSettings[int(index)] else: lowc, lowv = oldSettings[int(index)] highc, highv = oldSettings[int(index) + 1] frac = index - int(index) color = [] for lowcomp, highcomp in zip(lowc, highc): color.append((1.0 - frac) * lowcomp + frac * highcomp) value = (1.0 - frac) * lowv + frac * highv well = ColorWell(f, color=color) well.grid(row=0, column=len(self.wells)) self.wells.append(well) entry = Pmw.EntryField(f, value=str(value), **self._entryOpts) entry.grid(row=1, column=len(self.values)) self.values.append(entry)
def fillInUI(self, parent): self.parent = parent Tkinter.Label(parent, text="Change color every:").grid( row=0, rowspan=3, column=0, sticky='w') self.colorChangeVar = Tkinter.StringVar(parent) self.colorChangeVar.set("residues") Tkinter.Radiobutton(parent, text='residue', value='residues', variable=self.colorChangeVar).grid( row=0, column=1, sticky='w') Tkinter.Radiobutton(parent, text='chain', value='chains', variable=self.colorChangeVar).grid( row=1, column=1, sticky='w') Tkinter.Radiobutton(parent, text='model', value='models', variable=self.colorChangeVar).grid( row=2, column=1, sticky='w') group = Pmw.Group(parent, tag_text='Color range') group.grid(row=3, column=0, columnspan=2) self.wells = [] for i, color in enumerate(self.prefs["colors"]): well = ColorWell(group.interior(), color=color, noneOkay=1) well.grid(row=0, column=i) self.wells.append(well) from chimera.widgets import MoleculeScrolledListBox self.molListBox = MoleculeScrolledListBox(parent, listbox_selectmode="extended", labelpos="n", label_text="Models") self.molListBox.grid(row=0, column=2, rowspan=4, sticky="news") parent.rowconfigure(0, weight=1) parent.columnconfigure(2, weight=1)
def _componentsCB(self, opt, update=True): cf = self.componentsFrame if hasattr(self, 'wells'): for well in self.wells: well.grid_forget() well.destroy() for label in self.labels: label.frame.grid_forget() self.reverseButton.grid_forget() self.reverseButton.destroy() else: Tkinter.Label(cf, text="Colors").grid(row=0) Tkinter.Label(cf, text="Labels").grid(row=0, column=1) if isinstance(opt, int): numComponents = opt self.numComponents.set(opt) else: numComponents = opt.get() wellSize = min(38, int((7 * 38) / numComponents)) from CGLtk.color.ColorWell import ColorWell self.wells = [] self.labels = [] from CGLtk import Hybrid for i in range(numComponents): well = ColorWell(cf, width=wellSize, height=wellSize, callback=self._keyChangeCB, color='white') well.grid(row=i + 1) self.wells.append(well) label = Hybrid.Entry(cf, "", 10) label.variable.add_callback(self._keyTypingCB) label.frame.grid(row=i + 1, column=1, sticky='ew') self.labels.append(label) self.reverseButton = Tkinter.Button(cf, command=self.reverseKey, text="Reverse ordering of above", pady=0) self.reverseButton.grid(row=numComponents + 1, column=0, columnspan=2) self.notebook.setnaturalsize() if update: self._keyChangeCB()
def _componentsCB(self, opt, update=True): cf = self.componentsFrame if hasattr(self, 'wells'): for well in self.wells: well.grid_forget() well.destroy() for label in self.labels: label.frame.grid_forget() self.reverseButton.grid_forget() self.reverseButton.destroy() else: Tkinter.Label(cf, text="Colors").grid(row=0) Tkinter.Label(cf, text="Labels").grid(row=0, column=1) if isinstance(opt, int): numComponents = opt self.numComponents.set(opt) else: numComponents = opt.get() wellSize = min(38, int( (7 * 38) / numComponents )) from CGLtk.color.ColorWell import ColorWell self.wells = [] self.labels = [] from CGLtk import Hybrid for i in range(numComponents): well = ColorWell(cf, width=wellSize, height=wellSize, callback=self._keyChangeCB, color='white') well.grid(row=i+1) self.wells.append(well) label = Hybrid.Entry(cf, "", 10) label.variable.add_callback(self._keyTypingCB) label.frame.grid(row=i+1, column=1, sticky='ew') self.labels.append(label) self.reverseButton = Tkinter.Button(cf, command=self.reverseKey, text="Reverse ordering of above", pady=0) self.reverseButton.grid(row=numComponents+1, column=0, columnspan=2) self.notebook.setnaturalsize() if update: self._keyChangeCB()
def _menuCB(self, val): newNum = int(val) oldSettings = [] for well, entry in zip(self.wells, self.values): entry.invoke() oldSettings.append((well.rgba, float(entry.getvalue()))) well.grid_forget() well.destroy() entry.grid_forget() entry.destroy() import Pmw from CGLtk.color.ColorWell import ColorWell self.wells = [] self.values = [] scale = (len(oldSettings) - 1.0) / (newNum - 1.0) f = self.interpFrame for i in range(newNum): index = i * scale if index == int(index) \ or int(index) >= len(oldSettings): color, value = oldSettings[int(index)] else: lowc, lowv = oldSettings[int(index)] highc, highv = oldSettings[int(index)+1] frac = index - int(index) color = [] for lowcomp, highcomp in zip(lowc, highc): color.append((1.0 - frac) * lowcomp + frac * highcomp) value = (1.0 - frac) * lowv + frac * highv well = ColorWell(f, color=color) well.grid(row=0, column=len(self.wells)) self.wells.append(well) entry = Pmw.EntryField(f, value=str(value), **self._entryOpts) entry.grid(row=1, column=len(self.values)) self.values.append(entry)
class IlabelDialog(ModelessDialog): name = "2D Labels/Color Key" provideStatus = True buttons = ("Delete", "Close") LABELS = "Labels" COLOR_KEY = "Color Key" MOUSE_LABEL_TEXT = "Use mouse for label placement" MOUSE_KEY_TEXT = "Use mouse for key placement" EmphasisColor = "forest green" def __init__(self): import os.path myDir, junk = os.path.split(__file__) addFunction('place text', (self._pickLabel, self._moveLabel, None), icon=chimage.get(Image.open(os.path.join(myDir, 'ilabel.png')), tkgui.app)) addFunction('place key', (self._startOrGrabKey, self._sizeOrMoveKey, None), icon=chimage.get( Image.open(os.path.join(myDir, 'key.png')), tkgui.app)) import Ilabel if not Ilabel._ilabelModel: Ilabel.IlabelModel() self.model = Ilabel._ilabelModel ModelessDialog.__init__(self) self._sessionHandlerID = chimera.triggers.addHandler( SAVE_SESSION, self._saveSession, None) self._closeHandlerID = chimera.triggers.addHandler( CLOSE_SESSION, self.destroy, None) self._beginRestoreHandlerID = chimera.triggers.addHandler( BEGIN_RESTORE_SESSION, self.destroy, None) def fillInUI(self, parent): top = parent.winfo_toplevel() menubar = Tkinter.Menu(top, type="menubar", tearoff=False) top.config(menu=menubar) self.fileMenu = Tkinter.Menu(menubar) menubar.add_cascade(label="File", menu=self.fileMenu) self.fileMenu.add_command(label="Write...", command=self._writeFileCB) self.fileMenu.add_command(label="Read...", command=self._readFileCB) from chimera.tkgui import aquaMenuBar aquaMenuBar(menubar, parent, row=0) from ColorKey import KeyModel parent.rowconfigure(1, weight=1) parent.columnconfigure(0, weight=1) # _pageRaisedCB uses mouseModeVar, so define first self.mouseLabelingVar = Tkinter.IntVar(parent) self.mouseLabelingVar.set(True) self.mlLabelVar = Tkinter.StringVar(parent) self.mouseModeButton = Tkinter.Checkbutton(parent, command=self._mouseFuncCB, variable=self.mouseLabelingVar, textvariable=self.mlLabelVar) self.mouseModeButton.grid(row=2, column=0) self.notebook = Pmw.NoteBook(parent, raisecommand=self._pageRaisedCB) self.notebook.add(self.LABELS, tab_text=self.LABELS) self.notebook.add(self.COLOR_KEY, tab_text=self.COLOR_KEY) self.notebook.grid(row=1, column=0, sticky="nsew") self._fillLabelsPage(self.notebook.page(self.LABELS)) self.keyModel = KeyModel(self) self.keyPosition = None self._fillColorKeyPage(self.notebook.page(self.COLOR_KEY)) def _fillLabelsPage(self, page): page.columnconfigure(0, weight=1) page.columnconfigure(1, weight=1) page.columnconfigure(2, weight=1) row = 0 from CGLtk.Table import SortableTable self.labelTable = SortableTable(page, automultilineHeaders=False) self.labelTable.addColumn("Label [(x, y) text]", self._labelListing, anchor='w') self.labelTable.addColumn("Shown", "shown", format=bool) self.labelTable.setData(self.model.labels) self.labelTable.launch(browseCmd=self._tableCB, selectMode="single") self.labelTable.grid(row=row, column=0, columnspan=3, sticky="nsew") page.rowconfigure(row, weight=1) row += 1 self.labelText = Pmw.ScrolledText(page, labelpos='w', label_text="Text", text_height=3, text_width=20, text_wrap='none', text_state='disabled', text_exportselection=False) text = self.labelText.component('text') text.bind("<<Modified>>", self._textCB) text.bind("<<Selection>>", self._updateTextAttrWidgets) self.labelText.grid(row=row, column=0, sticky='nsew', columnspan=3) page.rowconfigure(row, weight=1) row += 1 self.labelSymbolMenu = Pmw.OptionMenu(page, labelpos='w', label_text="Insert symbol:", command=self._insertSymbol, items=[ u'\N{GREEK SMALL LETTER ALPHA}', u'\N{GREEK SMALL LETTER BETA}', u'\N{GREEK SMALL LETTER GAMMA}', u'\N{GREEK SMALL LETTER DELTA}', u'\N{GREEK SMALL LETTER EPSILON}', u'\N{GREEK SMALL LETTER PI}', u'\N{GREEK SMALL LETTER PHI}', u'\N{GREEK SMALL LETTER CHI}', u'\N{GREEK SMALL LETTER PSI}', u'\N{GREEK SMALL LETTER OMEGA}', u'\N{LEFTWARDS ARROW}', u'\N{RIGHTWARDS ARROW}', u'\N{LEFT RIGHT ARROW}', u'\N{UPWARDS ARROW}', u'\N{DOWNWARDS ARROW}', u'\N{SUPERSCRIPT TWO}', u'\N{SUPERSCRIPT THREE}', u'\N{DEGREE SIGN}', u'\N{LATIN CAPITAL LETTER A WITH RING ABOVE}', "more..." ]) self.labelSymbolMenu.grid(row=row, column=0, columnspan=3) row += 1 colorHouse = Pmw.LabeledWidget(page, labelpos='w', label_text="Color") colorHouse.grid(row=row, column=0, rowspan=3) from CGLtk.color.ColorWell import ColorWell self.colorWell = ColorWell(colorHouse.interior(), color=self._contrastWithBG(), callback=self._colorCB) self.colorWell.grid() from chimera.tkoptions import IntOption self.labelFontSize = IntOption(page, row, "Font size", 24, self._labelChangeCB, startCol=1, min=1, attribute="size", width=3) row += 1 self.labelFontStyle = FontStyle(page, row, "Font style", oglFont.normal, self._labelChangeCB, startCol=1) row += 1 self.labelFontTypeface = FontTypeface(page, row, "Font typeface", FONT_TYPEFACE_VALUES[0], self._labelChangeCB, startCol=1) row += 1 if self.model.curLabel: self.changeToLabel(self.model.curLabel, force=True) def _fillColorKeyPage(self, page): from chimera.tkoptions import IntOption, EnumOption, \ BooleanOption, RGBAOption f = Tkinter.Frame(page) f.grid(row=0, columnspan=2) self.numComponents = IntOption(f, 0, "Number of colors/labels", 3, self._componentsCB, min=2, width=2) self.componentsFrame = Tkinter.Frame(page) self.componentsFrame.grid(row=1, column=0, sticky="nsew", columnspan=2) page.columnconfigure(0, weight=1) self.componentsFrame.columnconfigure(1, weight=1) class ColorTreatment(EnumOption): values = ("distinct", "blended") self.colorTreatment = ColorTreatment(page, 2, "Color range depiction", "blended", self._keyChangeCB, balloon="Should colors be shown as distinct rectangles" " or as a continuous range") class LabelPosition(EnumOption): values = ("left/top", "right/bottom") self.labelPos = LabelPosition(page, 3, "Label positions", "right/bottom", self._keyChangeCB, balloon="Position of" " labels relative to color key.\nLabels always" " positioned adjacent to long side.") self.labelColor = RGBAOption(page, 4, "Label color", self._contrastWithBG(), self._keyChangeCB, balloob= "Label color. If set to 'No color', use corresponding" " key color", noneOkay=True) class LabelJustification(EnumOption): values = ("left", "decimal point", "right") self.justification = LabelJustification(page, 5, "Label justification", "decimal point", self._keyChangeCB, balloon="Justification of label text" " in a vertical key layout.\nHorizontal key labels will" " always be center justified.") self.labelOffset = IntOption(page, 6, "Label offset", 0, self._keyChangeCB, width=3, balloon="Additional offset" " of labels from color bar, in pixels") self.keyFontSize = IntOption(page, 7, "Font size", 24, self._keyChangeCB, width=3) self.keyFontStyle = FontStyle(page, 8, "Font style", oglFont.normal, self._keyChangeCB) self.keyFontTypeface = FontTypeface(page, 9, "Font typeface", FONT_TYPEFACE_VALUES[0], self._keyChangeCB) self.borderColor = RGBAOption(page, 10, "Border color", None, self._keyChangeCB, balloon="Color of border" " around color key (not each individual color).\n" "If 'no color', then no border is drawn.") self.borderWidth = IntOption(page, 11, "Border width", 3, self._keyChangeCB, balloon="in pixels") self.tickMarks = BooleanOption(page, 12, "Show tick marks", False, self._keyChangeCB, balloon="Show tick marks" " pointing from key to labels") self._componentsCB(self.numComponents) def destroy(self, *args): self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() chimera.triggers.deleteHandler(SAVE_SESSION, self._sessionHandlerID) chimera.triggers.deleteHandler(CLOSE_SESSION, self._closeHandlerID) chimera.triggers.deleteHandler(BEGIN_RESTORE_SESSION, self._beginRestoreHandlerID) chimera.openModels.close([self.model, self.keyModel]) ModelessDialog.destroy(self) def map(self, e=None): self._pageRaisedCB(self.notebook.getcurselection()) def unmap(self, e=None): self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() def changeToLabel(self, nextLabel, force=False): if nextLabel == self.model.curLabel and not force: return if self.model.curLabel and not unicode(self.model.curLabel) \ and self.model.curLabel != nextLabel: # remove previous label if empty self.removeLabel(self.model.curLabel) self.model.changeToLabel(nextLabel) self.labelText.component('text').configure(state='normal') self.labelTable.select(nextLabel) self.labelText.settext(unicode(nextLabel)) text = self.labelText.component('text') lineIndex = 1 for line in self.model.curLabel.lines: charIndex = 0 for c in line: text.tag_add(id(c), "%d.%d" % (lineIndex, charIndex)) charIndex += 1 text.tag_add(id(line), "%d.%d" % (lineIndex, charIndex)) lineIndex += 1 def Delete(self): if self.notebook.getcurselection() == self.LABELS: self.labelText.clear() if not self.model.curLabel: self.status("No label to delete", color="red", blankAfter=10) return self.removeLabel(self.model.curLabel) self.labelText.component('text').configure( state='disabled') else: self.keyPosition = None self._keyChangeCB() def Help(self): helpLoc = "ContributedSoftware/2dlabels/2dlabels.html" if self.notebook.getcurselection() == self.COLOR_KEY: helpLoc += "#colorkey" chimera.help.display(helpLoc) def keyConfigure(self, data, pageChange=True): self._componentsCB(len(data), update=False) for datum, well, label in zip(data, self.wells, self.labels): color, text = datum well.showColor(color, doCallback=False) label.variable.set(text, invoke_callbacks=False) self._keyChangeCB() if pageChange: self.notebook.selectpage(self.COLOR_KEY) def makeChar(self, char, model): attrs = {} try: attrs['rgba'] = self.colorWell.rgba except AttributeError: # multi or None if model: attrs['rgba'] = model.rgba size = self.labelFontSize.get() if size is not None: attrs['size'] = size style = self.labelFontStyle.get() if style is not None: attrs['style'] = style fontName = self.labelFontTypeface.get() if fontName is not None: attrs['fontName'] = fontName return Character(char, **attrs) def newLabel(self, pos): label = self.model.newLabel(pos) self.labelTable.setData(self.model.labels) self.status("Mouse drag to reposition label", color=self.EmphasisColor) return label def removeLabel(self, label): self.model.removeLabel(label) self.labelTable.setData(self.model.labels) if self.model.curLabel is not None: self.labelTable.select(self.model.curLabel) def reverseKey(self): data = zip([w.rgba for w in self.wells], [l.variable.get() for l in self.labels]) data.reverse() self.keyConfigure(data) def setLabelFromText(self): curLabel = self.model.curLabel text = self.labelText.component('text') # delete parts of label not in text... # # newlines first... while len(curLabel.lines) > 1: for i, line in enumerate(curLabel.lines[:-1]): if not text.tag_ranges(id(line)): curLabel.lines[i+1][:0] = line del curLabel.lines[i] break else: break # characters... for line in curLabel.lines: for c in line[:]: if not text.tag_ranges(id(c)): line.remove(c) # get new parts of text into label model = None targets = [] lines = curLabel.lines for line in lines: targets.extend([id(c) for c in line]) if not model and line: model = line[0] if line is not lines[-1]: targets.append(id(line)) contents = self.labelText.get()[:-1] # drop trailing newline if targets: target = targets.pop(0) else: target = None textLine = 1 textIndex = -1 curLine = lines[0] for c in contents: textIndex += 1 if str(target) in text.tag_names("%d.%d" % (textLine, textIndex)): if targets: target = targets.pop(0) else: target = None if c == '\n': textLine += 1 textIndex = -1 curLine = lines[[id(l) for l in lines].index( id(curLine))+1] elif curLine: model = curLine[textIndex] elif c == '\n': insertLine = curLine[0:textIndex] lines.insert(textLine-1, insertLine) del curLine[0:textIndex] text.tag_add(id(insertLine), "%d.%d" % (textLine, textIndex)) textLine += 1 textIndex = -1 else: labelChar = self.makeChar(c, model) curLine.insert(textIndex, labelChar) text.tag_add(id(labelChar), "%d.%d" % (textLine, textIndex)) self.model.setMajorChange() def updateGUI(self, source="gui"): curLabel = self.model.curLabel if curLabel and source == "gui": self.setLabelFromText() self.labelTable.setData(self.model.labels) if curLabel: self.labelTable.select(curLabel) self._updateTextAttrWidgets() def _colorCB(self, color): curLabel = self.model.curLabel if not curLabel: self.status("No label to color", color='red') return self.model.setMajorChange() for c in self._selChars(): c.rgba = color def _componentsCB(self, opt, update=True): cf = self.componentsFrame if hasattr(self, 'wells'): for well in self.wells: well.grid_forget() well.destroy() for label in self.labels: label.frame.grid_forget() self.reverseButton.grid_forget() self.reverseButton.destroy() else: Tkinter.Label(cf, text="Colors").grid(row=0) Tkinter.Label(cf, text="Labels").grid(row=0, column=1) if isinstance(opt, int): numComponents = opt self.numComponents.set(opt) else: numComponents = opt.get() wellSize = min(38, int( (7 * 38) / numComponents )) from CGLtk.color.ColorWell import ColorWell self.wells = [] self.labels = [] from CGLtk import Hybrid for i in range(numComponents): well = ColorWell(cf, width=wellSize, height=wellSize, callback=self._keyChangeCB, color='white') well.grid(row=i+1) self.wells.append(well) label = Hybrid.Entry(cf, "", 10) label.variable.add_callback(self._keyTypingCB) label.frame.grid(row=i+1, column=1, sticky='ew') self.labels.append(label) self.reverseButton = Tkinter.Button(cf, command=self.reverseKey, text="Reverse ordering of above", pady=0) self.reverseButton.grid(row=numComponents+1, column=0, columnspan=2) self.notebook.setnaturalsize() if update: self._keyChangeCB() def _contrastWithBG(self): bg = chimera.viewer.background if bg: bgColor = bg.rgba() else: bgColor = (0, 0, 0) if bgColor[0]*2 + bgColor[1]*3 + bgColor[2] < 0.417: return (1, 1, 1) else: return (0, 0, 0) def _eventToPos(self, viewer, event, offset = (0, 0)): w, h = viewer.windowSize return (event.x - offset[0]) / float(w), \ (h - event.y - offset[1]) / float(h) def _handleTextChange(self): self.updateGUI() self.labelText.edit_modified(False) def _insertSymbol(self, item): if len(item) > 1: from chimera import help help.display("ContributedSoftware/2dlabels/symbols.html") return if not self.model.labels: self.status("No labels have been created yet", color="red") return if not self.labelTable.selected(): self.status("No labels active", color="red") self.labelText.insert("insert", item) self.setLabelFromText() def _keyChangeCB(self, *args): self.keyModel.setMajorChange() def _keyTypingCB(self, fromAfter=False): # wait for a pause in typing before updating key... if fromAfter: self._typingHandler = None self._keyChangeCB() return handle = getattr(self, '_typingHandler', None) if handle: self.componentsFrame.after_cancel(handle) self._typingHandler = self.componentsFrame.after(500, lambda: self._keyTypingCB(fromAfter=True)) def _labelChangeCB(self, option): curLabel = self.model.curLabel self.model.setMajorChange() val = option.get() attrName = option.attribute for c in self._selChars(): setattr(c, attrName, val) def _labelListing(self, label): text = unicode(label) if '\n' in text: newline = text.index('\n') text= text[:newline] + "..." if not text: text = "<empty>" return "(%.2f, %.2f) %s" % (label.pos[0], label.pos[1], text) def _mouseFuncCB(self): self.status("") if not self.mouseLabelingVar.get(): if hasattr(self, "_prevMouse"): setButtonFunction("1", (), self._prevMouse) delattr(self, "_prevMouse") elif self.mlLabelVar.get() == self.MOUSE_LABEL_TEXT: if not hasattr(self, "_prevMouse"): self._prevMouse = getFuncName("1", ()) setButtonFunction("1", (), "place text") else: if not hasattr(self, "_prevMouse"): self._prevMouse = getFuncName("1", ()) setButtonFunction("1", (), "place key") def _moveLabel(self, viewer, event): pos = self._eventToPos(viewer, event, self._moveOffset) self.model.moveLabel(pos) curLabel = self.model.curLabel self.labelTable.setData(self.model.labels) self.labelTable.select(curLabel) def _pageRaisedCB(self, pageName): if pageName == "Labels": pageItem = self.MOUSE_LABEL_TEXT if not self.model.labels: self.status("Click mouse button 1 in graphics\n" "window to place first label", color=self.EmphasisColor) for index in range(0, self.fileMenu.index('end')+1): self.fileMenu.entryconfigure(index, state='normal') else: pageItem = self.MOUSE_KEY_TEXT self.status("Drag mouse to position/size key", color=self.EmphasisColor) for index in range(0, self.fileMenu.index('end')+1): self.fileMenu.entryconfigure(index, state='disabled') self.mlLabelVar.set(pageItem) # just setting the var doesn't cause the callback, and # yet using invoke() toggles the var, so set it _opposite_ # to what's desired before calling invoke() self.mouseLabelingVar.set(False) self.mouseModeButton.invoke() def _pickLabel(self, viewer, event): w, h = viewer.windowSize pos = self._eventToPos(viewer, event) label, self._moveOffset = self.model.pickLabel(pos, w, h) if label is None: label = self.newLabel(pos) self._moveOffset = (0, 0) self.changeToLabel(label) self.labelText.component('text').focus_set() def _readFile(self, okayed, dialog): if not okayed: return from Ilabel import readFiles readFiles(dialog.getPaths(), clear=dialog.deleteExistingVar.get()) def _readFileCB(self): if not hasattr(self, "_readFileDialog"): self._readFileDialog = ReadFileDialog( command=self._readFile, clientPos='s') self._readFileDialog.enter() def _restoreSession(self, info): if info["sel ranges"]: self.labelText.tag_add("sel", *info["sel ranges"]) self._updateTextAttrWidgets() self._suppressMap = True self.labelText.edit_modified(False) if "key position" not in info: self.notebook.selectpage(self.LABELS) if info["mouse func"] == "normal": self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() return self.keyPosition = info["key position"] self.colorTreatment.set(info["color depiction"]) self.labelPos.set(info["label positions"]) self.labelColor.set(info["label color"]) self.justification.set(info["label justification"]) self.labelOffset.set(info["label offset"]) self.keyFontSize.set(info["font size"]) self.keyFontStyle.set(info["font typeface"]) if "font name" in info: self.keyFontTypeface.set(info["font name"]) self.borderColor.set(info["border color"]) self.borderWidth.set(info["border width"]) self.tickMarks.set(info["show ticks"]) self.keyConfigure(info["colors/labels"]) if self.keyPosition: self.notebook.selectpage(self.COLOR_KEY) else: self.notebook.selectpage(self.LABELS) if info["mouse func"] == "normal": self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() return info def _saveSession(self, triggerName, myData, sessionFile): print>>sessionFile, """ def restore2DLabelDialog(info): from chimera.dialogs import find, display from Ilabel.gui import IlabelDialog dlg = find(IlabelDialog.name) if dlg is not None: dlg.destroy() dlg = display(IlabelDialog.name) dlg._restoreSession(info) import SimpleSession SimpleSession.registerAfterModelsCB(restore2DLabelDialog, %s) """ % repr(self._sessionInfo()) def _selChars(self): chars = [] curLabel = self.model.curLabel if curLabel: sel = self.labelText.tag_ranges("sel") if sel: sline, schar = [int(x) for x in str(sel[0]).split('.')] eline, echar = [int(x) for x in str(sel[1]).split('.')] sline -= 1 eline -= 1 for li, line in enumerate(curLabel.lines): if li < sline: continue if li > eline: break if sline == eline: chars.extend(line[schar:echar]) elif li == sline: chars.extend(line[schar:]) elif li == eline: chars.extend(line[:echar]) else: chars.extend(line) else: for l in curLabel.lines: chars.extend(l) return chars def _sessionInfo(self): info = {} info["sel ranges"] = tuple([str(tr) for tr in self.labelText.tag_ranges("sel")]) if self.mouseLabelingVar.get(): info["mouse func"] = "labeling" else: info["mouse func"] = "normal" info["key position"] = self.keyPosition info["colors/labels"] = [(w.rgba, l.variable.get()) for w, l in zip(self.wells, self.labels)] info["color depiction"] = self.colorTreatment.get() info["label positions"] = self.labelPos.get() info["label color"] = self.labelColor.get() info["label justification"] = self.justification.get() info["label offset"] = self.labelOffset.get() info["font size"] = self.keyFontSize.get() info["font typeface"] = self.keyFontStyle.get() info["font name"] = self.keyFontTypeface.get() info["border color"] = self.borderColor.get() info["border width"] = self.borderWidth.get() info["show ticks"] = self.tickMarks.get() return info def _sizeOrMoveKey(self, viewer, event): pos = self._eventToPos(viewer, event) if self.grabPos: deltas = [pos[axis] - self.grabPos[axis] for axis in [0, 1]] for posIndex in [0, 1]: old = self.keyPosition[posIndex] self.keyPosition[posIndex] = ( old[0] + deltas[0], old[1] + deltas[1]) self.grabPos = pos elif len(self.keyPosition) == 1: self.keyPosition.append(pos) else: self.keyPosition[1] = pos self._keyChangeCB() def _startOrGrabKey(self, viewer, event): pos = self._eventToPos(viewer, event) if self.keyPosition and len(self.keyPosition) == 2: # possible grab; # see if in middle third of long side... p1, p2 = self.keyPosition x1, y1 = p1 x2, y2 = p2 if abs(x2 - x1) < abs(y2 - y1): longAxis = 1 ymin = min(y2, y1) ymax = max(y2, y1) b1 = (2* ymin + ymax) / 3.0 b2 = (2* ymax + ymin) / 3.0 o1 = min(x1, x2) o2 = max(x1, x2) else: longAxis = 0 xmin = min(x2, x1) xmax = max(x2, x1) b1 = (2* xmin + xmax) / 3.0 b2 = (2* xmax + xmin) / 3.0 o1 = min(y1, y2) o2 = max(y1, y2) if b1 < pos[longAxis] < b2 \ and o1 < pos[1-longAxis] < o2: self.grabPos = pos return self.grabPos = None self.keyPosition = [pos] self._keyChangeCB() self.status("Grab middle of key to reposition", color=self.EmphasisColor) def _tableCB(self, sel): if not sel: return self.changeToLabel(sel) def _textCB(self, e): text = self.labelText.component('text') if not text.tk.call((text._w, 'edit', 'modified')): #if not text.edit_modified(): return # this callback can happen _before_ the change # actually occurs, so do the processing after idle text.after_idle(self._handleTextChange) def _updateTextAttrWidgets(self, e=None): rgba = None multiple = False for c in self._selChars(): if rgba is None: rgba = c.rgba elif rgba != c.rgba: multiple = True break if rgba is not None: self.colorWell.showColor(rgba, multiple=multiple, doCallback=False) self.labelFontSize.display(self._selChars()) self.labelFontStyle.display(self._selChars()) self.labelFontTypeface.display(self._selChars()) def _writeFile(self, okayed, dialog): if not okayed: return from Ilabel import writeFile writeFile(dialog.getPaths()[0]) def _writeFileCB(self): if not hasattr(self, "_writeFileDialog"): from OpenSave import SaveModeless self._writeFileDialog = SaveModeless(command=self._writeFile, title="Write 2D Labels Info") self._writeFileDialog.enter()
def fillInUI(self, parent): import Pmw, Tkinter self.buttonWidgets['OK']['state'] = 'disabled' self.buttonWidgets['Apply']['state'] = 'disabled' from chimera.widgets import ModelScrolledListBox self.surfListBox = ModelScrolledListBox( parent, labelpos='n', label_text='Surfaces to color by ESP:', listbox_selectmode="extended", filtFunc=lambda m: isinstance(m, chimera.MSMSModel), selectioncommand=self._selSurfCB) self.surfListBox.grid(row=0, column=0, sticky="nsew", columnspan=2) Pmw.OptionMenu(parent, command=self._menuCB, initialitem="3", items=[str(x) for x in range(2, 12)], labelpos='w', label_text="Number of colors/values:").grid( row=1, column=0, columnspan=2) f = self.interpFrame = Tkinter.Frame(parent) f.grid(row=2, column=0, columnspan=2) self.wells = [] self.values = [] self._entryOpts = { 'validate': 'real', 'entry_justify': 'center', 'entry_width': 6 } from CGLtk.color.ColorWell import ColorWell for color, value in [("red", -10), ("white", 0), ("blue", 10)]: well = ColorWell(f, color=color) well.grid(row=0, column=len(self.wells)) self.wells.append(well) entry = Pmw.EntryField(f, value=str(value), **self._entryOpts) entry.grid(row=1, column=len(self.values)) self.values.append(entry) from chimera.tkoptions import FloatOption, BooleanOption self.distDep = BooleanOption( parent, 3, "Distance-dependent dielectric", True, None, balloon="If true, charge falls off with distance squared to\n" "simulate solvent screening effects") self.dielectric = FloatOption(parent, 4, "Dielectric constant", 4.0, None) self.surfDist = FloatOption(parent, 5, "Distance from surface", 1.4, None, balloon="Potential at this distance from\n" "the surface is used for coloring") self.hisGroup = Pmw.Group(parent, hull_padx=2, tag_text="Implicit Histidine Protonation") self.hisGroup.grid(row=6, column=0, columnspan=2, sticky="nsew") self.hisProtVar = Tkinter.StringVar(parent) self.hisProtVar.set("name") interior = self.hisGroup.interior() interior.columnconfigure(0, weight=1) lab = Tkinter.Label( interior, text="Assumed histidine " "protonation for\nstructures without explicit hydrogens") from tkFont import Font font = Font(font=lab.cget('font')) font.config(size=int(0.75 * float(font.cget('size'))), slant='italic') lab.config(font=font) lab.grid(row=0) Tkinter.Radiobutton(interior, variable=self.hisProtVar, value="name", text="Residue name-based", command=self._switchHisList).grid(row=1, sticky='w') f = Tkinter.Frame(interior) f.grid(row=2) Tkinter.Label(f, text="HID/HIE/HIP = delta/epsilon/both").grid(row=0, sticky='w') self.hisDefault = Pmw.OptionMenu( f, initialitem=self.HB, items=[self.HB, "delta", "epsilon", "both"], labelpos='w', label_text="HIS = ", command=lambda a, s=self: setattr(s, 'hisChanged', True)) self.hisDefault.grid(row=1, sticky='w') self._pickText = Tkinter.StringVar(parent) self._pickText.set("Specified individually...") Tkinter.Radiobutton(interior, variable=self.hisProtVar, value="pick", textvariable=self._pickText, command=self._switchHisList).grid(row=3, sticky='w') Tkinter.Button(parent, pady=0, command=self._colorKeyCB, text="Create corresponding color key").grid( row=7, column=0, columnspan=2) self.hisChanged = False
class IlabelDialog(ModelessDialog): name = "2D Labels/Color Key" provideStatus = True buttons = ("Delete", "Close") LABELS = "Labels" COLOR_KEY = "Color Key" MOUSE_LABEL_TEXT = "Use mouse for label placement" MOUSE_KEY_TEXT = "Use mouse for key placement" EmphasisColor = "forest green" def __init__(self): import os.path myDir, junk = os.path.split(__file__) addFunction('place text', (self._pickLabel, self._moveLabel, None), icon=chimage.get( Image.open(os.path.join(myDir, 'ilabel.png')), tkgui.app)) addFunction('place key', (self._startOrGrabKey, self._sizeOrMoveKey, None), icon=chimage.get( Image.open(os.path.join(myDir, 'key.png')), tkgui.app)) import Ilabel if not Ilabel._ilabelModel: Ilabel.IlabelModel() self.model = Ilabel._ilabelModel ModelessDialog.__init__(self) self._sessionHandlerID = chimera.triggers.addHandler( SAVE_SESSION, self._saveSession, None) self._closeHandlerID = chimera.triggers.addHandler( CLOSE_SESSION, self.destroy, None) self._beginRestoreHandlerID = chimera.triggers.addHandler( BEGIN_RESTORE_SESSION, self.destroy, None) def fillInUI(self, parent): top = parent.winfo_toplevel() menubar = Tkinter.Menu(top, type="menubar", tearoff=False) top.config(menu=menubar) self.fileMenu = Tkinter.Menu(menubar) menubar.add_cascade(label="File", menu=self.fileMenu) self.fileMenu.add_command(label="Write...", command=self._writeFileCB) self.fileMenu.add_command(label="Read...", command=self._readFileCB) from chimera.tkgui import aquaMenuBar aquaMenuBar(menubar, parent, row=0) from ColorKey import KeyModel parent.rowconfigure(1, weight=1) parent.columnconfigure(0, weight=1) # _pageRaisedCB uses mouseModeVar, so define first self.mouseLabelingVar = Tkinter.IntVar(parent) self.mouseLabelingVar.set(True) self.mlLabelVar = Tkinter.StringVar(parent) self.mouseModeButton = Tkinter.Checkbutton( parent, command=self._mouseFuncCB, variable=self.mouseLabelingVar, textvariable=self.mlLabelVar) self.mouseModeButton.grid(row=2, column=0) self.notebook = Pmw.NoteBook(parent, raisecommand=self._pageRaisedCB) self.notebook.add(self.LABELS, tab_text=self.LABELS) self.notebook.add(self.COLOR_KEY, tab_text=self.COLOR_KEY) self.notebook.grid(row=1, column=0, sticky="nsew") self._fillLabelsPage(self.notebook.page(self.LABELS)) self.keyModel = KeyModel(self) self.keyPosition = None self._fillColorKeyPage(self.notebook.page(self.COLOR_KEY)) def _fillLabelsPage(self, page): page.columnconfigure(0, weight=1) page.columnconfigure(1, weight=1) page.columnconfigure(2, weight=1) row = 0 from CGLtk.Table import SortableTable self.labelTable = SortableTable(page, automultilineHeaders=False) self.labelTable.addColumn("Label [(x, y) text]", self._labelListing, anchor='w') self.labelTable.addColumn("Shown", "shown", format=bool) self.labelTable.setData(self.model.labels) self.labelTable.launch(browseCmd=self._tableCB, selectMode="single") self.labelTable.grid(row=row, column=0, columnspan=3, sticky="nsew") page.rowconfigure(row, weight=1) row += 1 self.labelText = Pmw.ScrolledText(page, labelpos='w', label_text="Text", text_height=3, text_width=20, text_wrap='none', text_state='disabled', text_exportselection=False) text = self.labelText.component('text') text.bind("<<Modified>>", self._textCB) text.bind("<<Selection>>", self._updateTextAttrWidgets) self.labelText.grid(row=row, column=0, sticky='nsew', columnspan=3) page.rowconfigure(row, weight=1) row += 1 self.labelSymbolMenu = Pmw.OptionMenu( page, labelpos='w', label_text="Insert symbol:", command=self._insertSymbol, items=[ u'\N{GREEK SMALL LETTER ALPHA}', u'\N{GREEK SMALL LETTER BETA}', u'\N{GREEK SMALL LETTER GAMMA}', u'\N{GREEK SMALL LETTER DELTA}', u'\N{GREEK SMALL LETTER EPSILON}', u'\N{GREEK SMALL LETTER PI}', u'\N{GREEK SMALL LETTER PHI}', u'\N{GREEK SMALL LETTER CHI}', u'\N{GREEK SMALL LETTER PSI}', u'\N{GREEK SMALL LETTER OMEGA}', u'\N{LEFTWARDS ARROW}', u'\N{RIGHTWARDS ARROW}', u'\N{LEFT RIGHT ARROW}', u'\N{UPWARDS ARROW}', u'\N{DOWNWARDS ARROW}', u'\N{SUPERSCRIPT TWO}', u'\N{SUPERSCRIPT THREE}', u'\N{DEGREE SIGN}', u'\N{LATIN CAPITAL LETTER A WITH RING ABOVE}', "more..." ]) self.labelSymbolMenu.grid(row=row, column=0, columnspan=3) row += 1 colorHouse = Pmw.LabeledWidget(page, labelpos='w', label_text="Color") colorHouse.grid(row=row, column=0, rowspan=3) from CGLtk.color.ColorWell import ColorWell self.colorWell = ColorWell(colorHouse.interior(), color=self._contrastWithBG(), callback=self._colorCB) self.colorWell.grid() from chimera.tkoptions import IntOption self.labelFontSize = IntOption(page, row, "Font size", 24, self._labelChangeCB, startCol=1, min=1, attribute="size", width=3) row += 1 self.labelFontStyle = FontStyle(page, row, "Font style", oglFont.normal, self._labelChangeCB, startCol=1) row += 1 self.labelFontTypeface = FontTypeface(page, row, "Font typeface", FONT_TYPEFACE_VALUES[0], self._labelChangeCB, startCol=1) row += 1 if self.model.curLabel: self.changeToLabel(self.model.curLabel, force=True) def _fillColorKeyPage(self, page): from chimera.tkoptions import IntOption, EnumOption, \ BooleanOption, RGBAOption f = Tkinter.Frame(page) f.grid(row=0, columnspan=2) self.numComponents = IntOption(f, 0, "Number of colors/labels", 3, self._componentsCB, min=2, width=2) self.componentsFrame = Tkinter.Frame(page) self.componentsFrame.grid(row=1, column=0, sticky="nsew", columnspan=2) page.columnconfigure(0, weight=1) self.componentsFrame.columnconfigure(1, weight=1) class ColorTreatment(EnumOption): values = ("distinct", "blended") self.colorTreatment = ColorTreatment( page, 2, "Color range depiction", "blended", self._keyChangeCB, balloon="Should colors be shown as distinct rectangles" " or as a continuous range") class LabelPosition(EnumOption): values = ("left/top", "right/bottom") self.labelPos = LabelPosition( page, 3, "Label positions", "right/bottom", self._keyChangeCB, balloon="Position of" " labels relative to color key.\nLabels always" " positioned adjacent to long side.") self.labelColor = RGBAOption( page, 4, "Label color", self._contrastWithBG(), self._keyChangeCB, balloob="Label color. If set to 'No color', use corresponding" " key color", noneOkay=True) class LabelJustification(EnumOption): values = ("left", "decimal point", "right") self.justification = LabelJustification( page, 5, "Label justification", "decimal point", self._keyChangeCB, balloon="Justification of label text" " in a vertical key layout.\nHorizontal key labels will" " always be center justified.") self.labelOffset = IntOption(page, 6, "Label offset", 0, self._keyChangeCB, width=3, balloon="Additional offset" " of labels from color bar, in pixels") self.keyFontSize = IntOption(page, 7, "Font size", 24, self._keyChangeCB, width=3) self.keyFontStyle = FontStyle(page, 8, "Font style", oglFont.normal, self._keyChangeCB) self.keyFontTypeface = FontTypeface(page, 9, "Font typeface", FONT_TYPEFACE_VALUES[0], self._keyChangeCB) self.borderColor = RGBAOption( page, 10, "Border color", None, self._keyChangeCB, balloon="Color of border" " around color key (not each individual color).\n" "If 'no color', then no border is drawn.") self.borderWidth = IntOption(page, 11, "Border width", 3, self._keyChangeCB, balloon="in pixels") self.tickMarks = BooleanOption(page, 12, "Show tick marks", False, self._keyChangeCB, balloon="Show tick marks" " pointing from key to labels") self._componentsCB(self.numComponents) def destroy(self, *args): self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() chimera.triggers.deleteHandler(SAVE_SESSION, self._sessionHandlerID) chimera.triggers.deleteHandler(CLOSE_SESSION, self._closeHandlerID) chimera.triggers.deleteHandler(BEGIN_RESTORE_SESSION, self._beginRestoreHandlerID) chimera.openModels.close([self.model, self.keyModel]) ModelessDialog.destroy(self) def map(self, e=None): self._pageRaisedCB(self.notebook.getcurselection()) def unmap(self, e=None): self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() def changeToLabel(self, nextLabel, force=False): if nextLabel == self.model.curLabel and not force: return if self.model.curLabel and not unicode(self.model.curLabel) \ and self.model.curLabel != nextLabel: # remove previous label if empty self.removeLabel(self.model.curLabel) self.model.changeToLabel(nextLabel) self.labelText.component('text').configure(state='normal') self.labelTable.select(nextLabel) self.labelText.settext(unicode(nextLabel)) text = self.labelText.component('text') lineIndex = 1 for line in self.model.curLabel.lines: charIndex = 0 for c in line: text.tag_add(id(c), "%d.%d" % (lineIndex, charIndex)) charIndex += 1 text.tag_add(id(line), "%d.%d" % (lineIndex, charIndex)) lineIndex += 1 def Delete(self): if self.notebook.getcurselection() == self.LABELS: self.labelText.clear() if not self.model.curLabel: self.status("No label to delete", color="red", blankAfter=10) return self.removeLabel(self.model.curLabel) self.labelText.component('text').configure(state='disabled') else: self.keyPosition = None self._keyChangeCB() def Help(self): helpLoc = "ContributedSoftware/2dlabels/2dlabels.html" if self.notebook.getcurselection() == self.COLOR_KEY: helpLoc += "#colorkey" chimera.help.display(helpLoc) def keyConfigure(self, data, pageChange=True): self._componentsCB(len(data), update=False) for datum, well, label in zip(data, self.wells, self.labels): color, text = datum well.showColor(color, doCallback=False) label.variable.set(text, invoke_callbacks=False) self._keyChangeCB() if pageChange: self.notebook.selectpage(self.COLOR_KEY) def makeChar(self, char, model): attrs = {} try: attrs['rgba'] = self.colorWell.rgba except AttributeError: # multi or None if model: attrs['rgba'] = model.rgba size = self.labelFontSize.get() if size is not None: attrs['size'] = size style = self.labelFontStyle.get() if style is not None: attrs['style'] = style fontName = self.labelFontTypeface.get() if fontName is not None: attrs['fontName'] = fontName return Character(char, **attrs) def newLabel(self, pos): label = self.model.newLabel(pos) self.labelTable.setData(self.model.labels) self.status("Mouse drag to reposition label", color=self.EmphasisColor) return label def removeLabel(self, label): self.model.removeLabel(label) self.labelTable.setData(self.model.labels) if self.model.curLabel is not None: self.labelTable.select(self.model.curLabel) def reverseKey(self): data = zip([w.rgba for w in self.wells], [l.variable.get() for l in self.labels]) data.reverse() self.keyConfigure(data) def setLabelFromText(self): curLabel = self.model.curLabel text = self.labelText.component('text') # delete parts of label not in text... # # newlines first... while len(curLabel.lines) > 1: for i, line in enumerate(curLabel.lines[:-1]): if not text.tag_ranges(id(line)): curLabel.lines[i + 1][:0] = line del curLabel.lines[i] break else: break # characters... for line in curLabel.lines: for c in line[:]: if not text.tag_ranges(id(c)): line.remove(c) # get new parts of text into label model = None targets = [] lines = curLabel.lines for line in lines: targets.extend([id(c) for c in line]) if not model and line: model = line[0] if line is not lines[-1]: targets.append(id(line)) contents = self.labelText.get()[:-1] # drop trailing newline if targets: target = targets.pop(0) else: target = None textLine = 1 textIndex = -1 curLine = lines[0] for c in contents: textIndex += 1 if str(target) in text.tag_names("%d.%d" % (textLine, textIndex)): if targets: target = targets.pop(0) else: target = None if c == '\n': textLine += 1 textIndex = -1 curLine = lines[[id(l) for l in lines].index(id(curLine)) + 1] elif curLine: model = curLine[textIndex] elif c == '\n': insertLine = curLine[0:textIndex] lines.insert(textLine - 1, insertLine) del curLine[0:textIndex] text.tag_add(id(insertLine), "%d.%d" % (textLine, textIndex)) textLine += 1 textIndex = -1 else: labelChar = self.makeChar(c, model) curLine.insert(textIndex, labelChar) text.tag_add(id(labelChar), "%d.%d" % (textLine, textIndex)) self.model.setMajorChange() def updateGUI(self, source="gui"): curLabel = self.model.curLabel if curLabel and source == "gui": self.setLabelFromText() self.labelTable.setData(self.model.labels) if curLabel: self.labelTable.select(curLabel) self._updateTextAttrWidgets() def _colorCB(self, color): curLabel = self.model.curLabel if not curLabel: self.status("No label to color", color='red') return self.model.setMajorChange() for c in self._selChars(): c.rgba = color def _componentsCB(self, opt, update=True): cf = self.componentsFrame if hasattr(self, 'wells'): for well in self.wells: well.grid_forget() well.destroy() for label in self.labels: label.frame.grid_forget() self.reverseButton.grid_forget() self.reverseButton.destroy() else: Tkinter.Label(cf, text="Colors").grid(row=0) Tkinter.Label(cf, text="Labels").grid(row=0, column=1) if isinstance(opt, int): numComponents = opt self.numComponents.set(opt) else: numComponents = opt.get() wellSize = min(38, int((7 * 38) / numComponents)) from CGLtk.color.ColorWell import ColorWell self.wells = [] self.labels = [] from CGLtk import Hybrid for i in range(numComponents): well = ColorWell(cf, width=wellSize, height=wellSize, callback=self._keyChangeCB, color='white') well.grid(row=i + 1) self.wells.append(well) label = Hybrid.Entry(cf, "", 10) label.variable.add_callback(self._keyTypingCB) label.frame.grid(row=i + 1, column=1, sticky='ew') self.labels.append(label) self.reverseButton = Tkinter.Button(cf, command=self.reverseKey, text="Reverse ordering of above", pady=0) self.reverseButton.grid(row=numComponents + 1, column=0, columnspan=2) self.notebook.setnaturalsize() if update: self._keyChangeCB() def _contrastWithBG(self): bg = chimera.viewer.background if bg: bgColor = bg.rgba() else: bgColor = (0, 0, 0) if bgColor[0] * 2 + bgColor[1] * 3 + bgColor[2] < 0.417: return (1, 1, 1) else: return (0, 0, 0) def _eventToPos(self, viewer, event, offset=(0, 0)): w, h = viewer.windowSize return (event.x - offset[0]) / float(w), \ (h - event.y - offset[1]) / float(h) def _handleTextChange(self): self.updateGUI() self.labelText.edit_modified(False) def _insertSymbol(self, item): if len(item) > 1: from chimera import help help.display("ContributedSoftware/2dlabels/symbols.html") return if not self.model.labels: self.status("No labels have been created yet", color="red") return if not self.labelTable.selected(): self.status("No labels active", color="red") self.labelText.insert("insert", item) self.setLabelFromText() def _keyChangeCB(self, *args): self.keyModel.setMajorChange() def _keyTypingCB(self, fromAfter=False): # wait for a pause in typing before updating key... if fromAfter: self._typingHandler = None self._keyChangeCB() return handle = getattr(self, '_typingHandler', None) if handle: self.componentsFrame.after_cancel(handle) self._typingHandler = self.componentsFrame.after( 500, lambda: self._keyTypingCB(fromAfter=True)) def _labelChangeCB(self, option): curLabel = self.model.curLabel self.model.setMajorChange() val = option.get() attrName = option.attribute for c in self._selChars(): setattr(c, attrName, val) def _labelListing(self, label): text = unicode(label) if '\n' in text: newline = text.index('\n') text = text[:newline] + "..." if not text: text = "<empty>" return "(%.2f, %.2f) %s" % (label.pos[0], label.pos[1], text) def _mouseFuncCB(self): self.status("") if not self.mouseLabelingVar.get(): if hasattr(self, "_prevMouse"): setButtonFunction("1", (), self._prevMouse) delattr(self, "_prevMouse") elif self.mlLabelVar.get() == self.MOUSE_LABEL_TEXT: if not hasattr(self, "_prevMouse"): self._prevMouse = getFuncName("1", ()) setButtonFunction("1", (), "place text") else: if not hasattr(self, "_prevMouse"): self._prevMouse = getFuncName("1", ()) setButtonFunction("1", (), "place key") def _moveLabel(self, viewer, event): pos = self._eventToPos(viewer, event, self._moveOffset) self.model.moveLabel(pos) curLabel = self.model.curLabel self.labelTable.setData(self.model.labels) self.labelTable.select(curLabel) def _pageRaisedCB(self, pageName): if pageName == "Labels": pageItem = self.MOUSE_LABEL_TEXT if not self.model.labels: self.status( "Click mouse button 1 in graphics\n" "window to place first label", color=self.EmphasisColor) for index in range(0, self.fileMenu.index('end') + 1): self.fileMenu.entryconfigure(index, state='normal') else: pageItem = self.MOUSE_KEY_TEXT self.status("Drag mouse to position/size key", color=self.EmphasisColor) for index in range(0, self.fileMenu.index('end') + 1): self.fileMenu.entryconfigure(index, state='disabled') self.mlLabelVar.set(pageItem) # just setting the var doesn't cause the callback, and # yet using invoke() toggles the var, so set it _opposite_ # to what's desired before calling invoke() self.mouseLabelingVar.set(False) self.mouseModeButton.invoke() def _pickLabel(self, viewer, event): w, h = viewer.windowSize pos = self._eventToPos(viewer, event) label, self._moveOffset = self.model.pickLabel(pos, w, h) if label is None: label = self.newLabel(pos) self._moveOffset = (0, 0) self.changeToLabel(label) self.labelText.component('text').focus_set() def _readFile(self, okayed, dialog): if not okayed: return from Ilabel import readFiles readFiles(dialog.getPaths(), clear=dialog.deleteExistingVar.get()) def _readFileCB(self): if not hasattr(self, "_readFileDialog"): self._readFileDialog = ReadFileDialog(command=self._readFile, clientPos='s') self._readFileDialog.enter() def _restoreSession(self, info): if info["sel ranges"]: self.labelText.tag_add("sel", *info["sel ranges"]) self._updateTextAttrWidgets() self._suppressMap = True self.labelText.edit_modified(False) if "key position" not in info: self.notebook.selectpage(self.LABELS) if info["mouse func"] == "normal": self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() return self.keyPosition = info["key position"] self.colorTreatment.set(info["color depiction"]) self.labelPos.set(info["label positions"]) self.labelColor.set(info["label color"]) self.justification.set(info["label justification"]) self.labelOffset.set(info["label offset"]) self.keyFontSize.set(info["font size"]) self.keyFontStyle.set(info["font typeface"]) if "font name" in info: self.keyFontTypeface.set(info["font name"]) self.borderColor.set(info["border color"]) self.borderWidth.set(info["border width"]) self.tickMarks.set(info["show ticks"]) self.keyConfigure(info["colors/labels"]) if self.keyPosition: self.notebook.selectpage(self.COLOR_KEY) else: self.notebook.selectpage(self.LABELS) if info["mouse func"] == "normal": self.mouseLabelingVar.set(True) self.mouseModeButton.invoke() return info def _saveSession(self, triggerName, myData, sessionFile): print >> sessionFile, """ def restore2DLabelDialog(info): from chimera.dialogs import find, display from Ilabel.gui import IlabelDialog dlg = find(IlabelDialog.name) if dlg is not None: dlg.destroy() dlg = display(IlabelDialog.name) dlg._restoreSession(info) import SimpleSession SimpleSession.registerAfterModelsCB(restore2DLabelDialog, %s) """ % repr(self._sessionInfo()) def _selChars(self): chars = [] curLabel = self.model.curLabel if curLabel: sel = self.labelText.tag_ranges("sel") if sel: sline, schar = [int(x) for x in str(sel[0]).split('.')] eline, echar = [int(x) for x in str(sel[1]).split('.')] sline -= 1 eline -= 1 for li, line in enumerate(curLabel.lines): if li < sline: continue if li > eline: break if sline == eline: chars.extend(line[schar:echar]) elif li == sline: chars.extend(line[schar:]) elif li == eline: chars.extend(line[:echar]) else: chars.extend(line) else: for l in curLabel.lines: chars.extend(l) return chars def _sessionInfo(self): info = {} info["sel ranges"] = tuple( [str(tr) for tr in self.labelText.tag_ranges("sel")]) if self.mouseLabelingVar.get(): info["mouse func"] = "labeling" else: info["mouse func"] = "normal" info["key position"] = self.keyPosition info["colors/labels"] = [(w.rgba, l.variable.get()) for w, l in zip(self.wells, self.labels)] info["color depiction"] = self.colorTreatment.get() info["label positions"] = self.labelPos.get() info["label color"] = self.labelColor.get() info["label justification"] = self.justification.get() info["label offset"] = self.labelOffset.get() info["font size"] = self.keyFontSize.get() info["font typeface"] = self.keyFontStyle.get() info["font name"] = self.keyFontTypeface.get() info["border color"] = self.borderColor.get() info["border width"] = self.borderWidth.get() info["show ticks"] = self.tickMarks.get() return info def _sizeOrMoveKey(self, viewer, event): pos = self._eventToPos(viewer, event) if self.grabPos: deltas = [pos[axis] - self.grabPos[axis] for axis in [0, 1]] for posIndex in [0, 1]: old = self.keyPosition[posIndex] self.keyPosition[posIndex] = (old[0] + deltas[0], old[1] + deltas[1]) self.grabPos = pos elif len(self.keyPosition) == 1: self.keyPosition.append(pos) else: self.keyPosition[1] = pos self._keyChangeCB() def _startOrGrabKey(self, viewer, event): pos = self._eventToPos(viewer, event) if self.keyPosition and len(self.keyPosition) == 2: # possible grab; # see if in middle third of long side... p1, p2 = self.keyPosition x1, y1 = p1 x2, y2 = p2 if abs(x2 - x1) < abs(y2 - y1): longAxis = 1 ymin = min(y2, y1) ymax = max(y2, y1) b1 = (2 * ymin + ymax) / 3.0 b2 = (2 * ymax + ymin) / 3.0 o1 = min(x1, x2) o2 = max(x1, x2) else: longAxis = 0 xmin = min(x2, x1) xmax = max(x2, x1) b1 = (2 * xmin + xmax) / 3.0 b2 = (2 * xmax + xmin) / 3.0 o1 = min(y1, y2) o2 = max(y1, y2) if b1 < pos[longAxis] < b2 \ and o1 < pos[1-longAxis] < o2: self.grabPos = pos return self.grabPos = None self.keyPosition = [pos] self._keyChangeCB() self.status("Grab middle of key to reposition", color=self.EmphasisColor) def _tableCB(self, sel): if not sel: return self.changeToLabel(sel) def _textCB(self, e): text = self.labelText.component('text') if not text.tk.call((text._w, 'edit', 'modified')): #if not text.edit_modified(): return # this callback can happen _before_ the change # actually occurs, so do the processing after idle text.after_idle(self._handleTextChange) def _updateTextAttrWidgets(self, e=None): rgba = None multiple = False for c in self._selChars(): if rgba is None: rgba = c.rgba elif rgba != c.rgba: multiple = True break if rgba is not None: self.colorWell.showColor(rgba, multiple=multiple, doCallback=False) self.labelFontSize.display(self._selChars()) self.labelFontStyle.display(self._selChars()) self.labelFontTypeface.display(self._selChars()) def _writeFile(self, okayed, dialog): if not okayed: return from Ilabel import writeFile writeFile(dialog.getPaths()[0]) def _writeFileCB(self): if not hasattr(self, "_writeFileDialog"): from OpenSave import SaveModeless self._writeFileDialog = SaveModeless(command=self._writeFile, title="Write 2D Labels Info") self._writeFileDialog.enter()
class CastpDialog(ModelessDialog): help = "UsersGuide/castp.html" buttons = ("Quit", "Hide") def __init__(self, name, cavities, sessionData=None): self.title = "CASTp: %s" % name self.cavities = cavities from weakref import proxy def wrapper(s=proxy(self)): s._cavityChangeCB() for cav in cavities: cav.pocketInfo["atoms"].selChangedCB = wrapper cav.mouthInfo["atoms"].selChangedCB = wrapper if sessionData: self.tableData = sessionData else: self.tableData = None ModelessDialog.__init__(self) chimera.extension.manager.registerInstance(self) def fillInUI(self, parent): from sys import getrefcount import Tkinter, Pmw top = parent.winfo_toplevel() menubar = Tkinter.Menu(top, type="menubar", tearoff=False) top.config(menu=menubar) self.columnMenu = Tkinter.Menu(menubar) menubar.add_cascade(label="Columns", menu=self.columnMenu) from chimera.tkgui import aquaMenuBar aquaMenuBar(menubar, parent, row = 0) row = 1 from CGLtk.Table import SortableTable self.cavityTable = SortableTable(parent, menuInfo= (self.columnMenu, prefs, dict.fromkeys( defaults[SHOWN_COLS], True), False)) if not self.tableData: from CASTp import mouthFieldNames, pocketFieldNames # add preferred columns first shownCols = prefs[SHOWN_COLS] for fn in ("ID", "MS volume", "SA volume", "pocket MS area", "pocket SA area", "# openings"): if fn[0] == '#' or fn == "ID": kw = {'format': "%d"} else: kw = {'format': "%6.1f", 'font': "TkFixedFont"} self.cavityTable.addColumn(fn, "lambda c: " "c.pocketInfo['%s']" % fn, **kw) for fn in ("mouth MS area", "mouth SA area", "MS circumference sum", "SA circumference sum"): self.cavityTable.addColumn(fn, "lambda c: " "c.mouthInfo['%s']" % fn, format="%6.1f", font='TkFixedFont') for fieldNames, attrName in [ (pocketFieldNames, "pocketInfo"), (mouthFieldNames, "mouthInfo")]: for fn in fieldNames: if fn[0] == '#' or fn == "ID": kw = {'format': "%d"} else: kw = {'format': "%6.1f", 'font': "TkFixedFont"} c = self.cavityTable.addColumn(fn, "lambda c: " "getattr(c, '%s')['%s']" % (attrName, fn), **kw) if fn == "ID": self.cavityTable.sortBy(c) self.cavityTable.sortBy(c) self.cavityTable.setData(self.cavities) self.cavityTable.launch(browseCmd=self._selCavityCB, restoreInfo=self.tableData) self.cavityTable.grid(row=row, column=0, sticky="nsew") parent.rowconfigure(row, weight=1) parent.columnconfigure(0, weight=1) row += 1 grp = Pmw.Group(parent, tag_text="Treatment of Chosen Pocket Atoms") grp.grid(row=row) checkFrame = grp.interior() from CGLtk import Hybrid def buttonCB(s=self): self._selCavityCB(self.cavityTable.selected()) self.doSelect = Hybrid.Checkbutton(checkFrame, "Select", prefs[DO_SELECT]) self.doSelect.variable.add_callback(buttonCB) self.doSelect.button.grid(row=0, sticky='w') f = Tkinter.Frame(checkFrame) f.grid(row=1, sticky='w') self.doColor = Hybrid.Checkbutton(f, "Color", prefs[DO_COLOR]) self.doColor.variable.add_callback(buttonCB) self.doColor.button.grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.pocketColor = ColorWell(f, color=prefs[POCKET_COLOR], noneOkay=True) self.pocketColor.grid(row=0, column=1) Tkinter.Label(f, text=" (and color all other atoms ").grid( row=0, column=2) self.nonpocketColor = ColorWell(f, color=prefs[NONPOCKET_COLOR], noneOkay=True) self.nonpocketColor.grid(row=0, column=3) Tkinter.Label(f, text=")").grid(row=0, column=4) self.doSurface = Hybrid.Checkbutton(checkFrame, "Surface", prefs[DO_SURFACE]) self.doSurface.variable.add_callback(buttonCB) self.doSurface.button.grid(row=2, sticky='w') self.doZoom = Hybrid.Checkbutton(checkFrame, "Zoom in on", prefs[DO_ZOOM]) self.doZoom.variable.add_callback(buttonCB) self.doZoom.button.grid(row=3, sticky='w') self.excludeMouth = Hybrid.Checkbutton(checkFrame, "Exclude mouth atoms", prefs[EXCLUDE_MOUTH]) self.excludeMouth.variable.add_callback(buttonCB) self.excludeMouth.button.grid(row=4, sticky='w') row += 1 def destroy(self): if self.cavities: cav1 = self.cavities[0] atoms = (cav1.mouthInfo["atoms"].atoms() or cav1.pocketInfo["atoms"].atoms()) if atoms: # close surface too... from chimera import openModels mol = atoms[0].molecule openModels.close(openModels.list( id=mol.id, subid=mol.subid)) for chk in [self.doSelect, self.doColor, self.doSurface, self.doZoom, self.excludeMouth]: chk.destroy() chimera.extension.manager.deregisterInstance(self) ModelessDialog.destroy(self) def emHide(self): """Extension manager method""" self.Close() Hide = emHide def emName(self): """Extension manager method""" return self.title def emQuit(self): """Extension manager method""" self.destroy() Quit = emQuit def emRaise(self): """Extension manager method""" self.enter() def _cavityChangeCB(self): newCavities = [cav for cav in self.cavities if len(cav.mouthInfo["atoms"]) > 0 or len(cav.pocketInfo["atoms"]) > 0] if len(newCavities) == len(self.cavities): return if not newCavities: self.destroy() return self.cavities = newCavities self.cavityTable.setData(self.cavities) def _colDispChange(self, col): self.cavityTable.columnUpdate(col, display=not col.display) prefs[SHOWN_COLS] = [c.title for c in self.cavityTable.columns if c.display] def _selCavityCB(self, tableSel): prefs[EXCLUDE_MOUTH] = self.excludeMouth.variable.get() from chimera.selection import ItemizedSelection, mergeCurrent, \ EXTEND, REMOVE cavitySel = ItemizedSelection() for cavity in tableSel: cavitySel.merge(EXTEND, cavity.pocketInfo["atoms"]) if prefs[EXCLUDE_MOUTH]: cavitySel.merge(REMOVE, cavity.mouthInfo["atoms"]) cavitySel.addImplied() # might be no cavities selected... cav1 = self.cavities[0] someA = (cav1.mouthInfo["atoms"].atoms() or cav1.pocketInfo["atoms"].atoms())[0] if someA.__destroyed__: return mol = someA.molecule cavitySet = set(cavitySel.atoms()) from chimera import selectionOperation doSelect = self.doSelect.variable.get() if doSelect != prefs[DO_SELECT]: #if not doSelect: # mergeCurrent(REMOVE, cavitySel) prefs[DO_SELECT] = doSelect doColor = self.doColor.variable.get() if doColor != prefs[DO_COLOR]: if not doColor and hasattr(self, '_prevColors'): for a, c, sc in self._prevColors: if a.__destroyed__: continue a.color = c a.surfaceColor = sc delattr(self, '_prevColors') prefs[DO_COLOR] = doColor if doColor: prefs[POCKET_COLOR] = self.pocketColor.rgba prefs[NONPOCKET_COLOR] = self.nonpocketColor.rgba doSurface = self.doSurface.variable.get() if doSurface != prefs[DO_SURFACE]: if not doSurface: for a in cavitySet: a.surfaceDisplay = False prefs[DO_SURFACE] = doSurface doZoom = self.doZoom.variable.get() if doZoom != prefs[DO_ZOOM]: if not doZoom: from Midas import focus, uncofr focus([mol]) uncofr() prefs[DO_ZOOM] = doZoom if doSelect: selectionOperation(cavitySel) if doColor: if prefs[POCKET_COLOR] == None: pocketColor = None else: pocketColor = chimera.MaterialColor( *prefs[POCKET_COLOR]) if prefs[NONPOCKET_COLOR] == None: nonpocketColor = None else: nonpocketColor = chimera.MaterialColor( *prefs[NONPOCKET_COLOR]) if not hasattr(self, '_prevColors'): self._prevColors = [(a, a.color, a.surfaceColor) for a in mol.atoms] for a in mol.atoms: if a in cavitySet: a.surfaceColor = a.color = pocketColor else: a.surfaceColor = a.color = nonpocketColor if doSurface: for a in mol.atoms: a.surfaceDisplay = a in cavitySet surfs = chimera.openModels.list(mol.id, mol.subid, modelTypes=[chimera.MSMSModel]) catsurfs = [s for s in surfs if s.category == "main"] if not catsurfs: from Midas import surfaceNew surfaceNew("main", models=[mol]) if doZoom and tableSel: from Midas import align, focus align(cavitySel, mol.atoms) focus(cavitySel)
class DetectClashDialog(ModelessDialog): name = "detect clashes" title = "Find Clashes/Contacts" provideStatus = True statusPosition = "above" help = "ContributedSoftware/findclash/findclash.html" FREQ_APPLY = "when OK/Apply clicked" FREQ_MOTION = "after relative motions (until dialog closed)" FREQ_CONTINUOUS = "continuously (until dialog closed)" CHECK_SET = "second set of designated atoms" def fillInUI(self, parent): self._handlers = {} desigGroup = Pmw.Group(parent, tag_text="Atoms to Check", hull_padx=2) desigGroup.grid(row=0, sticky="ew") from chimera.tkgui import windowSystem Tkinter.Button(desigGroup.interior(), command=self._desigCB, text="Designate").grid(row=0, column=0, sticky='e') Tkinter.Label(desigGroup.interior(), text="currently selected" " atoms for checking").grid(row=0, column=1, sticky='w') self.desigStatus = Tkinter.Label(desigGroup.interior()) from tkFont import Font font = Font(font=self.desigStatus.cget('font')) size = int(font.cget('size')) if size > 2: font.config(size=size - 2) font.config(weight='normal') self.desigStatus.config(font=font) from chimera.selection import ItemizedSelection self.designated = ItemizedSelection( selChangedCB=self._updateDesigStatus) self.desigStatus.grid(row=1, column=0, columnspan=2) self.designated2 = ItemizedSelection(selChangedCB=self._locButtonCB) if windowSystem == 'aqua': pady = None else: pady = 0 Tkinter.Button(desigGroup.interior(), command=self._desig2CB, pady=pady, text="Designate selection as second set").grid(row=3, column=1) self.desig2Status = Tkinter.Label(desigGroup.interior()) if size > 4: font2 = Font(font=font) font2.config(size=size - 4) else: font2 = font self.desig2Status.config(font=font2) self.desig2Status.grid(row=4, column=1) self.checkLocButtons = Pmw.RadioSelect( desigGroup.interior(), pady=0, orient='vertical', buttontype='radiobutton', labelpos='w', label_text="Check designated\natoms" " against:", command=self._locButtonCB) self.checkLocButtons.grid(row=2, column=0, columnspan=2) self.checkLocButtons.add("themselves") self.checkLocButtons.add("all other atoms") self.checkLocButtons.add("other atoms in same model") self.checkLocButtons.add(self.CHECK_SET) self.checkLocButtons.invoke(1) defGroup = Pmw.Group(parent, tag_text="Clash/Contact Parameters", hull_padx=2) defGroup.grid(row=1, sticky='ew') self.clashDef = ClashDef(defGroup.interior(), command=self._checkContinuous, value=str(prefs[CLASH_THRESHOLD])) self.clashDef.grid(row=0, sticky='w') self.hbondAllow = HbondAllow(defGroup.interior(), command=self._checkContinuous, value=str(prefs[HBOND_ALLOWANCE])) self.hbondAllow.grid(row=1, sticky='w') defaultsFrame = Tkinter.Frame(defGroup.interior()) defaultsFrame.grid(row=2) Tkinter.Label(defaultsFrame, text="Default").grid(row=0, column=0) Tkinter.Button(defaultsFrame, text="clash", pady=pady, command=self._clashDefaultsCB).grid(row=0, column=1) Tkinter.Label(defaultsFrame, text="/").grid(row=0, column=2) Tkinter.Button(defaultsFrame, text="contact", pady=pady, command=self._contactDefaultsCB).grid(row=0, column=3) Tkinter.Label(defaultsFrame, text="criteria").grid(row=0, column=4) bondsFrame = Tkinter.Frame(defGroup.interior()) bondsFrame.grid(row=3, sticky='w') self.bondsApart = Pmw.OptionMenu(bondsFrame, labelpos='w', label_text="Ignore contacts of pairs", command=self._checkContinuous, initialitem=str( prefs[BOND_SEPARATION]), items=[str(i + 2) for i in range(4)]) self.bondsApart.grid(row=0, column=0) Tkinter.Label(bondsFrame, text="or fewer bonds apart").grid(row=0, column=1) self.ignoreIntraResVar = Tkinter.IntVar(parent) self.ignoreIntraResVar.set(prefs[IGNORE_INTRA_RES]) Tkinter.Checkbutton(defGroup.interior(), text="Ignore intra-" "residue contacts", variable=self.ignoreIntraResVar, command=self._checkContinuous).grid(row=4) actionGroup = Pmw.Group(parent, tag_text="Treatment of Clash/Contact Atoms", hull_padx=2) actionGroup.grid(row=2, sticky='ew') self.actionSelVar = Tkinter.IntVar(parent) self.actionSelVar.set(prefs[ACTION_SELECT]) Tkinter.Checkbutton(actionGroup.interior(), text="Select", command=self._checkContinuous, variable=self.actionSelVar).grid(row=0, sticky='w') self.actionColorVar = Tkinter.IntVar(parent) self.actionColorVar.set(prefs[ACTION_COLOR]) f = Tkinter.Frame(actionGroup.interior()) f.grid(row=1, sticky='w') Tkinter.Checkbutton(f, text="Color", command=self._checkContinuous, variable=self.actionColorVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.clashColorWell = ColorWell(f, noneOkay=True, callback=self._checkContinuous, color=prefs[CLASH_COLOR]) self.clashColorWell.grid(row=0, column=1) Tkinter.Label(f, text=" (and color all other atoms").grid(row=0, column=2) self.nonclashColorWell = ColorWell(f, noneOkay=True, callback=self._checkContinuous, color=prefs[NONCLASH_COLOR]) self.nonclashColorWell.grid(row=0, column=3) Tkinter.Label(f, text=")").grid(row=0, column=4) self.actionPBVar = Tkinter.IntVar(parent) self.actionPBVar.set(prefs[ACTION_PSEUDOBONDS]) f = Tkinter.Frame(actionGroup.interior()) f.grid(row=2, sticky='w') Tkinter.Checkbutton(f, text="Draw pseudobonds of color", command=self._checkContinuous, variable=self.actionPBVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.pbColorWell = ColorWell(f, noneOkay=False, callback=self._checkContinuous, color=prefs[PB_COLOR]) self.pbColorWell.grid(row=0, column=1) self.pbWidthEntry = Pmw.EntryField(f, labelpos='w', label_text=" and width", validate={ 'validator': 'real', 'min': 0.01 }, entry_width=4, entry_justify="center", command=self._checkContinuous, value=str(prefs[PB_WIDTH])) self.pbWidthEntry.grid(row=0, column=2) self.actionAttrVar = Tkinter.IntVar(parent) self.actionAttrVar.set(prefs[ACTION_ATTR]) self.assignAttrButton = Tkinter.Checkbutton( actionGroup.interior(), text="Assign 'overlap' attribute", variable=self.actionAttrVar) self.assignAttrButton.grid(row=3, sticky='w') self.actionWriteInfoVar = Tkinter.IntVar(parent) self.actionWriteInfoVar.set(prefs[ACTION_WRITEINFO]) self.writeInfoButton = Tkinter.Checkbutton( actionGroup.interior(), text="Write information to" " file", variable=self.actionWriteInfoVar) self.writeInfoButton.grid(row=4, sticky='w') self.actionLogInfoVar = Tkinter.IntVar(parent) self.actionLogInfoVar.set(prefs[ACTION_REPLYLOG]) self.logInfoButton = Tkinter.Checkbutton( actionGroup.interior(), text="Write information to" " reply log", variable=self.actionLogInfoVar) self.logInfoButton.grid(row=5, sticky='w') freqGroup = Pmw.Group(parent, tag_text="Frequency of Checking", hull_padx=2) freqGroup.grid(row=3, sticky="ew") self.freqButtons = Pmw.RadioSelect(freqGroup.interior(), pady=0, orient='vertical', buttontype='radiobutton', labelpos='w', label_text="Check...", command=self._freqChangeCB) self.freqButtons.grid(sticky='w') self.freqButtons.add(self.FREQ_APPLY) self.freqButtons.add(self.FREQ_MOTION) self.freqButtons.add(self.FREQ_CONTINUOUS) self.freqButtons.invoke(0) self._updateDesigStatus() def OK(self, *args): # use main status line if dialog closing from chimera.replyobj import status self.status = status ModelessDialog.OK(self, *args) def Apply(self, *args): # workaround: remove pseudobonds before recreating colors # so C++ layer doesn't end up with pointers to deleted # colors in obscure circumstances from DetectClash import nukeGroup nukeGroup() from chimera import UserError self.status("") checkAtoms = self.designated.atoms() if not checkAtoms: self.enter() raise UserError("No atoms designated for clash detection") self.clashDef['command'] = None self.clashDef.invoke() self.clashDef['command'] = self._checkContinuous if not self.clashDef.valid(): self.enter() raise UserError("Invalid clash amount" " (in Clash/Contact Parameters)") prefs[CLASH_THRESHOLD] = float(self.clashDef.getvalue()) self.hbondAllow['command'] = None self.hbondAllow.invoke() self.hbondAllow['command'] = self._checkContinuous if not self.hbondAllow.valid(): self.enter() raise UserError("Invalid H-bond overlap amount" " (in Clash/Contact Parameters)") prefs[HBOND_ALLOWANCE] = float(self.hbondAllow.getvalue()) prefs[BOND_SEPARATION] = int(self.bondsApart.getvalue()) prefs[IGNORE_INTRA_RES] = self.ignoreIntraResVar.get() checkVal = self.checkLocButtons.getvalue() if checkVal == "themselves": test = "self" elif checkVal == "all other atoms": test = "others" elif checkVal == "other atoms in same model": test = "model" else: test = self.designated2.atoms() if not test: self.enter() raise UserError("No second-set atoms designated") actionAttr = prefs[ACTION_ATTR] = self.actionAttrVar.get() actionSelect = prefs[ACTION_SELECT] = self.actionSelVar.get() actionColor = prefs[ACTION_COLOR] = self.actionColorVar.get() actionPseudobonds = prefs[ACTION_PSEUDOBONDS] = \ self.actionPBVar.get() actionWriteInfo = prefs[ACTION_WRITEINFO] = \ self.actionWriteInfoVar.get() actionLogInfo = prefs[ACTION_REPLYLOG] = \ self.actionLogInfoVar.get() if self.freqButtons.getvalue() != self.FREQ_APPLY: actionAttr = actionWriteInfo = actionLogInfo = False if not actionAttr and not actionSelect and not actionColor \ and not actionPseudobonds and not actionWriteInfo \ and not actionLogInfo: self.enter() raise UserError("No actions selected for clashes") self.status("Checking for clashes") clashColor = nonclashColor = None if actionColor: prefs[CLASH_COLOR] = self.clashColorWell.rgba prefs[NONCLASH_COLOR] = self.nonclashColorWell.rgba if prefs[CLASH_COLOR] == None: clashColor = None else: clashColor = chimera.MaterialColor(*prefs[CLASH_COLOR]) if prefs[NONCLASH_COLOR] == None: nonclashColor = None else: nonclashColor = chimera.MaterialColor(*prefs[NONCLASH_COLOR]) pbColor = None if actionPseudobonds: prefs[PB_COLOR] = self.pbColorWell.rgba pbColor = chimera.MaterialColor(*prefs[PB_COLOR]) self.pbWidthEntry['command'] = None self.pbWidthEntry.invoke() self.pbWidthEntry['command'] = self._checkContinuous if not self.pbWidthEntry.valid(): self.enter() raise UserError("Invalid pseudobond width " "(in Treatment of Clash/Contact Atoms)") prefs[PB_WIDTH] = float(self.pbWidthEntry.getvalue()) from DetectClash import cmdDetectClash if actionWriteInfo: saveFile = "-" else: saveFile = None clashes = cmdDetectClash(checkAtoms, test=test, overlapCutoff=prefs[CLASH_THRESHOLD], hbondAllowance=prefs[HBOND_ALLOWANCE], bondSeparation=prefs[BOND_SEPARATION], ignoreIntraRes=prefs[IGNORE_INTRA_RES], setAttrs=actionAttr, selectClashes=actionSelect, colorClashes=actionColor, clashColor=clashColor, nonclashColor=nonclashColor, makePseudobonds=actionPseudobonds, pbColor=pbColor, lineWidth=prefs[PB_WIDTH], saveFile=saveFile, log=actionLogInfo, summary=self.status) if actionAttr: from ShowAttr import ShowAttrDialog from chimera import dialogs from DetectClash import attrName d = dialogs.display(ShowAttrDialog.name) d.configure(attrsOf="atoms", attrName=attrName, mode="Render") def Close(self): ModelessDialog.Close(self) if self.freqButtons.getvalue() != self.FREQ_APPLY: self.freqButtons.invoke(self.FREQ_APPLY) def _checkContinuous(self, *args): if self.freqButtons.getvalue() == self.FREQ_CONTINUOUS: self.Apply() def _clashDefaultsCB(self): from prefs import defaults self.hbondAllow.setvalue(str(defaults[HBOND_ALLOWANCE])) self.clashDef.setvalue(str(defaults[CLASH_THRESHOLD])) self._checkContinuous() def _clearHandlers(self): while self._handlers: trigName, handler = self._handlers.popitem() chimera.triggers.deleteHandler(trigName, handler) def _contactDefaultsCB(self): self.hbondAllow.setvalue("0.0") self.clashDef.setvalue("-0.4") self._checkContinuous() def _desigCB(self): self.designated.clear() self.designated.add(chimera.selection.currentAtoms()) self._updateDesigStatus() def _desig2CB(self): self.designated2.clear() self.designated2.add(chimera.selection.currentAtoms()) self._locButtonCB() self._updateDesig2Status() def _freqChangeCB(self, freqVal): self._clearHandlers() if freqVal == self.FREQ_APPLY: self.assignAttrButton.configure(state='normal') self.writeInfoButton.configure(state='normal') self.logInfoButton.configure(state='normal') return self.assignAttrButton.configure(state='disabled') self.writeInfoButton.configure(state='disabled') self.logInfoButton.configure(state='disabled') def modCoordSets(trigName, myData, changes): if changes.modified: self.Apply() self._handlers['CoordSet'] = chimera.triggers.addHandler( 'CoordSet', modCoordSets, None) def justCoordSets(trigName, myData, changes): if 'activeCoordSet changed' in changes.reasons: self.Apply() self._handlers['Molecule'] = chimera.triggers.addHandler( 'Molecule', justCoordSets, None) if freqVal == self.FREQ_MOTION: self._handlers[chimera.MOTION_STOP] = chimera.triggers\ .addHandler(chimera.MOTION_STOP, self._motionCB, None) elif freqVal == self.FREQ_CONTINUOUS: def preCB(trigName, myData, changes): if 'transformation change' in changes.reasons: self._motionCB() self._handlers['OpenState'] = chimera.triggers\ .addHandler('OpenState', preCB, None) self.Apply() def _locButtonCB(self, butName=None): checkSetBut = self.checkLocButtons.button(self.CHECK_SET) if self.checkLocButtons.getvalue() == self.CHECK_SET \ and not self.designated2.atoms(): checkSetBut.config(fg="red", activeforeground="red") else: checkSetBut.config(fg="black", activeforeground="black") self._updateDesig2Status() def _motionCB(self, *args): # if all molecule activities are the same (i.e. no possible # relative motion), do nothing activity = None for m in chimera.openModels.list(modelTypes=[chimera.Molecule]): if activity is None: activity = m.openState.active elif activity != m.openState.active: self.Apply() return def _updateDesigStatus(self): numAtoms = len(self.designated.atoms()) if numAtoms: statusText = "%d atoms designated" % numAtoms color = 'blue' else: statusText = "No atoms designated" color = 'red' self.freqButtons.invoke(self.FREQ_APPLY) self.desigStatus.config(text=statusText, fg=color) self._checkContinuous() def _updateDesig2Status(self): numAtoms = len(self.designated2.atoms()) checkSet = self.checkLocButtons.getvalue() == self.CHECK_SET color = 'black' if numAtoms: statusText = "Second set: %d atoms" % numAtoms else: statusText = "No second set" if checkSet: color = 'red' self.freqButtons.invoke(self.FREQ_APPLY) self.desig2Status.config(text=statusText, fg=color) if checkSet: self._checkContinuous()
def fillInUI(self, parent): import Pmw, Tkinter self.buttonWidgets['OK']['state'] = 'disabled' self.buttonWidgets['Apply']['state'] = 'disabled' from chimera.widgets import ModelScrolledListBox self.surfListBox = ModelScrolledListBox(parent, labelpos='n', label_text='Surfaces to color by ESP:', listbox_selectmode="extended", filtFunc=lambda m: isinstance(m, chimera.MSMSModel), selectioncommand=self._selSurfCB) self.surfListBox.grid(row=0, column=0, sticky="nsew", columnspan=2) Pmw.OptionMenu(parent, command=self._menuCB, initialitem="3", items=[str(x) for x in range(2, 12)], labelpos='w', label_text="Number of colors/values:").grid(row=1, column=0, columnspan=2) f = self.interpFrame = Tkinter.Frame(parent) f.grid(row=2, column=0, columnspan=2) self.wells = [] self.values = [] self._entryOpts = { 'validate': 'real', 'entry_justify': 'center', 'entry_width': 6 } from CGLtk.color.ColorWell import ColorWell for color, value in [("red", -10), ("white", 0), ("blue", 10)]: well = ColorWell(f, color=color) well.grid(row=0, column=len(self.wells)) self.wells.append(well) entry = Pmw.EntryField(f, value=str(value), **self._entryOpts) entry.grid(row=1, column=len(self.values)) self.values.append(entry) from chimera.tkoptions import FloatOption, BooleanOption self.distDep = BooleanOption(parent, 3, "Distance-dependent dielectric", True, None, balloon= "If true, charge falls off with distance squared to\n" "simulate solvent screening effects") self.dielectric = FloatOption(parent, 4, "Dielectric constant", 4.0, None) self.surfDist = FloatOption(parent, 5, "Distance from surface", 1.4, None, balloon="Potential at this distance from\n" "the surface is used for coloring") self.hisGroup = Pmw.Group(parent, hull_padx=2, tag_text="Implicit Histidine Protonation") self.hisGroup.grid(row=6, column=0, columnspan=2, sticky="nsew") self.hisProtVar = Tkinter.StringVar(parent) self.hisProtVar.set("name") interior = self.hisGroup.interior() interior.columnconfigure(0, weight=1) lab = Tkinter.Label(interior, text="Assumed histidine " "protonation for\nstructures without explicit hydrogens") from tkFont import Font font = Font(font=lab.cget('font')) font.config(size=int(0.75 * float(font.cget('size'))), slant='italic') lab.config(font=font) lab.grid(row=0) Tkinter.Radiobutton(interior, variable=self.hisProtVar, value="name", text="Residue name-based", command= self._switchHisList).grid(row=1, sticky='w') f = Tkinter.Frame(interior) f.grid(row=2) Tkinter.Label(f, text="HID/HIE/HIP = delta/epsilon/both").grid( row=0, sticky='w') self.hisDefault = Pmw.OptionMenu(f, initialitem=self.HB, items=[self.HB, "delta", "epsilon", "both"], labelpos='w', label_text="HIS = ", command=lambda a, s=self: setattr(s, 'hisChanged', True)) self.hisDefault.grid(row=1, sticky='w') self._pickText = Tkinter.StringVar(parent) self._pickText.set("Specified individually...") Tkinter.Radiobutton(interior, variable=self.hisProtVar, value="pick", textvariable=self._pickText, command=self._switchHisList).grid(row=3, sticky='w') Tkinter.Button(parent, pady=0, command=self._colorKeyCB, text="Create corresponding color key").grid(row=7, column=0, columnspan=2) self.hisChanged = False
class HbondDialog(ModelessDialog): title = "Hydrogen Bond Params" buttons = ("OK", "Apply", "Close") help = "ContributedSoftware/rotamers/rotamers.html#hbonds" def __init__(self, rotDialog): self.rotDialog = rotDialog ModelessDialog.__init__(self) def fillInUI(self, parent): import Tkinter, Pmw row = 0 f = Tkinter.Frame(parent) f.grid(row=row, column=0) self.drawHbondsVar = Tkinter.IntVar(parent) self.drawHbondsVar.set(prefs[DRAW_HBONDS]) Tkinter.Checkbutton(f, text="Draw H-bonds of color", variable=self.drawHbondsVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.hbColorWell = ColorWell(f, noneOkay=False, color=prefs[HBOND_COLOR]) self.hbColorWell.grid(row=0, column=1) self.hbWidthEntry = Pmw.EntryField(f, labelpos='w', label_text=" and width", validate={'validator': 'real', 'min': 0.01}, entry_width=4, entry_justify="center", value=str(prefs[HBOND_WIDTH])) self.hbWidthEntry.grid(row=0, column=2) row += 1 from FindHBond.gui import RelaxParams self.relaxParams = RelaxParams(parent, prefs[RELAX_COLOR]) self.relaxParams.grid(row=row, column=0) row += 1 self.ignoreOthersVar = Tkinter.IntVar(parent) self.ignoreOthersVar.set(prefs[HBOND_IGNORE_OTHERS]) Tkinter.Checkbutton(parent, text="Ignore H-bonds with other" " models", variable=self.ignoreOthersVar).grid(row=row, column=0, sticky='w') row += 1 def Apply(self): dhb = self.drawHbondsVar.get() prefs[DRAW_HBONDS] = dhb prefs[HBOND_COLOR] = self.hbColorWell.rgba bc = chimera.MaterialColor(*prefs[HBOND_COLOR]) self.hbWidthEntry.invoke() if not self.hbWidthEntry.valid(): self.enter() raise UserError("Invalid H-bond width") lw = prefs[HBOND_WIDTH] = float(self.hbWidthEntry.getvalue()) distSlop = 0.0 angleSlop = 0.0 twoColors = False relax = self.relaxParams.relaxConstraints rc = self.relaxParams.relaxColor if relax: distSlop = self.relaxParams.relaxDist angleSlop = self.relaxParams.relaxAngle if self.relaxParams.useRelaxColor: twoColors = True prefs[RELAX_COLOR] = rc.rgba() self.groupName = "H-bonds for rotamers of %s" % ( self.rotDialog.residue) prefs[HBOND_IGNORE_OTHERS] = self.ignoreOthersVar.get() self.rotDialog.addHbondColumn(dhb, bc, lw, relax, distSlop, angleSlop, twoColors, rc, self.groupName, prefs[HBOND_IGNORE_OTHERS]) def destroy(self): self.rotDialog = None if hasattr(self, 'groupName'): from Rotamers import nukeGroup nukeGroup(self.groupName) ModelessDialog.destroy(self)
class ClashDialog(ModelessDialog): title = "Rotamer Clash Params" buttons = ("OK", "Apply", "Close") help = "ContributedSoftware/rotamers/rotamers.html#clashes" def __init__(self, rotDialog): self.rotDialog = rotDialog ModelessDialog.__init__(self) def fillInUI(self, parent): row = 0 from DetectClash.gui import ClashDef, HbondAllow self.clashDef = ClashDef(parent, value=prefs[CLASH_THRESHOLD]) self.clashDef.grid(row=row, column=0, sticky='w') row += 1 self.hbondAllow = HbondAllow(parent, value=prefs[HBOND_ALLOWANCE]) self.hbondAllow.grid(row=row, column=0, sticky='w') row += 1 import Pmw, Tkinter Tkinter.Button(parent, text="Default criteria", pady=0, command=self._revertDefaults).grid(row=row) row += 1 self.computeType = Pmw.RadioSelect(parent, pady=0, buttontype='radiobutton', labelpos='w', label_text="Column Value:", orient='vertical', frame_borderwidth=2, frame_relief="ridge") self.buttonInfo= [ ("Number of clashes", "num"), ("Sum of overlaps", "sum"), ] for label, short in self.buttonInfo: self.computeType.add(label) if prefs[CLASH_METHOD] == short: default = label self.computeType.invoke(default) self.computeType.grid(row=row, column=0) row += 1 f = Tkinter.Frame(parent) f.grid(row=row, column=0, sticky='w') self.pbVar = Tkinter.IntVar(parent) self.pbVar.set(prefs[CLASH_PBS]) Tkinter.Checkbutton(f, text="Draw pseudobonds of color", variable=self.pbVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.pbColorWell = ColorWell(f, noneOkay=False, color=prefs[CLASH_COLOR]) self.pbColorWell.grid(row=0, column=1) self.pbWidthEntry = Pmw.EntryField(f, labelpos='w', label_text=" and width", validate={'validator': 'real', 'min': 0.01}, entry_width=4, entry_justify="center", value=str(prefs[CLASH_WIDTH])) self.pbWidthEntry.grid(row=0, column=2) row += 1 self.ignoreOthersVar = Tkinter.IntVar(parent) self.ignoreOthersVar.set(prefs[CLASH_IGNORE_OTHERS]) Tkinter.Checkbutton(parent, text="Ignore clashes with other" " models", variable=self.ignoreOthersVar).grid(row=row, column=0, sticky='w') row += 1 def Apply(self): from chimera import UserError self.clashDef.invoke() if not self.clashDef.valid(): self.enter() raise UserError("Invalid clash amount") prefs[CLASH_THRESHOLD] = float(self.clashDef.getvalue()) self.hbondAllow.invoke() if not self.hbondAllow.valid(): self.enter() raise UserError("Invalid H-bond overlap amount") prefs[HBOND_ALLOWANCE] = float(self.hbondAllow.getvalue()) prefs[CLASH_PBS] = self.pbVar.get() if prefs[CLASH_PBS]: prefs[CLASH_COLOR] = self.pbColorWell.rgba pbColor = chimera.MaterialColor(*prefs[CLASH_COLOR]) self.pbWidthEntry.invoke() if not self.pbWidthEntry.valid(): self.enter() raise UserError("Invalid pseudobond width") prefs[CLASH_WIDTH] = float(self.pbWidthEntry.getvalue()) else: pbColor = None prefs[CLASH_METHOD] = self.buttonInfo[self.computeType.index( self.computeType.getvalue())][1] prefs[CLASH_IGNORE_OTHERS] = self.ignoreOthersVar.get() self.rotDialog.addClashColumn(prefs[CLASH_THRESHOLD], prefs[HBOND_ALLOWANCE], prefs[CLASH_METHOD], prefs[CLASH_PBS], pbColor, prefs[CLASH_WIDTH], prefs[CLASH_IGNORE_OTHERS]) def destroy(self): self.rotDialog = None if prefs[CLASH_PBS]: from DetectClash import nukeGroup nukeGroup() ModelessDialog.destroy(self) def _revertDefaults(self): from prefs import defaults self.clashDef.setvalue(str(defaults[CLASH_THRESHOLD])) self.hbondAllow.setvalue(str(defaults[HBOND_ALLOWANCE]))
class ClashDialog(ModelessDialog): title = "Rotamer Clash Params" buttons = ("OK", "Apply", "Close") help = "ContributedSoftware/rotamers/rotamers.html#clashes" def __init__(self, rotDialog): self.rotDialog = rotDialog ModelessDialog.__init__(self) def fillInUI(self, parent): row = 0 from DetectClash.gui import ClashDef, HbondAllow self.clashDef = ClashDef(parent, value=prefs[CLASH_THRESHOLD]) self.clashDef.grid(row=row, column=0, sticky='w') row += 1 self.hbondAllow = HbondAllow(parent, value=prefs[HBOND_ALLOWANCE]) self.hbondAllow.grid(row=row, column=0, sticky='w') row += 1 import Pmw, Tkinter Tkinter.Button(parent, text="Default criteria", pady=0, command=self._revertDefaults).grid(row=row) row += 1 self.computeType = Pmw.RadioSelect(parent, pady=0, buttontype='radiobutton', labelpos='w', label_text="Column Value:", orient='vertical', frame_borderwidth=2, frame_relief="ridge") self.buttonInfo = [ ("Number of clashes", "num"), ("Sum of overlaps", "sum"), ] for label, short in self.buttonInfo: self.computeType.add(label) if prefs[CLASH_METHOD] == short: default = label self.computeType.invoke(default) self.computeType.grid(row=row, column=0) row += 1 f = Tkinter.Frame(parent) f.grid(row=row, column=0, sticky='w') self.pbVar = Tkinter.IntVar(parent) self.pbVar.set(prefs[CLASH_PBS]) Tkinter.Checkbutton(f, text="Draw pseudobonds of color", variable=self.pbVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.pbColorWell = ColorWell(f, noneOkay=False, color=prefs[CLASH_COLOR]) self.pbColorWell.grid(row=0, column=1) self.pbWidthEntry = Pmw.EntryField(f, labelpos='w', label_text=" and width", validate={ 'validator': 'real', 'min': 0.01 }, entry_width=4, entry_justify="center", value=str(prefs[CLASH_WIDTH])) self.pbWidthEntry.grid(row=0, column=2) row += 1 self.ignoreOthersVar = Tkinter.IntVar(parent) self.ignoreOthersVar.set(prefs[CLASH_IGNORE_OTHERS]) Tkinter.Checkbutton(parent, text="Ignore clashes with other" " models", variable=self.ignoreOthersVar).grid(row=row, column=0, sticky='w') row += 1 def Apply(self): from chimera import UserError self.clashDef.invoke() if not self.clashDef.valid(): self.enter() raise UserError("Invalid clash amount") prefs[CLASH_THRESHOLD] = float(self.clashDef.getvalue()) self.hbondAllow.invoke() if not self.hbondAllow.valid(): self.enter() raise UserError("Invalid H-bond overlap amount") prefs[HBOND_ALLOWANCE] = float(self.hbondAllow.getvalue()) prefs[CLASH_PBS] = self.pbVar.get() if prefs[CLASH_PBS]: prefs[CLASH_COLOR] = self.pbColorWell.rgba pbColor = chimera.MaterialColor(*prefs[CLASH_COLOR]) self.pbWidthEntry.invoke() if not self.pbWidthEntry.valid(): self.enter() raise UserError("Invalid pseudobond width") prefs[CLASH_WIDTH] = float(self.pbWidthEntry.getvalue()) else: pbColor = None prefs[CLASH_METHOD] = self.buttonInfo[self.computeType.index( self.computeType.getvalue())][1] prefs[CLASH_IGNORE_OTHERS] = self.ignoreOthersVar.get() self.rotDialog.addClashColumn(prefs[CLASH_THRESHOLD], prefs[HBOND_ALLOWANCE], prefs[CLASH_METHOD], prefs[CLASH_PBS], pbColor, prefs[CLASH_WIDTH], prefs[CLASH_IGNORE_OTHERS]) def destroy(self): self.rotDialog = None if prefs[CLASH_PBS]: from DetectClash import nukeGroup nukeGroup() ModelessDialog.destroy(self) def _revertDefaults(self): from prefs import defaults self.clashDef.setvalue(str(defaults[CLASH_THRESHOLD])) self.hbondAllow.setvalue(str(defaults[HBOND_ALLOWANCE]))
class HbondDialog(ModelessDialog): title = "Hydrogen Bond Params" buttons = ("OK", "Apply", "Close") help = "ContributedSoftware/rotamers/rotamers.html#hbonds" def __init__(self, rotDialog): self.rotDialog = rotDialog ModelessDialog.__init__(self) def fillInUI(self, parent): import Tkinter, Pmw row = 0 f = Tkinter.Frame(parent) f.grid(row=row, column=0) self.drawHbondsVar = Tkinter.IntVar(parent) self.drawHbondsVar.set(prefs[DRAW_HBONDS]) Tkinter.Checkbutton(f, text="Draw H-bonds of color", variable=self.drawHbondsVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.hbColorWell = ColorWell(f, noneOkay=False, color=prefs[HBOND_COLOR]) self.hbColorWell.grid(row=0, column=1) self.hbWidthEntry = Pmw.EntryField(f, labelpos='w', label_text=" and width", validate={ 'validator': 'real', 'min': 0.01 }, entry_width=4, entry_justify="center", value=str(prefs[HBOND_WIDTH])) self.hbWidthEntry.grid(row=0, column=2) row += 1 from FindHBond.gui import RelaxParams self.relaxParams = RelaxParams(parent, prefs[RELAX_COLOR]) self.relaxParams.grid(row=row, column=0) row += 1 self.ignoreOthersVar = Tkinter.IntVar(parent) self.ignoreOthersVar.set(prefs[HBOND_IGNORE_OTHERS]) Tkinter.Checkbutton(parent, text="Ignore H-bonds with other" " models", variable=self.ignoreOthersVar).grid(row=row, column=0, sticky='w') row += 1 def Apply(self): dhb = self.drawHbondsVar.get() prefs[DRAW_HBONDS] = dhb prefs[HBOND_COLOR] = self.hbColorWell.rgba bc = chimera.MaterialColor(*prefs[HBOND_COLOR]) self.hbWidthEntry.invoke() if not self.hbWidthEntry.valid(): self.enter() raise UserError("Invalid H-bond width") lw = prefs[HBOND_WIDTH] = float(self.hbWidthEntry.getvalue()) distSlop = 0.0 angleSlop = 0.0 twoColors = False relax = self.relaxParams.relaxConstraints rc = self.relaxParams.relaxColor if relax: distSlop = self.relaxParams.relaxDist angleSlop = self.relaxParams.relaxAngle if self.relaxParams.useRelaxColor: twoColors = True prefs[RELAX_COLOR] = rc.rgba() self.groupName = "H-bonds for rotamers of %s" % ( self.rotDialog.residue) prefs[HBOND_IGNORE_OTHERS] = self.ignoreOthersVar.get() self.rotDialog.addHbondColumn(dhb, bc, lw, relax, distSlop, angleSlop, twoColors, rc, self.groupName, prefs[HBOND_IGNORE_OTHERS]) def destroy(self): self.rotDialog = None if hasattr(self, 'groupName'): from Rotamers import nukeGroup nukeGroup(self.groupName) ModelessDialog.destroy(self)
class DetectClashDialog(ModelessDialog): name = "detect clashes" title = "Find Clashes/Contacts" provideStatus = True statusPosition = "above" help = "ContributedSoftware/findclash/findclash.html" FREQ_APPLY = "when OK/Apply clicked" FREQ_MOTION = "after relative motions (until dialog closed)" FREQ_CONTINUOUS = "continuously (until dialog closed)" CHECK_SET = "second set of designated atoms" def fillInUI(self, parent): self._handlers = {} desigGroup = Pmw.Group(parent, tag_text="Atoms to Check", hull_padx=2) desigGroup.grid(row=0, sticky="ew") from chimera.tkgui import windowSystem Tkinter.Button(desigGroup.interior(), command=self._desigCB, text="Designate").grid(row=0, column=0, sticky='e') Tkinter.Label(desigGroup.interior(), text="currently selected" " atoms for checking").grid(row=0, column=1, sticky='w') self.desigStatus = Tkinter.Label(desigGroup.interior()) from tkFont import Font font = Font(font=self.desigStatus.cget('font')) size = int(font.cget('size')) if size > 2: font.config(size=size-2) font.config(weight='normal') self.desigStatus.config(font=font) from chimera.selection import ItemizedSelection self.designated = ItemizedSelection( selChangedCB=self._updateDesigStatus) self.desigStatus.grid(row=1, column=0, columnspan=2) self.designated2 = ItemizedSelection(selChangedCB=self._locButtonCB) if windowSystem == 'aqua': pady = None else: pady = 0 Tkinter.Button(desigGroup.interior(), command=self._desig2CB, pady=pady, text="Designate selection as second set" ).grid(row=3, column=1) self.desig2Status = Tkinter.Label(desigGroup.interior()) if size > 4: font2 = Font(font=font) font2.config(size=size-4) else: font2 = font self.desig2Status.config(font=font2) self.desig2Status.grid(row=4, column=1) self.checkLocButtons = Pmw.RadioSelect(desigGroup.interior(), pady=0, orient='vertical', buttontype='radiobutton', labelpos='w', label_text="Check designated\natoms" " against:", command=self._locButtonCB) self.checkLocButtons.grid(row=2, column=0, columnspan=2) self.checkLocButtons.add("themselves") self.checkLocButtons.add("all other atoms") self.checkLocButtons.add("other atoms in same model") self.checkLocButtons.add(self.CHECK_SET) self.checkLocButtons.invoke(1) defGroup = Pmw.Group(parent, tag_text="Clash/Contact Parameters", hull_padx=2) defGroup.grid(row=1, sticky='ew') self.clashDef = ClashDef(defGroup.interior(), command=self._checkContinuous, value=str(prefs[CLASH_THRESHOLD])) self.clashDef.grid(row=0, sticky='w') self.hbondAllow = HbondAllow(defGroup.interior(), command=self._checkContinuous, value=str(prefs[HBOND_ALLOWANCE])) self.hbondAllow.grid(row=1, sticky='w') defaultsFrame = Tkinter.Frame(defGroup.interior()) defaultsFrame.grid(row=2) Tkinter.Label(defaultsFrame, text="Default").grid( row=0, column=0) Tkinter.Button(defaultsFrame, text="clash", pady=pady, command=self._clashDefaultsCB).grid(row=0, column=1) Tkinter.Label(defaultsFrame, text="/").grid(row=0, column=2) Tkinter.Button(defaultsFrame, text="contact", pady=pady, command=self._contactDefaultsCB).grid(row=0, column=3) Tkinter.Label(defaultsFrame, text="criteria").grid( row=0, column=4) bondsFrame = Tkinter.Frame(defGroup.interior()) bondsFrame.grid(row=3, sticky='w') self.bondsApart = Pmw.OptionMenu(bondsFrame, labelpos='w', label_text="Ignore contacts of pairs", command=self._checkContinuous, initialitem=str(prefs[BOND_SEPARATION]), items=[str(i+2) for i in range(4)]) self.bondsApart.grid(row=0, column=0) Tkinter.Label(bondsFrame, text="or fewer bonds apart").grid( row=0, column=1) self.ignoreIntraResVar = Tkinter.IntVar(parent) self.ignoreIntraResVar.set(prefs[IGNORE_INTRA_RES]) Tkinter.Checkbutton(defGroup.interior(), text="Ignore intra-" "residue contacts", variable=self.ignoreIntraResVar, command=self._checkContinuous ).grid(row=4) actionGroup = Pmw.Group(parent, tag_text= "Treatment of Clash/Contact Atoms", hull_padx=2) actionGroup.grid(row=2, sticky='ew') self.actionSelVar = Tkinter.IntVar(parent) self.actionSelVar.set(prefs[ACTION_SELECT]) Tkinter.Checkbutton(actionGroup.interior(), text="Select", command=self._checkContinuous, variable=self.actionSelVar).grid(row=0, sticky='w') self.actionColorVar = Tkinter.IntVar(parent) self.actionColorVar.set(prefs[ACTION_COLOR]) f = Tkinter.Frame(actionGroup.interior()) f.grid(row=1, sticky='w') Tkinter.Checkbutton(f, text="Color", command=self._checkContinuous, variable=self.actionColorVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.clashColorWell = ColorWell(f, noneOkay=True, callback=self._checkContinuous, color=prefs[CLASH_COLOR]) self.clashColorWell.grid(row=0, column=1) Tkinter.Label(f, text=" (and color all other atoms").grid(row=0, column=2) self.nonclashColorWell = ColorWell(f, noneOkay=True, callback=self._checkContinuous, color=prefs[NONCLASH_COLOR]) self.nonclashColorWell.grid(row=0, column=3) Tkinter.Label(f, text=")").grid(row=0, column=4) self.actionPBVar = Tkinter.IntVar(parent) self.actionPBVar.set(prefs[ACTION_PSEUDOBONDS]) f = Tkinter.Frame(actionGroup.interior()) f.grid(row=2, sticky='w') Tkinter.Checkbutton(f, text="Draw pseudobonds of color", command=self._checkContinuous, variable=self.actionPBVar).grid(row=0, column=0) from CGLtk.color.ColorWell import ColorWell self.pbColorWell = ColorWell(f, noneOkay=False, callback=self._checkContinuous, color=prefs[PB_COLOR]) self.pbColorWell.grid(row=0, column=1) self.pbWidthEntry = Pmw.EntryField(f, labelpos='w', label_text=" and width", validate={'validator': 'real', 'min': 0.01}, entry_width=4, entry_justify="center", command=self._checkContinuous, value=str(prefs[PB_WIDTH])) self.pbWidthEntry.grid(row=0, column=2) self.actionAttrVar = Tkinter.IntVar(parent) self.actionAttrVar.set(prefs[ACTION_ATTR]) self.assignAttrButton = Tkinter.Checkbutton( actionGroup.interior(), text="Assign 'overlap' attribute", variable=self.actionAttrVar) self.assignAttrButton.grid(row=3, sticky='w') self.actionWriteInfoVar = Tkinter.IntVar(parent) self.actionWriteInfoVar.set(prefs[ACTION_WRITEINFO]) self.writeInfoButton = Tkinter.Checkbutton( actionGroup.interior(), text="Write information to" " file", variable=self.actionWriteInfoVar) self.writeInfoButton.grid(row=4, sticky='w') self.actionLogInfoVar = Tkinter.IntVar(parent) self.actionLogInfoVar.set(prefs[ACTION_REPLYLOG]) self.logInfoButton = Tkinter.Checkbutton( actionGroup.interior(), text="Write information to" " reply log", variable=self.actionLogInfoVar) self.logInfoButton.grid(row=5, sticky='w') freqGroup = Pmw.Group(parent, tag_text="Frequency of Checking", hull_padx=2) freqGroup.grid(row=3, sticky="ew") self.freqButtons = Pmw.RadioSelect(freqGroup.interior(), pady=0, orient='vertical', buttontype='radiobutton', labelpos='w', label_text= "Check...", command=self._freqChangeCB) self.freqButtons.grid(sticky='w') self.freqButtons.add(self.FREQ_APPLY) self.freqButtons.add(self.FREQ_MOTION) self.freqButtons.add(self.FREQ_CONTINUOUS) self.freqButtons.invoke(0) self._updateDesigStatus() def OK(self, *args): # use main status line if dialog closing from chimera.replyobj import status self.status = status ModelessDialog.OK(self, *args) def Apply(self, *args): # workaround: remove pseudobonds before recreating colors # so C++ layer doesn't end up with pointers to deleted # colors in obscure circumstances from DetectClash import nukeGroup nukeGroup() from chimera import UserError self.status("") checkAtoms = self.designated.atoms() if not checkAtoms: self.enter() raise UserError("No atoms designated for clash detection") self.clashDef['command'] = None self.clashDef.invoke() self.clashDef['command'] = self._checkContinuous if not self.clashDef.valid(): self.enter() raise UserError("Invalid clash amount" " (in Clash/Contact Parameters)") prefs[CLASH_THRESHOLD] = float(self.clashDef.getvalue()) self.hbondAllow['command'] = None self.hbondAllow.invoke() self.hbondAllow['command'] = self._checkContinuous if not self.hbondAllow.valid(): self.enter() raise UserError("Invalid H-bond overlap amount" " (in Clash/Contact Parameters)") prefs[HBOND_ALLOWANCE] = float(self.hbondAllow.getvalue()) prefs[BOND_SEPARATION] = int(self.bondsApart.getvalue()) prefs[IGNORE_INTRA_RES] = self.ignoreIntraResVar.get() checkVal = self.checkLocButtons.getvalue() if checkVal == "themselves": test = "self" elif checkVal == "all other atoms": test = "others" elif checkVal == "other atoms in same model": test = "model" else: test = self.designated2.atoms() if not test: self.enter() raise UserError("No second-set atoms designated") actionAttr = prefs[ACTION_ATTR] = self.actionAttrVar.get() actionSelect = prefs[ACTION_SELECT] = self.actionSelVar.get() actionColor = prefs[ACTION_COLOR] = self.actionColorVar.get() actionPseudobonds = prefs[ACTION_PSEUDOBONDS] = \ self.actionPBVar.get() actionWriteInfo = prefs[ACTION_WRITEINFO] = \ self.actionWriteInfoVar.get() actionLogInfo = prefs[ACTION_REPLYLOG] = \ self.actionLogInfoVar.get() if self.freqButtons.getvalue() != self.FREQ_APPLY: actionAttr = actionWriteInfo = actionLogInfo = False if not actionAttr and not actionSelect and not actionColor \ and not actionPseudobonds and not actionWriteInfo \ and not actionLogInfo: self.enter() raise UserError("No actions selected for clashes") self.status("Checking for clashes") clashColor = nonclashColor = None if actionColor: prefs[CLASH_COLOR] = self.clashColorWell.rgba prefs[NONCLASH_COLOR] = self.nonclashColorWell.rgba if prefs[CLASH_COLOR] == None: clashColor = None else: clashColor = chimera.MaterialColor( *prefs[CLASH_COLOR]) if prefs[NONCLASH_COLOR] == None: nonclashColor = None else: nonclashColor = chimera.MaterialColor( *prefs[NONCLASH_COLOR]) pbColor = None if actionPseudobonds: prefs[PB_COLOR] = self.pbColorWell.rgba pbColor = chimera.MaterialColor(*prefs[PB_COLOR]) self.pbWidthEntry['command'] = None self.pbWidthEntry.invoke() self.pbWidthEntry['command'] = self._checkContinuous if not self.pbWidthEntry.valid(): self.enter() raise UserError("Invalid pseudobond width " "(in Treatment of Clash/Contact Atoms)") prefs[PB_WIDTH] = float(self.pbWidthEntry.getvalue()) from DetectClash import cmdDetectClash if actionWriteInfo: saveFile = "-" else: saveFile = None clashes = cmdDetectClash(checkAtoms, test=test, overlapCutoff=prefs[CLASH_THRESHOLD], hbondAllowance=prefs[HBOND_ALLOWANCE], bondSeparation=prefs[BOND_SEPARATION], ignoreIntraRes=prefs[IGNORE_INTRA_RES], setAttrs=actionAttr, selectClashes=actionSelect, colorClashes=actionColor, clashColor=clashColor, nonclashColor=nonclashColor, makePseudobonds=actionPseudobonds, pbColor=pbColor, lineWidth=prefs[PB_WIDTH], saveFile=saveFile, log=actionLogInfo, summary=self.status) if actionAttr: from ShowAttr import ShowAttrDialog from chimera import dialogs from DetectClash import attrName d = dialogs.display(ShowAttrDialog.name) d.configure(attrsOf="atoms", attrName=attrName, mode="Render") def Close(self): ModelessDialog.Close(self) if self.freqButtons.getvalue() != self.FREQ_APPLY: self.freqButtons.invoke(self.FREQ_APPLY) def _checkContinuous(self, *args): if self.freqButtons.getvalue() == self.FREQ_CONTINUOUS: self.Apply() def _clashDefaultsCB(self): from prefs import defaults self.hbondAllow.setvalue(str(defaults[HBOND_ALLOWANCE])) self.clashDef.setvalue(str(defaults[CLASH_THRESHOLD])) self._checkContinuous() def _clearHandlers(self): while self._handlers: trigName, handler = self._handlers.popitem() chimera.triggers.deleteHandler(trigName, handler) def _contactDefaultsCB(self): self.hbondAllow.setvalue("0.0") self.clashDef.setvalue("-0.4") self._checkContinuous() def _desigCB(self): self.designated.clear() self.designated.add(chimera.selection.currentAtoms()) self._updateDesigStatus() def _desig2CB(self): self.designated2.clear() self.designated2.add(chimera.selection.currentAtoms()) self._locButtonCB() self._updateDesig2Status() def _freqChangeCB(self, freqVal): self._clearHandlers() if freqVal == self.FREQ_APPLY: self.assignAttrButton.configure(state='normal') self.writeInfoButton.configure(state='normal') self.logInfoButton.configure(state='normal') return self.assignAttrButton.configure(state='disabled') self.writeInfoButton.configure(state='disabled') self.logInfoButton.configure(state='disabled') def modCoordSets(trigName, myData, changes): if changes.modified: self.Apply() self._handlers['CoordSet'] = chimera.triggers.addHandler( 'CoordSet', modCoordSets, None) def justCoordSets(trigName, myData, changes): if 'activeCoordSet changed' in changes.reasons: self.Apply() self._handlers['Molecule'] = chimera.triggers.addHandler( 'Molecule', justCoordSets, None) if freqVal == self.FREQ_MOTION: self._handlers[chimera.MOTION_STOP] = chimera.triggers\ .addHandler(chimera.MOTION_STOP, self._motionCB, None) elif freqVal == self.FREQ_CONTINUOUS: def preCB(trigName, myData, changes): if 'transformation change' in changes.reasons: self._motionCB() self._handlers['OpenState'] = chimera.triggers\ .addHandler('OpenState', preCB, None) self.Apply() def _locButtonCB(self, butName=None): checkSetBut = self.checkLocButtons.button(self.CHECK_SET) if self.checkLocButtons.getvalue() == self.CHECK_SET \ and not self.designated2.atoms(): checkSetBut.config(fg="red", activeforeground="red") else: checkSetBut.config(fg="black", activeforeground="black") self._updateDesig2Status() def _motionCB(self, *args): # if all molecule activities are the same (i.e. no possible # relative motion), do nothing activity = None for m in chimera.openModels.list(modelTypes=[chimera.Molecule]): if activity is None: activity = m.openState.active elif activity != m.openState.active: self.Apply() return def _updateDesigStatus(self): numAtoms = len(self.designated.atoms()) if numAtoms: statusText = "%d atoms designated" % numAtoms color = 'blue' else: statusText = "No atoms designated" color = 'red' self.freqButtons.invoke(self.FREQ_APPLY) self.desigStatus.config(text=statusText, fg=color) self._checkContinuous() def _updateDesig2Status(self): numAtoms = len(self.designated2.atoms()) checkSet = self.checkLocButtons.getvalue() == self.CHECK_SET color = 'black' if numAtoms: statusText = "Second set: %d atoms" % numAtoms else: statusText = "No second set" if checkSet: color = 'red' self.freqButtons.invoke(self.FREQ_APPLY) self.desig2Status.config(text=statusText, fg=color) if checkSet: self._checkContinuous()