# --- UCSF Chimera Copyright ---
# Copyright (c) 2000 Regents of the University of California.
# All rights reserved.  This software provided pursuant to a
# license agreement containing restrictions on its disclosure,
# duplication and use.  This notice must be embedded in or
# attached to all copies, including partial copies, of the
# software or any revisions or derivations thereof.
# --- UCSF Chimera Copyright ---
#
# $Id: AngleCounter.py 26655 2009-01-07 22:02:30Z gregc $

"""Specialization of Pmw.Counter for angles"""

import Pmw
from CGLtk.AngleDial import AngleDial
import math

class AngleCounter(Pmw.MegaWidget):

	def __init__(self, parent = None, **kw):

		# Define the megawidget options
		optiondefs = (
			('angle',	0.0,	self._angleCB),
			('command',	None,	None),
			('dialpos',	'w',	Pmw.INITOPT),
			('labelmargin',	0,	Pmw.INITOPT),
			('labelpos',	None,	Pmw.INITOPT),
			('minangle',	-180.0,	Pmw.INITOPT),
		)
		self.defineoptions(kw, optiondefs)

		# Initialise base class (after defining options)
		Pmw.MegaWidget.__init__(self, parent)

		# Create the components
		interior = self.interior()

		# Create the dial component, maybe
		dialpos = self['dialpos']
		if dialpos is not None:
			self.dial = self.createcomponent('dial', (), None,
				AngleDial, (interior,),
				command=self._dialChange)
			if dialpos == 'w':
				dialRow, dialColumn = (2, 2)
				counterRow, counterColumn = (2, 3)
				childRows, childCols = (1, 2)
			elif dialpos == 'n':
				dialRow, dialColumn = (2, 2)
				counterRow, counterColumn = (3, 2)
				childRows, childCols = (2, 1)
			elif dialpos == 'e':
				dialRow, dialColumn = (2, 3)
				counterRow, counterColumn = (2, 2)
				childRows, childCols = (1, 2)
			else:
				dialRow, dialColumn = (3, 2)
				counterRow, counterColumn = (2, 2)
				childRows, childCols = (2, 1)
			self.dial.grid(row=dialRow, column=dialColumn, 
								sticky='nsew')
			interior.rowconfigure(dialRow, weight=1)
			interior.columnconfigure(dialColumn, weight=1)
		else:
			counterRow, counterColumn = (2, 2)
			childRows, childCols = (1, 1)
			interior.rowconfigure(2, weight=1)
			interior.columnconfigure(2, weight=1)
		
		# Create the counter component
		self.counter = self.createcomponent('counter', (), None,
			Pmw.Counter, (interior,), datatype=self._incrCounter,
			entryfield_command=self._counterChange, entry_width=8)
		if self.counter['orient'] == 'horizontal':
			sticky='ew'
		else:
			sticky='nsew'
		self.counter.grid(row=counterRow, column=counterColumn,
								sticky=sticky)
		
		# Optionally create the label component
		self.createlabel(interior, childRows=childRows,
							childCols=childCols)
		 
		# Check keywords and initialise options
		self.initialiseoptions(AngleCounter)
	
	def _angleCB(self):
		if hasattr(self, '_inAngleCB') and self._inAngleCB:
			return
		self._inAngleCB = 1
		self['angle'] = self.normalize(self['angle'])
		if self['dialpos'] is not None:
			self.dial.configure(angle=self['angle'])
		self.counter.setentry(str(self['angle']))
		self._inAngleCB = 0
	
	def _counterChange(self):
		"""callback from counter entryfield"""

		degrees = float(self.counter.component('entry').get())
		degrees = self.normalize(degrees)
		if self['dialpos'] is not None:
			# setting dial will result in callback to counter
			self.dial.configure(angle=degrees)
		else:
			self._mkCmdCB(degrees)

	def _dialChange(self, degrees):
		"""callback from dial"""

		degrees = self.normalize(degrees)
		self.counter.setentry(str(degrees))
		self._mkCmdCB(degrees)

	def _incrCounter(self, cur, upDown, incr, **kw):
		degrees = float(cur)
		if upDown > 0:
			degrees = degrees + incr
		else:
			degrees = degrees - incr
		if incr >= 1.0:
			degrees = math.floor(degrees + 0.5)
		degrees = self.normalize(degrees)
		if self['dialpos'] is not None:
			self.dial.configure(angle=degrees)
		else:
			self._mkCmdCB(degrees)
		return str(degrees)

	def _mkCmdCB(self, degrees):
		if self['command']:
			if not hasattr(self, '_inAngleCB') \
			or not self._inAngleCB:
				self['command'](degrees)
	
	def normalize(self, degrees):
		"""return angle given constraint of self['minangle']"""

		if self['minangle'] is None:
			return degrees
		
		minangle = self['minangle']
		while degrees < minangle:
			degrees = degrees + 360
		while degrees >= minangle + 360:
			degrees = degrees - 360
		return degrees

Pmw.forwardmethods(AngleCounter, Pmw.Counter, 'counter')