import pygtk
pygtk.require('2.0')
import gtk
import cairo

class Knob(gtk.DrawingArea):
	def __init__(self, path, bg_color=None, min_value=0, max_value=100, current_value=0, scale=5, name=""):
		self.setValueCallback(None)
		self.setEnterCallback(None)
		self.setLeaveCallback(None)
		gtk.DrawingArea.__init__(self)
		self._bg_color = bg_color
		self._name = name
		self._pixbuf = gtk.gdk.pixbuf_new_from_file(path)
		x = self._pixbuf.get_width()
		y = self._pixbuf.get_height()
		self.set_size_request(x, y)
		self._min_value = min_value
		self._max_value = max_value
		self._current_value = current_value
		self._scale = scale
		self.set_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK)
		self.connect("motion_notify_event", self._onMotionNotify)
		self.connect("enter-notify-event", self._onEnterNotify)
		self.connect("leave-notify-event", self._onLeaveNotify)
		self._previous_y = 0
		self.connect("expose-event", self._onAreaExpose)

	def _onMotionNotify(self, widget, event):
		if event.is_hint:
			x, y, mask = event.window.get_pointer()
		else:
			x = event.x
			y = event.y
			mask = event.state
		if mask == gtk.gdk.BUTTON1_MASK:
			self.rotateKnob(y)
			self._previous_y = y

	def _onAreaExpose(self, widget, event):
		context = widget.window.cairo_create()
		context.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
		if self._bg_color != None:
			context.set_source_rgb(self._bg_color[0], self._bg_color[1], self._bg_color[2])
			context.fill()
		x = self._pixbuf.get_width()
		y = self._pixbuf.get_height()
		context.translate(int(x/2),int(y/2))
		variable = 270./(self._max_value-self._min_value)*(self._current_value-self._min_value)
		radian = (2*3.14/360)*variable
		context.rotate(radian)
		context.translate(int(-x/2),int(-y/2))
		context.set_source_pixbuf(self._pixbuf, 0, 0)
		context.paint()

	def rotateKnob(self, degree):
		##print self._current_value
		x = self._pixbuf.get_width()
		y = self._pixbuf.get_height()
		if degree > self._previous_y: #then y is going downward, so we must rotate counterclockwise
			self._current_value += self._scale
		elif degree < self._previous_y:
			self._current_value -= self._scale
		if self._current_value > self._max_value:
			self._current_value = self._max_value
		elif self._current_value < self._min_value:
			#print self._current_value, self._min_value
			self._current_value = self._min_value
		else:
			self.value_callback(self._current_value)
			if self.enter_callback != None:
				self.enter_callback(self._name, self._current_value)
			self.queue_draw_area(0, 0, x, y)
			#print self._current_value
	
	def setValueCallback(self, callback, data=None):
		self.value_callback = callback
		self.value_data = data
		
	def setEnterCallback(self, callback, data=None):
		self.enter_callback = callback
		self.enter_data = data
		
	def setLeaveCallback(self, callback, data=None):
		self.leave_callback = callback
		self.leave_data = data

	def _onEnterNotify(self, widget, event):
		if self.enter_callback != None:
			self.enter_callback(self._name, self._current_value)
		
	def _onLeaveNotify(self, widget, event):
		mask = event.state
		if mask != gtk.gdk.BUTTON1_MASK:
			if self.leave_callback != None:
				self.leave_callback()
