From e6c65d33e68fdfe3b28bff284c62ead374566504 Mon Sep 17 00:00:00 2001 From: Brian Silverman Date: Wed, 30 May 2007 13:28:45 +0000 Subject: Initial import --- (limited to 'ta.py') 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()>k.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() -- cgit v0.9.1