Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/ta.py
diff options
context:
space:
mode:
Diffstat (limited to 'ta.py')
-rwxr-xr-xta.py554
1 files changed, 554 insertions, 0 deletions
diff --git a/ta.py b/ta.py
new file mode 100755
index 0000000..7bbdf5b
--- /dev/null
+++ b/ta.py
@@ -0,0 +1,554 @@
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import os
+import os.path
+import pickle
+from math import atan2, pi
+
+from sprites import *
+from turtlesetup import *
+import logo
+import turtle
+
+WIDTH=1200
+HEIGHT=900
+
+DEGTOR = 2*pi/360
+
+gc = None
+area = None
+draggroup = None
+dragpos = (0,0)
+current_category = None
+category_spr = None
+bgcolor = None
+block_operation = None
+selected_block = None
+select_mask = None
+firstkey = False
+turtlecanvas = None
+status_spr = None
+turtle_spr = None
+hidden_palette_icon = None
+selbuttons = None
+project_flap = None
+
+load_save_folder = None
+save_file_name = None
+
+#
+# Button Press
+#
+
+def buttonpress_cb(win, event):
+ global draggroup, dragpos, block_operation, selected_block
+ block_operation = 'click'
+ if selected_block!=None: unselect()
+ status_spr.setlayer(400)
+ pos = xy(event)
+ x,y = pos
+ spr = findsprite(pos)
+ if spr==None: return True
+ if spr.type == 'selbutton':
+ select_category(spr)
+ elif spr.type == 'tool':
+ tooldispatch(spr)
+ elif spr.type == 'category':
+ block_selector_pressed(x,y)
+ elif spr.type == 'block':
+ block_pressed(event,x,y,spr)
+ elif spr.type == 'turtle':
+ turtle_pressed(x,y)
+ elif spr.type == 'project_flap':
+ project_flap_pressed(spr,x,y)
+ return True
+
+def block_pressed(event,x,y,spr):
+ global draggroup, dragpos, block_operation
+ dragpos = x-spr.x,y-spr.y
+ draggroup = findgroup(spr)
+ for b in draggroup:
+ b.setlayer(2000)
+ disconnect(spr)
+
+def turtle_pressed(x,y):
+ global draggroup, dragpos, block_operation
+ dx,dy = x-turtle_spr.x-30,y-turtle_spr.y-30
+ if dx*dx+dy*dy > 200: dragpos = ('turn', turtle.heading-atan2(dy,dx)/DEGTOR,0)
+ else: dragpos = ('move', x-turtle_spr.x,y-turtle_spr.y)
+ draggroup = [turtle_spr]
+
+def block_selector_pressed(x,y):
+ if category_spr.image==hidden_palette_icon:
+ for i in selbuttons: i.setlayer(800)
+ select_category(selbuttons[0])
+ else:
+ proto = get_proto_from_category(x,y)
+ if proto==None: return
+ if proto!='hide': new_block_from_category(proto,x,y)
+ else:
+ for i in selbuttons: i.hide()
+ category_spr.setshape(hidden_palette_icon)
+
+
+def new_block_from_category(proto,x,y):
+ global draggroup, dragpos, block_operation
+ block_operation = 'new'
+ if proto == None: return True
+ newspr = Sprite(x-20,y-20,proto.image)
+ newspr.setlayer(2000)
+ dragpos = 20,20
+ newspr.type = 'block'
+ newspr.proto = proto
+ if newspr.proto.name == 'number': newspr.label=100
+ newspr.connections = [None]*len(proto.docks)
+ for i in range(len(proto.defaults)):
+ dock = proto.docks[i+1]
+ numproto = blockproto('number')
+ numdock = numproto.docks[0]
+ nx,ny = newspr.x+dock[2]-numdock[2],newspr.y+dock[3]-numdock[3]
+ argspr = Sprite(nx,ny,numproto.image)
+ argspr.type = 'block'
+ argspr.proto = numproto
+ argspr.label = str(proto.defaults[i])
+ argspr.setlayer(2000)
+ argspr.connections = [newspr,None]
+ newspr.connections[i+1] = argspr
+ draggroup = findgroup(newspr)
+
+def get_proto_from_category(x,y):
+# if current_category.mask == None: return current_category.blockprotos[(y-100)/30]
+ dx,dy = x-category_spr.x, y-category_spr.y,
+ pixel = getpixel(current_category.mask,dx,dy)
+ index = ((pixel%256)>>3)-1
+# print hex(pixel),index
+ if index==0: return 'hide'
+ index-=1
+ if index>len(current_category.blockprotos): return None
+ return current_category.blockprotos[index]
+
+def select_category(spr):
+ global current_category
+ if current_category != None:
+ current_category.setshape(current_category.offshape)
+ spr.setshape(spr.onshape)
+ current_category = spr
+ category_spr.setshape(spr.group)
+
+#
+# Mouse move
+#
+
+def move_cb(win, event):
+ global block_operation
+ if draggroup == None: return True
+ block_operation = 'move'
+ spr = draggroup[0]
+ x,y = xy(event)
+ if spr.type=='block':
+ dragx, dragy = dragpos
+ dx,dy = x-dragx-spr.x,y-dragy-spr.y
+ for b in draggroup:
+ b.move((b.x+dx, b.y+dy))
+ elif spr.type=='turtle':
+ type,dragx,dragy = dragpos
+ if type == 'move':
+ dx,dy = x-dragx-spr.x,y-dragy-spr.y
+ spr.move((spr.x+dx, spr.y+dy))
+ else:
+ dx,dy = x-spr.x-30,y-spr.y-30
+ turtle.seth(int(dragx+atan2(dy,dx)/DEGTOR+5)/10*10)
+ return True
+
+
+#
+# Button release
+#
+
+def buttonrelease_cb(win, event):
+ global draggroup, selected_block,firstkey
+ if draggroup == None: return True
+ spr = draggroup[0]
+ x,y = xy(event)
+ if spr.type == 'turtle':
+ turtle.xcor = turtle_spr.x-turtlecanvas.x-turtle.width/2+30
+ turtle.ycor = turtle.height/2-turtle_spr.y+turtlecanvas.y-30
+ turtle.move_turtle()
+ draggroup = None
+ return True
+ if block_operation=='move' and category_spr.hit((x,y)):
+ for b in draggroup: b.hide()
+ draggroup = None
+ return True
+ snap_to_dock(draggroup)
+ for b in draggroup: b.setlayer(650)
+ draggroup = None
+ if block_operation=='click':
+ if spr.proto.name=='number':
+ selected_block = spr
+ select_mask.move((spr.x-6,spr.y-6))
+ select_mask.setlayer(660)
+ firstkey = True
+ else: run_stack(spr)
+ return True
+
+def snap_to_dock(group):
+ d=200
+ me = draggroup[0]
+ for mydockn in range(len(me.proto.docks)):
+ for you in blocks():
+ if you in group: continue
+ for yourdockn in range(len(you.proto.docks)):
+ thisxy = dock_dx_dy(you,yourdockn,me,mydockn)
+ if magnitude(thisxy)>d: continue
+ d=magnitude(thisxy)
+ bestxy=thisxy
+ bestyou=you
+ bestyourdockn=yourdockn
+ bestmydockn=mydockn
+ if d<200:
+ for b in group: b.move((b.x+bestxy[0],b.y+bestxy[1]))
+ me.connections[bestmydockn]=bestyou
+ bestyou.connections[bestyourdockn]=me
+
+def dock_dx_dy(block1,dock1n,block2,dock2n):
+ if block1.connections[dock1n] != None: return (100,100)
+ if block2.connections[dock2n] != None: return (100,100)
+ dock1 = block1.proto.docks[dock1n]
+ dock2 = block2.proto.docks[dock2n]
+ d1type,d1dir,d1x,d1y=dock1[0:4]
+ d2type,d2dir,d2x,d2y=dock2[0:4]
+ if block1==block2: return (100,100)
+ if d1type!=d2type: return (100,100)
+ if d1dir==d2dir: return (100,100)
+ return (block1.x+d1x)-(block2.x+d2x),(block1.y+d1y)-(block2.y+d2y)
+
+
+#
+# Repaint
+#
+
+def expose_cb(win, event):
+# gc.set_foreground(bgcolor)
+# area.draw_rectangle(gc, True, category_spr.x, 0, category_spr.width, HEIGHT)
+# area.draw_rectangle(gc, True, 100, 100, 100, 100)
+
+ redrawsprites()
+ return True
+
+
+#
+# Keyboard, new, load, save
+#
+
+def keypress_cb(area, event):
+ global firstkey
+ keyname = gtk.gdk.keyval_name(event.keyval)
+# print keyname
+ if (event.get_state()&gtk.gdk.CONTROL_MASK):
+ if keyname=="n": new_project()
+ elif keyname=="o": load_file()
+ elif keyname=="s": save_file()
+ elif keyname=="c": turtle.clearscreen()
+ return True
+ if selected_block==None: return True
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname in ['minus', 'period']: keyname = {'minus': '-', 'period': '.'}[keyname]
+ if len(keyname)>1: return True
+ oldnum = selected_block.label
+ if firstkey: newnum = numcheck(keyname,'0')
+ else: newnum = oldnum+keyname
+ selected_block.setlabel(numcheck(newnum,oldnum))
+ firstkey = False
+ return True
+
+def numcheck(new, old):
+ if new in ['-', '.', '-.']: return new
+ if new=='.': return '0.'
+ try: float(new); return new
+ except ValueError,e : return old
+
+def unselect():
+ global selected_block
+ if selected_block.label in ['-', '.', '-.']: select_block.setlabel('0')
+ select_mask.hide()
+ selected_block = None
+
+def new_project():
+ global save_file_name
+ for b in blocks(): b.hide()
+ turtlecanvas.setlayer(600)
+ toolsprite('hideshow').setshape(toolsprs['hideshow'].offshape)
+ turtle.clearscreen()
+ save_file_name = None
+
+def load_file():
+ global save_file_name
+ fname = get_load_name()
+ if fname==None: return
+ if fname[-3:]=='.ta': fname=fname[0:-3]
+ f = open(fname+'.ta',"rU")
+ data = pickle.load(f)
+ f.close()
+ new_project()
+ read_data(data)
+ if os.access(fname+'.png', os.F_OK): load_pict(fname+'.png')
+ turtlecanvas.inval()
+ save_file_name = os.path.basename(fname)
+
+def get_load_name():
+ dialog = gtk.FileChooserDialog("Load...", None,
+ gtk.FILE_CHOOSER_ACTION_OPEN,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN, gtk.RESPONSE_OK))
+ dialog.set_default_response(gtk.RESPONSE_OK)
+ return do_dialog(dialog)
+
+def read_data(data):
+ blocks = []
+ for b in data:
+ if b[1]=='turtle': load_turtle(b)
+ else: spr = load_spr(b); blocks.append(spr)
+ for i in range(len(blocks)):
+ cons=[]
+ for c in data[i][4]:
+ if c==None: cons.append(None)
+ else: cons.append(blocks[c])
+ blocks[i].connections = cons
+
+def load_spr(b):
+ btype, label = b[1],None
+ if type(btype)==type((1,2)): btype, label = btype
+ proto = blockproto(btype)
+ spr = Sprite(b[2]+turtlecanvas.x,b[3]+turtlecanvas.y, proto.image)
+ spr.type = 'block'
+ spr.proto = proto
+ if label!=None: spr.label=label
+ spr.setlayer(650)
+ return spr
+
+def load_turtle(b):
+ id, name, xcor, ycor, heading, color, shade, pensize = b
+ turtle.setxy(xcor, ycor)
+ turtle.seth(heading)
+ turtle.setcolor(color)
+ turtle.setshade(shade)
+ turtle.setpensize(pensize)
+
+def load_pict(fname):
+ pict = gtk.gdk.pixbuf_new_from_file(fname)
+ turtlecanvas.image.draw_pixbuf(gc, pict, 0, 0, 0, 0)
+
+def save_file():
+ global save_file_name
+ fname = get_save_name()
+ if fname==None: return
+ if fname[-3:]=='.ta': fname=fname[0:-3]
+ save_data(fname)
+ save_pict(fname)
+ save_file_name = os.path.basename(fname)
+
+def get_save_name():
+ dialog = gtk.FileChooserDialog("Save..", None,
+ gtk.FILE_CHOOSER_ACTION_SAVE,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE, gtk.RESPONSE_OK))
+ dialog.set_default_response(gtk.RESPONSE_OK)
+ if save_file_name!=None: dialog.set_current_name(save_file_name+'.ta')
+ return do_dialog(dialog)
+
+def save_data(fname):
+ f = file(fname+".ta", "w")
+ bs = blocks()
+ data = []
+ for i in range(len(bs)): bs[i].id=i
+ for b in bs:
+ name = b.proto.name
+ if name=='number': name=(name,b.label)
+ connections = [get_id(x) for x in b.connections]
+ data.append((b.id,name,b.x-turtlecanvas.x,b.y-turtlecanvas.y,connections))
+ data.append((-1,'turtle',
+ turtle.xcor,turtle.ycor,turtle.heading,
+ turtle.color,turtle.shade,turtle.pensize))
+ pickle.dump(data,f)
+ f.close()
+
+def save_pict(fname):
+ tc = turtlecanvas
+ pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, tc.width, tc.height)
+ pixbuf.get_from_drawable(tc.image, tc.image.get_colormap(), 0, 0, 0, 0, tc.width, tc.height)
+ pixbuf.save(fname+'.png', 'png')
+
+def get_id(x):
+ if x==None: return None
+ return x.id
+
+def do_dialog(dialog):
+ global load_save_folder
+ result = None
+ filter = gtk.FileFilter()
+ filter.add_pattern("*.ta")
+ filter.set_name("Turtle Art")
+ dialog.add_filter(filter)
+ dialog.set_current_folder(load_save_folder)
+ response = dialog.run()
+ if response == gtk.RESPONSE_OK:
+ result = dialog.get_filename()
+ load_save_folder = dialog.get_current_folder()
+ dialog.destroy()
+ return result
+
+
+#
+# Block utilities
+#
+
+def run_stack(spr):
+ top = find_top_block(spr)
+ logo.run_blocks(top, blocks())
+ gobject.idle_add(logo.doevalstep)
+
+
+def disconnect(b):
+ if b.connections[0]==None: return
+ b2=b.connections[0]
+ b2.connections[b2.connections.index(b)] = None
+ b.connections[0] = None
+
+
+def findgroup(b):
+ group=[b]
+ for b2 in b.connections[1:]:
+ if b2!=None: group.extend(findgroup(b2))
+ return group
+
+def find_top_block(spr):
+ while spr.connections[0]!=None: spr=spr.connections[0]
+ return spr
+
+def magnitude(pos):
+ x,y = pos
+ return x*x+y*y
+
+def xy(event): return map(int, event.get_coords())
+def blocks(): return [spr for spr in spritelist() if spr.type == 'block']
+
+
+#
+# Toolbar
+#
+
+def tooldispatch(spr):
+ if spr.blocktype == 'new': runtool(spr,new_project)
+ elif spr.blocktype == 'open': runtool(spr,load_file)
+ elif spr.blocktype == 'save': runtool(spr,save_file)
+ elif spr.blocktype == 'hideshow': hideshow_blocks(spr)
+ elif spr.blocktype == 'eraser': runtool(spr,turtle.clearscreen)
+ elif spr.blocktype == 'stopit': logo.step = just_stop()
+
+def just_stop(): yield False
+
+def runtool(spr,cmd):
+ spr.setshape(spr.onshape)
+ cmd()
+ gobject.timeout_add(250,spr.setshape,spr.offshape)
+
+def hideshow_blocks(spr):
+ if spr.image==spr.offshape:
+ for b in blocks(): b.setlayer(100)
+ spr.setshape(spr.onshape)
+ else:
+ for b in blocks(): b.setlayer(650)
+ spr.setshape(spr.offshape)
+ turtlecanvas.inval()
+
+
+def project_flap_pressed(spr,x,y):
+ if spr.image==project_flap['closed']: spr.setshape(project_flap['open'])
+ else:
+ dx,dy = x-spr.x, y-spr.y,
+ pixel = getpixel(project_flap['mask'],dx,dy)
+ index = ((pixel%256)>>3)-1
+ if index==0: spr.setshape(project_flap['closed'])
+ elif index==1: new_project()
+ elif index==2: load_file()
+ elif index==3: save_file()
+
+
+#
+# Startup
+#
+
+def init(top_window, path):
+ global gc, area, category_spr, bgcolor,turtlecanvas, select_mask
+ global status_spr, turtle_spr, selbuttons, hidden_palette_icon, project_flap
+ global base_path, load_save_folder
+ window = top_window
+ base_path = path
+
+ # remove any children of the window that Sugar may have added
+ for widget in window.get_children(): window.remove(widget)
+
+ window.set_title("TurteArt")
+ window.connect("destroy", lambda w: gtk.main_quit())
+ window.set_size_request(WIDTH, HEIGHT)
+ window.add_events(gtk.gdk.BUTTON_PRESS_MASK)
+ window.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
+ window.add_events(gtk.gdk.POINTER_MOTION_MASK)
+ window.connect("expose-event", expose_cb)
+ window.connect("button-press-event", buttonpress_cb)
+ window.connect("button-release-event", buttonrelease_cb)
+ window.connect("motion-notify-event", move_cb)
+ window.connect("key_press_event", keypress_cb)
+ window.show()
+ area = window.window
+ cursor_pix = gtk.gdk.pixbuf_new_from_file(os.path.join(base_path, 'arrow.gif'))
+ cursor = gtk.gdk.Cursor(area.get_display(), cursor_pix, 10, 0)
+ area.set_cursor(cursor)
+ gc = area.new_gc()
+
+ setspritecontext(window,area,gc)
+ cm = gc.get_colormap()
+ bgcolor = cm.alloc_color('#fff8de')
+
+# who = Sprite(0,0,gtk.gdk.pixbuf_new_from_file('fullscreen.gif'))
+# who.type = 'bg'
+# who.setlayer(700)
+
+
+ turtlecanvas = Sprite(0,0,gtk.gdk.Pixmap(area,1200,900,-1))
+ turtlecanvas.type = 'canvas'
+ turtlecanvas.setlayer(600)
+ select_mask = Sprite(100,100,gtk.gdk.pixbuf_new_from_file(os.path.join(base_path, 'masknumber.gif')))
+ select_mask.type = 'selectmask'
+ status_spr = Sprite(0,865,gtk.gdk.pixbuf_new_from_file(os.path.join(base_path, 'status.gif')),True)
+ status_spr.type = 'status'
+ status_spr.setlayer(400)
+ turtle.shapelist = [gtk.gdk.pixbuf_new_from_file(os.path.join(base_path, 'shapes','t'+str(i)+'.gif'))
+ for i in range(36)]
+ turtle_spr = Sprite(100,100,turtle.shapelist[0])
+ turtle_spr.type = 'turtle'
+ turtle_spr.setlayer(630)
+ turtle.init(window,turtlecanvas, turtle_spr, bgcolor)
+ hidden_palette_icon = gtk.gdk.pixbuf_new_from_file(os.path.join(base_path, 'toolbar','blocks-.gif'))
+ category_spr, selbuttons, default_category = setup_selectors(base_path)
+# select_category(default_category)
+ for i in selbuttons: i.hide()
+ category_spr.setshape(hidden_palette_icon)
+ setup_toolbar()
+ project_flap = setup_project_flap()
+ logo.turtle = turtle
+ logo.turtle_spr = turtle_spr
+ logo.stopsign = toolsprite('stopit')
+ logo.status = status_spr
+ logo.init()
+ load_save_folder = os.path.join(base_path,'samples')
+
+def main():
+ win = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ init(win, os.path.abspath('.'))
+ gtk.main()
+ return 0
+
+if __name__ == "__main__":
+ main()