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)
Exemple #3
0
	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)
Exemple #4
0
 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()
Exemple #5
0
	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()
Exemple #6
0
	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)
Exemple #7
0
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
Exemple #9
0
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()
Exemple #10
0
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()
Exemple #12
0
	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]))
Exemple #15
0
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)
Exemple #17
0
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()