#!/usr/bin/python

# Created by Robert Wenzlaff (Det. Thorn). 
# Oct. 30, 2003

from  Tkinter import *
color=["black", "white", "darkgreen", "gray"]

class App:

	def __init__(self, master):
		frame = Frame(master, borderwidth=5)
		frame.grid(column=0, row=0, pady=5)	

		self.state=[]
		self.states=256
		self.laststate=2  # 0=Black, 1=White, 2=Transp.
		
		self.size=16
		self.gridsz=20
		
		for x in range(1024):
			self.state.append(2);	
		
		self.screen=Canvas( frame, height=320, width=320, bg=color[2] )
		self.screen.bind("<Button-1>", self.scrnclick1)
		self.screen.bind("<Button-3>", self.scrnclick2)
		self.screen.bind("<B1-Motion>", self.scrndrag)	
		
		for x in range(16):
			self.screen.create_line((x*20, 0, x*20, 320), fill=color[3]);
			self.screen.create_line((0, x*20, 320, x*20), fill=color[3]);
			
		self.screen.grid(row=0, column=0, columnspan=5) 
			
		frame2=Frame(master, borderwidth=5)
		frame2.grid(column=0, row=1, pady=5)
		
		self.clear=Button(frame2,text="Clear",command=self.clearit)
		self.clear.grid(row=0, column=0, pady=20)
		
		self.doit=Button(frame2, text="Do It", command=self.doit)
		self.doit.grid(row=0, column=1, pady=20)
		
		#self.doitlab=Label(frame2, text="(Output to stdout)");
		#self.doitlab.grid(row=1, column=1);
		
		self.parse=Button(frame2, text="Parse it", command=self.parsetext);
		self.parse.grid(row=0, column=2, pady=20)
		
		self.large=0
		self.dummy=IntVar()
		self.largeb=Checkbutton(frame2, text="Large", var=self.dummy, command=self.changesize)
		self.largeb.grid(row=0, column=3, pady=20)
		
		self.prev=Canvas(frame2, height=17, width=17, bg=color[2], relief=RIDGE)
		self.prev.grid(row=0, column=4, pady=20, padx=20)
		
		# DataParsers
		self.bmlabel=Label(frame2, text="Bitmap Data (paste hex from code)")
		self.bmlabel.grid(row=2, column=0, columnspan=5, sticky="W")
		
		self.bmentry=Text(frame2, width=80, height=9, font="Times 8");
		self.bmentry.bind("<Leave>", self.bmtextpaste);
		self.bmentry.grid(row=3, column=0, columnspan=5, pady=5);
		
		self.msklabel=Label(frame2, text="Mask Data (paste hex from code)")
		self.msklabel.grid(row=4, column=0, columnspan=5, sticky="W")
		
		self.mskentry=Text(frame2, width=80, height=9, font="Times 8");
		self.mskentry.bind("<Leave>", self.msktextpaste);
		self.mskentry.grid(row=5, column=0, columnspan=5, pady=5);
	
	def changesize(self):
		self.large=~self.large
		if self.large:
			self.size=32
			self.gridsz=10
			self.states=1024
			oldstate=self.state
			self.state=[]
			for n in range(1024):
				col=(n/2)%16
				row=int(n/64)
				self.state.append(oldstate[16*row+col])
			oldstate=[]
		else:
			self.size=16
			self.gridsz=20
			self.states=256
			oldstate=self.state
			self.state=[]
			for n in range(1024):
				if not((n%2) or ((n/32)%2)):
					self.state.append(oldstate[n])
			for n in range(256,1024):
				self.state.append(2)	
			oldstate=[]
			
		#Insert scaling here
	
		self.updatescrn()	
		self.prev.config(width=self.size+1, height=self.size+1)
		for n in range(self.states):
			self.updateprev(n)
		#self.prev.grid(row=0, column=4, padx=self.gridsz, pady=self.gridsz)
	
	def scrnclick1(self, event):
		self.scrnclick(event, 1)
	
	def scrnclick2(self, event):
		self.scrnclick(event, -1)
		
	def scrnclick(self, event, direction):
		if (event.x>319) or (event.y>319) or (event.x<0) or (event.y<0): return
		
		n=(event.x/self.gridsz) + self.size*(event.y/self.gridsz)

		self.state[n]+=direction
		self.state[n]%=3
		
		row=n%self.size
		col=n/self.size
		
		self.screen.create_rectangle( (self.gridsz*row+1, self.gridsz*col+1,\
			self.gridsz*row+self.gridsz-1, self.gridsz*col+self.gridsz-1), \
			fill=color[self.state[n]], outline="" )
			
		self.laststate=self.state[n]
		self.updateprev(n)
		
	def scrndrag(self,event):
		if (event.x>319) or (event.y>319) or (event.x<0) or (event.y<0): return
	
		n=(event.x/self.gridsz) + self.size*(event.y/self.gridsz)
		
		row=n%self.size
		col=n/self.size
		
		self.screen.create_rectangle( (self.gridsz*row+1, self.gridsz*col+1, \
			self.gridsz*row+self.gridsz-1, self.gridsz*col+self.gridsz-1), \
			fill=color[self.laststate], outline="" )
		self.state[n]=self.laststate
		
		self.updateprev(n)

	def updateprev(self, n):
		x=n%self.size+1
		y=n/self.size+1
		
		if self.large: pad=12
		else: pad=20
		
		self.prev.create_line(x+1,y+1,x+2,y+1,fill=color[self.state[n]])
		self.prev.grid(row=0, column=4, padx=pad, pady=pad)
		
	def updatescrn(self):
		self.screen.create_rectangle( 0,0,320,320, fill=color[2] )
		for x in range(self.size):
			self.screen.create_line((x*self.gridsz, 0, x*self.gridsz, 320), fill=color[3]);
			self.screen.create_line((0, x*self.gridsz, 320, x*self.gridsz), fill=color[3]);
		for n in range(self.states):
			row=n%self.size
			col=n/self.size
			self.screen.create_rectangle( (self.gridsz*row+1, self.gridsz*col+1, \
				self.gridsz*row+self.gridsz-1, self.gridsz*col+self.gridsz-1), \
			fill=color[self.state[n]], outline="" )
			
	def bmtextpaste(self, event):
		string=self.bmentry.get(1.0, END)
		self.bmentry.delete(1.0, END)
		string=string.replace("\t", "")
		self.bmentry.insert(END, string)
		
	def msktextpaste(self, event):		
		string=self.mskentry.get(1.0, END)
		self.mskentry.delete(1.0, END)
		string=string.replace("\t", "")
		self.mskentry.insert(END, string)
		
	def parsetext(self):
		from string import atoi
		
		bmstring=self.bmentry.get(1.0, END)
		bmstring=bmstring.replace(",", " ")
		bmstring=bmstring.split()
		
		mskstring=self.mskentry.get(1.0, END)
		mskstring=mskstring.replace(",", " ")
		mskstring=mskstring.split()
		
		if (len(bmstring)!=len(mskstring)):
			print "Mismatched data. Bitmap and mask must be same size,"
			return
		elif not (len(bmstring)==32 or len(bmstring)==128):
			print "Size Error, input must be 32 or 128 hex bytes. "
			return

		
		for n in range(self.states):
			self.state[n]=0;
		
		m=0	
		for entry in bmstring:
			e=atoi(entry, 16);
			for bit in range(8):
				self.state[m]=(e&1)
				e=e>>1;
				m+=1
				
		m=0	
		for entry in mskstring:
			e=atoi(entry, 16);
			for bit in range(8):
				if not (e&1):
					self.state[m]=2;
				e=e>>1
				m+=1	
				
		self.updatescrn()
		for n in range(self.states):  self.updateprev(n)
		
	def clearit(self):
		for n in range(self.states):
			self.state[n]=2;
			self.updateprev(n)
		self.updatescrn()
		self.bmentry.delete(0.0, END);
		self.mskentry.delete(0.0, END);
	
	def doit(self):
		mask=[]
		bitmap=[]
		numbytes=self.size*self.size/8
		for i in range(numbytes):
			m=0
			b=0
			for j in range(8):
				m<<=1
				b<<=1
				if (self.state[(i*8)+(7-j)]!=2):
					m|=1
				if (self.state[(i*8)+(7-j)]==1):
					b|=1
				#print (i*8)+(7-j), self.state[(i*8)+(7-j)], m
			mask.append(m)
			bitmap.append(b)	
		
		print "\n\nstatic char bitmap[]={" %vars(),
		for i in range(numbytes):
			b1=bitmap[i]
			if not(i%8): print "\n\t",
			print "0x%(b1)02x, "%vars(),
		print "\n};"
		
		print "\nstatic char mask[]={" %vars(),
		for i in range(numbytes):
			b1=mask[i]
			if not(i%8): print "\n\t",
			print "0x%(b1)02x, "%vars(),
		print "\n};"
		
################## Main App #######################
root = Tk()

app = App(root)
root.title("Cursor Maker")

root.mainloop()
