title = 'Blt Graph demonstration'

# Import Pmw from this directory tree.
import sys
sys.path[:0] = ['../../..']

import string
import Tkinter
import Pmw

# Simple random number generator.
rand = 12345
def random():
    global rand
    rand = (rand * 125) % 2796203
    return rand

class GraphDemo(Pmw.MegaToplevel):

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

	# Define the megawidget options.
	optiondefs = (
	    ('size',      10,   Pmw.INITOPT),
	)
	self.defineoptions(kw, optiondefs)

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

	# Create the graph.
	self.createWidgets()

	# Check keywords and initialise options.
	self.initialiseoptions()

    def createWidgets(self):
	# Create vectors for use as x and y data points.
	self._numElements = 7
	self._vectorSize = self['size']
	self._vector_x = Pmw.Blt.Vector()
	self._vector_y = []
	for y in range(self._numElements):
	    self._vector_y.append(Pmw.Blt.Vector())
	for index in range(self._vectorSize):
	    self._vector_x.append(index)
	    for y in range(self._numElements):
		self._vector_y[y].append(random() % 100)

	interior = self.interior()

        controlFrame = Tkinter.Frame(interior)
	controlFrame.pack(side = 'bottom', fill = 'x', expand = 0)

        # Create an option menu for the kind of elements to create.
	elementtype = Pmw.OptionMenu(controlFrame,
		labelpos = 'nw',
		label_text = 'Element type',
		items = ['bars', 'lines', 'mixed', 'none'],
		command = self._setelementtype,
		menubutton_width = 8,
	)
	elementtype.pack(side = 'left')

        # Create an option menu for the barmode option.
	barmode = Pmw.OptionMenu(controlFrame,
		labelpos = 'nw',
		label_text = 'Bar mode',
		items = ['normal', 'stacked', 'aligned', 'overlap'],
		command = self._setbarmode,
		menubutton_width = 8,
	)
	barmode.pack(side = 'left')

        # Create an option menu for the smooth option.
	self.smooth = Pmw.OptionMenu(controlFrame,
		labelpos = 'nw',
		label_text = 'Smooth',
		items = ['linear', 'step', 'natural', 'quadratic'],
		command = self._setsmooth,
		menubutton_width = 9,
	)
	self.smooth.pack(side = 'left')

        # Create an option menu to reverse sort the elements.
	sortelements = Pmw.OptionMenu(controlFrame,
		labelpos = 'nw',
		label_text = 'Order',
		items = ['normal', 'reverse'],
		command = self._setsortelements,
		menubutton_width = 8,
	)
	sortelements.pack(side = 'left')

        # Create an option menu for the bufferelements option.
	bufferelements = Pmw.OptionMenu(controlFrame,
		labelpos = 'nw',
		label_text = 'Buffering',
		items = ['buffered', 'unbuffered'],
		command = self._setbufferelements,
		menubutton_width = 10,
	)
	bufferelements.pack(side = 'left')

	# Create a button to add a point to the vector.
	addpoint = Tkinter.Button(controlFrame, text = 'Add point', 
		command = Pmw.busycallback(self._addpoint))
	addpoint.pack(side = 'left', fill = 'x', expand = 0)

	# Create a button to close the window
	close = Tkinter.Button(controlFrame, text = 'Close', 
		command = Pmw.busycallback(self.destroy))
	close.pack(side = 'left', fill = 'x', expand = 0)

	# Create the graph and its elements.
	self._graph = Pmw.Blt.Graph(interior)
	self._graph.pack(expand = 1, fill = 'both')
	self._graph.yaxis_configure(command=self.yaxisCommand)
	elementtype.invoke('mixed')
	bufferelements.invoke('buffered')

    def yaxisCommand(self, graph, value):
        try:
            num = string.atoi(value)
            return '%d      %3d' % (num * 3, num)
        except ValueError:
            num = string.atof(value)
            return '%g      %3g' % (num * 3, num)

    def _setelementtype(self, type):
        elements = self._graph.element_names()
	apply(self._graph.element_delete, elements)

        if type == 'none':
            return

	colorList = Pmw.Color.spectrum(self._numElements)
	for elem in range(self._numElements):
	    if elem == 0:
	        hue = None
	    else:
	        hue = (elem + 1.0) / self._numElements * 6.28318
	    foreground = colorList[elem]
	    background = Pmw.Color.changebrightness(self, foreground, 0.8)
	    if type == 'mixed':
	        if elem < self._numElements / 2:
		    bar = 0
		else:
		    bar = 1
	    elif type == 'bars':
	        bar = 1
	    else:
	        bar = 0
	    if bar:
		self._graph.bar_create(
		    'var' + str(elem),
		    xdata=self._vector_x,
		    ydata=self._vector_y[elem],
		    foreground = foreground,
		    background = background)
	    else:
		self._graph.line_create(
		    'var' + str(elem),
		    linewidth = 4,
		    xdata=self._vector_x,
		    ydata=self._vector_y[elem],
                    smooth = self.smooth.getcurselection(),
		    color = foreground)

    def _setbarmode(self, tag):
        self._graph.configure(barmode = tag)

    def _setsmooth(self, tag):
	for element in self._graph.element_show():
            if self._graph.element_type(element) == 'line':
                self._graph.element_configure(element, smooth = tag)

    def _setbufferelements(self, tag):
        self._graph.configure(bufferelements = (tag == 'buffered'))

    def _setsortelements(self, tag):
	element_list = list(self._graph.element_show())
        if len(element_list) > 1:
            if (tag == 'normal') == (element_list[-1] != 'var0'):
                element_list.reverse()
                self._graph.element_show(element_list)

    def _addpoint(self):
	self._vector_x.append(self._vectorSize)
	for y in range(self._numElements):
	    self._vector_y[y].append(random() % 100)
	self._vectorSize = self._vectorSize + 1

class Demo:
    def __init__(self, parent):
	if not Pmw.Blt.haveblt(parent):
	    message = 'Sorry\nThe BLT package has not been\n' + \
		    'installed on this system.\n' + \
		    'Please install it and try again.'
	    w = Tkinter.Label(parent, text = message)
	    w.pack(padx = 8, pady = 8)
	    return

	message = 'This is a simple demonstration of the\n' + \
		'BLT graph widget.\n' + \
		'Select the number of points to display and\n' + \
		'click on the button to display the graph.'
	w = Tkinter.Label(parent, text = message)
	w.pack(padx = 8, pady = 8)

	# Create combobox to select number of points to display.
	self.combo = Pmw.ComboBox(parent,
		scrolledlist_items = ('10', '25', '50', '100', '300'),
		entryfield_value = '10')
	self.combo.pack(padx = 8, pady = 8)

	# Create button to start blt graph.
	start = Tkinter.Button(parent,
		text = 'Show BLT graph',
	        command = Pmw.busycallback(self.showGraphDemo))
	start.pack(padx = 8, pady = 8)

	self.parent = parent

    def showGraphDemo(self):
	size = string.atoi(self.combo.get())
	demo = GraphDemo(self.parent, size = size)
        demo.focus()

######################################################################

# Create demo in root window for testing.
if __name__ == '__main__':
    root = Tkinter.Tk()
    Pmw.initialise(root)
    root.title(title)

    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
    exitButton.pack(side = 'bottom')
    widget = Demo(root)
    root.mainloop()
