"""
I needed a simple guage, so I've made on with Pmw.
It might be useful for others to use as a base to develop more comples
guages with.
 
Is it worth cleaning up and submitting?
 
cheers and thanks
 
chris
 
Dr. Chris Wright
Intensive Care Unit
Monash Medical Centre
Clayton. VIC Australia
"""

import sys
import Tkinter
import Pmw
import time


if sys.platform == 'win32':
    # MS-Windows specific fonts
    label_font = "-family Ariel  -size 12"
    value_font = "-family Ariel  -size 12"
    small_font = "-family {MS Sans Serif} -size 9 -weight bold"
    header_font = "-family {MS Sans Serif} -weight bold"
else:
    # X-Windows specific fonts
    label_font = "-*-helvetica-*-r-*-*-*-160-*-*-*-*-*-*"
    value_font = "-*-courier-*-r-*-*-*-160-*-*-*-*-*-*"
    small_font = "-*-helvetica-*-r-*-*-*-130-*-*-*-*-*-*"
    header_font = "-*-helvetica-bold-r-*-*-*-150-*-*-*-*-*-*"

class VerticalGuage(Pmw.MegaWidget):
    """Vertical guage with actual and desired settings"""

    def __init__(self, parent = None, **kw):
	optiondefs = (
	    ('min', 0, None),
	    ('max', 100, None),
	    ('majortickinterval', 10, None),
	    ('minortickinterval', 5, None),
	    ('units', '', None),
	    ('bg', 'grey', self._backgroundSet),
	    ('actualvalue', 50, self._actualSet),
	    ('desiredvalue', 50, self._desiredSet),
	    ('actualcolour', 'yellow1', None),
	    ('desiredcolour', 'turquoise1', None),
	    ('label', 'Label', None),
	    )
	self.defineoptions(kw, optiondefs)
	Pmw.MegaWidget.__init__(self, parent)

	interior = self.interior()
	interior.grid_rowconfigure(1, weight = 1)
	for r in range(3):
	    interior.grid_columnconfigure(r, weight = 1)

	self.actuallabel = self.createcomponent('actualLabel',
						(), None,
						Tkinter.Label, (interior,),
						text = '',
						width = 3,
						relief = 'sunken',
						bd = 1,
						fg = self['actualcolour'],
						font = value_font)
	self.actuallabel.grid(sticky = "nswe", row = 0, column = 0)

	self.label = self.createcomponent('label',
					  (), None,
					  Tkinter.Label, (interior,),
					  text = self['label'],
					  relief = 'raised',
					  font = label_font,
					  fg = 'navy',
					  bd = 2)
	self.label.grid(sticky = "nsew", row = 0, column = 1)

	self.desiredlabel = self.createcomponent('desiredLabel',
						 (), None,
						 Tkinter.Label, (interior,),
						 text = '',
						 width = 3,
						 relief = 'sunken',
						 bd = 1,
						 fg = self['desiredcolour'],
						 font = value_font)
	self.desiredlabel.grid(sticky = "nswe", row = 0, column = 2)

	self.canvas = self.createcomponent('canvas',
					   (), None,
					   Tkinter.Canvas, (interior,),
					   width = 100,
					   height = 300,
					   bg = 'grey')
			
	self.canvas.grid(sticky = "nsew", columnspan = 3, pady = 1)
	self.canvas.bind("<Configure>", self._createGuageAxes)
	
	self._createGuageAxes()
	
	self.initialiseoptions(VerticalGuage)
    
    def _createGuageAxes(self, event = None):
	min = self['min']
	max = self['max']
	units = self['units']
	majortickinterval = self['majortickinterval']

	guage_range = max - min

	c = self.canvas
	c.delete("all")
	if event:
	    h, w = event.height, event.width
	else:
	    h = int(c.configure("height")[4])
	    w = int(c.configure("width")[4])

	self.lower = h - 15
	self.upper = 15
	self.middle = w / 2
	c.create_line(self.middle, self.lower, self.middle, self.upper)
	
	majortickcount = int((max - min) / majortickinterval) 
	self.axislength = self.lower - self.upper
	self.majortickdistance = float(self.axislength) / majortickcount
	self.majortickwidth = w / 5
	labeloffset = (w / 4) + 10

	for i in range(majortickcount + 1):
	    v = min + i * majortickinterval
	    d = self.lower - i * self.majortickdistance
	    c.create_line(self.middle, d, self.middle + self.majortickwidth, d)
	    c.create_text(self.middle + labeloffset, d, font = small_font, text = str(v))
	
	self._desiredSet(event)
	self._actualSet(event)

    def _backgroundSet(self):
	self.canvas.configure(bg = self['bg'])
		
    def _desiredSet(self, event = None):
	c = self.canvas
	desired = self['desiredvalue']
	desiredcolour = self['desiredcolour']

	min = self['min']
	max = self['max']
	
	if desired > max: desired = max
	if desired < min: desired = min
	guage_range = max - min
	
	c = self.canvas
	if event:
	    h, w = event.height, event.width
	else:
	    h = int(c.configure("height")[4])
	    w = int(c.configure("width")[4])


	desired_y = self.lower - (float(desired - min) / guage_range) * self.axislength

	try:
	    c.delete('desiredBar')
	except:
	    pass

	c.create_line(self.middle - self.majortickwidth, desired_y, 
		      self.middle + self.majortickwidth, desired_y,
		      fill = desiredcolour, stipple = 'gray50',
		      width = 10, tag = 'desiredBar')
	self.desiredlabel.configure(text = desired)

    def setActual(self, value):
	self.configure(actualvalue = value)

    def getActual(self):
	return self.cget('actualvalue')

    def _actualSet(self, event = None):
	c = self.canvas
	actual = self['actualvalue']
	actualcolour = self['actualcolour']

	min = self['min']
	max = self['max']
	
	if actual > max: actual = max
	if actual < min: actual = min
	guage_range = max - min
	
	c = self.canvas
	if event:
	    h, w = event.height, event.width
	else:
	    h = int(c.configure("height")[4])
	    w = int(c.configure("width")[4])

	actual_y = self.lower - (float(actual - min) / guage_range) * self.axislength

	try:
	    c.delete('actualPointer')
	except:
	    pass
	
	triangle = ((self.middle, actual_y), 
		    (self.middle - 1.4 * self.majortickwidth, actual_y - self.majortickwidth / 2),
		    (self.middle - 1.4 * self.majortickwidth, actual_y + self.majortickwidth / 2))

	c.create_polygon(triangle, fill = actualcolour, tag = 'actualPointer')
	self.actuallabel.configure(text = actual)


Pmw.forwardmethods(VerticalGuage, Tkinter.Canvas, 'canvas')

if __name__ == '__main__':


    # Initialise Tkinter and Pmw.
    root = Pmw.initialise()
    root.title('Pmw VerticalGuage demonstration')


    def increase():
	av = g1.getActual()
	g1.setActual(av + 1)

    def decrease():
	av = g1.getActual()
	g1.setActual(av - 1)

    g1 = VerticalGuage(min = 0,
		       max = 30, 
		       actualvalue = 15,
		       desiredvalue = 22,
		       majortickinterval = 2,
		       label = "Pms")
    g1.grid(sticky = "nsew")
    root.grid_rowconfigure(0, weight = 1)
    root.grid_columnconfigure(0, weight = 1)
    b1 = Tkinter.Button(text = "Increase", command = increase)
    b1.grid()
    b2 = Tkinter.Button(text = "Decrease", command = decrease)
    b2.grid()

    # Let's go.
    root.mainloop()
