From e6c65d33e68fdfe3b28bff284c62ead374566504 Mon Sep 17 00:00:00 2001 From: Brian Silverman Date: Wed, 30 May 2007 13:28:45 +0000 Subject: Initial import --- diff --git a/MANIFEST b/MANIFEST new file mode 100755 index 0000000..d18f090 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,191 @@ +arrow.gif +logo.py +masknumber.gif +sprites.py +status.gif +ta.py +TurtleArtActivity.py +turtle.py +turtlesetup.py +flow/flowgroup.gif +flow/flowmask.gif +flow/forever.gif +flow/hspace.gif +flow/ifelse.gif +flow/if.gif +flow/repeat.gif +flow/stopstack.gif +flow/vspace.gif +flow/wait.gif +myblocks/1input.gif +myblocks/1inputmask.gif +myblocks/2inputs.gif +myblocks/2inputsmask.gif +myblocks/3inputs.gif +myblocks/3inputsmask.gif +myblocks/boutput.gif +myblocks/boutputmask.gif +myblocks/box1.gif +myblocks/box2.gif +myblocks/global1.gif +myblocks/global1mask.gif +myblocks/global.gif +myblocks/globalmask.gif +myblocks/hat1.gif +myblocks/hat2.gif +myblocks/line.gif +myblocks/linemask.gif +myblocks/myblocksgroup.gif +myblocks/myblocksmask.gif +myblocks/mystuffbg.gif +myblocks/mystuffgroup.gif +myblocks/mystuffmask.gif +myblocks/opwith1ipb.gif +myblocks/opwith1ipbmask.gif +myblocks/opwith1ip.gif +myblocks/opwith1ipmask.gif +myblocks/output1.gif +myblocks/output1mask.gif +myblocks/output.gif +myblocks/outputmask.gif +myblocks/procedure.gif +myblocks/proceduremask.gif +myblocks/setglobal.gif +myblocks/setglobalmask.gif +myblocks/stack1.gif +myblocks/stack2.gif +myblocks/start.gif +myblocks/startmask.gif +myblocks/storeinbox1.gif +myblocks/storeinbox2.gif +numbers/and.gif +numbers/division.gif +numbers/equal.gif +numbers/greater.gif +numbers/less.gif +numbers/minus.gif +numbers/not.gif +numbers/number.gif +numbers/numbersgroup.gif +numbers/numbersmask.gif +numbers/or.gif +numbers/plus.gif +numbers/print.gif +numbers/product.gif +numbers/random.gif +numbers/remainder.gif +palette/flowoff.gif +palette/flowon.gif +palette/myblocksoff.gif +palette/myblockson.gif +palette/numbersoff.gif +palette/numberson.gif +palette/penoff.gif +palette/penon.gif +palette/turtleoff.gif +palette/turtleon.gif +pen/color.gif +pen/fillscreen.gif +pen/pendown.gif +pen/pengroup.gif +pen/penmask.gif +pen/pensize.gif +pen/penup.gif +pen/setbg.gif +pen/setcolor.gif +pen/setpensize.gif +pen/setshade.gif +pen/shade.gif +shapes/t0.gif +shapes/t10.gif +shapes/t11.gif +shapes/t12.gif +shapes/t13.gif +shapes/t14.gif +shapes/t15.gif +shapes/t16.gif +shapes/t17.gif +shapes/t18.gif +shapes/t19.gif +shapes/t1.gif +shapes/t20.gif +shapes/t21.gif +shapes/t22.gif +shapes/t23.gif +shapes/t24.gif +shapes/t25.gif +shapes/t26.gif +shapes/t27.gif +shapes/t28.gif +shapes/t29.gif +shapes/t2.gif +shapes/t30.gif +shapes/t31.gif +shapes/t32.gif +shapes/t33.gif +shapes/t34.gif +shapes/t35.gif +shapes/t3.gif +shapes/t4.gif +shapes/t5.gif +shapes/t6.gif +shapes/t7.gif +shapes/t8.gif +shapes/t9.gif +toolbar/blocks-.gif +toolbar/eraseroff.gif +toolbar/eraseron.gif +toolbar/hideshowoff.gif +toolbar/hideshowon.gif +toolbar/project-.gif +toolbar/project.gif +toolbar/projectmask.gif +toolbar/stopitoff.gif +toolbar/stopiton.gif +turtle/arc.gif +turtle/back.gif +turtle/clean.gif +turtle/forward.gif +turtle/heading.gif +turtle/left.gif +turtle/right.gif +turtle/seth.gif +turtle/setxy.gif +turtle/turtlegroup.gif +turtle/turtlemask.gif +turtle/xcor.gif +turtle/ycor.gif +samples/birds.png +samples/birds.ta +samples/bubbles.png +samples/bubbles.ta +samples/candyvortex.png +samples/candyvortex.ta +samples/colors.png +samples/colors.ta +samples/csquiral.png +samples/csquiral.ta +samples/curlygates.png +samples/curlygates.ta +samples/dots.png +samples/dots.ta +samples/flower.png +samples/flower.ta +samples/fountain.png +samples/fountain.ta +samples/rainbow.png +samples/rainbow.ta +samples/redwisp.png +samples/redwisp.ta +samples/reflections.png +samples/reflections.ta +samples/shades.png +samples/shades.ta +samples/smoothcandy.png +samples/smoothcandy.ta +samples/square.png +samples/square.ta +samples/squares.png +samples/squares.ta +samples/squiral.png +samples/squiral.ta diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py new file mode 100755 index 0000000..7869e4a --- /dev/null +++ b/TurtleArtActivity.py @@ -0,0 +1,25 @@ +import ta + +from sugar.activity import activity + +class TurtleArtActivity(activity.Activity): + def __init__(self, handle): + activity.Activity.__init__(self, handle) + self.connect('destroy', self._cleanup_cb) + + self.gamename = 'turtleart' + self.set_title("TurtleArt") + + self.connect('focus_in_event', self._focus_in) + self.connect('focus_out_event', self._focus_out) + ta.init(self, activity.get_bundle_path()) + + + def _cleanup_cb(self, data=None): + return + + def _focus_in(self, event, data=None): + return + + def _focus_out(self, event, data=None): + return diff --git a/activity/activity-turtleart.svg b/activity/activity-turtleart.svg new file mode 100755 index 0000000..8ad1dc7 --- /dev/null +++ b/activity/activity-turtleart.svg @@ -0,0 +1,27 @@ + + + + + + +]> + + + + + diff --git a/activity/activity.info b/activity/activity.info new file mode 100755 index 0000000..060bc97 --- /dev/null +++ b/activity/activity.info @@ -0,0 +1,7 @@ +[Activity] +name = TurtleArt +service_name = org.laptop.TurtleArtActivity +class = TurtleArtActivity.TurtleArtActivity +icon = activity-turtleart +activity_version = 1 +show_launcher = yes diff --git a/activity/activity.info.bak b/activity/activity.info.bak new file mode 100755 index 0000000..20d7863 --- /dev/null +++ b/activity/activity.info.bak @@ -0,0 +1,7 @@ +[Activity] +name = BlockParty +service_name = org.laptop.BlockPartyActivity +class = BlockPartyActivity.BlockPartyActivity +icon = activity-blockparty +activity_version = 7 +show_launcher = yes diff --git a/arrow.gif b/arrow.gif new file mode 100755 index 0000000..37640dc --- /dev/null +++ b/arrow.gif Binary files differ diff --git a/flow/flowgroup.gif b/flow/flowgroup.gif new file mode 100755 index 0000000..caeb659 --- /dev/null +++ b/flow/flowgroup.gif Binary files differ diff --git a/flow/flowmask.gif b/flow/flowmask.gif new file mode 100755 index 0000000..3369f1d --- /dev/null +++ b/flow/flowmask.gif Binary files differ diff --git a/flow/forever.gif b/flow/forever.gif new file mode 100755 index 0000000..e722b52 --- /dev/null +++ b/flow/forever.gif Binary files differ diff --git a/flow/hspace.gif b/flow/hspace.gif new file mode 100755 index 0000000..f396a80 --- /dev/null +++ b/flow/hspace.gif Binary files differ diff --git a/flow/if.gif b/flow/if.gif new file mode 100755 index 0000000..d12e66d --- /dev/null +++ b/flow/if.gif Binary files differ diff --git a/flow/ifelse.gif b/flow/ifelse.gif new file mode 100755 index 0000000..9fd70e6 --- /dev/null +++ b/flow/ifelse.gif Binary files differ diff --git a/flow/repeat.gif b/flow/repeat.gif new file mode 100755 index 0000000..469ccdd --- /dev/null +++ b/flow/repeat.gif Binary files differ diff --git a/flow/stopstack.gif b/flow/stopstack.gif new file mode 100755 index 0000000..2a6cdd8 --- /dev/null +++ b/flow/stopstack.gif Binary files differ diff --git a/flow/vspace.gif b/flow/vspace.gif new file mode 100755 index 0000000..6f63c80 --- /dev/null +++ b/flow/vspace.gif Binary files differ diff --git a/flow/wait.gif b/flow/wait.gif new file mode 100755 index 0000000..0cf6ad6 --- /dev/null +++ b/flow/wait.gif Binary files differ diff --git a/logo.py b/logo.py new file mode 100755 index 0000000..1c4a460 --- /dev/null +++ b/logo.py @@ -0,0 +1,361 @@ +import re +from time import clock +from operator import isNumberType +import random + +oblist = {} + +iline = None +cfun = None +arglist = None + +istack = [] +iresult = None +step = None +procstop = False + +boxes = {'box1': 0, 'box2': 0} +stacks = {} + +utime_start = 0 + +class symbol: + + def __init__(self, name): + self.name = name + self.nargs = None + self.fcn = None + + def __str__(self): return self.name + def __repr__(self): return '#'+self.name + +class logoerror(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + + +def run_blocks(spr, blocks): + stacks['stack1'] = None + stacks['stack2'] = None + for i in blocks: + if i.proto.name=='hat1': stacks['stack1']= readline(blocks_to_code(i)) + if i.proto.name=='hat2': stacks['stack2']= readline(blocks_to_code(i)) + code = blocks_to_code(spr) + print code + setup_cmd(code) + +def blocks_to_code(spr): + if spr==None: return ['%nothing%'] + code = [] + dock = spr.proto.docks[0] + if len(dock)>4: code.append(dock[4]) + if spr.proto.primname != '': code.append(spr.proto.primname) + else: code.append(float(spr.label)) + for i in range(1,len(spr.connections)): + b = spr.connections[i] + dock = spr.proto.docks[i] + if len(dock)>4: + for c in dock[4]: code.append(c) + if b!=None: code.extend(blocks_to_code(b)) + elif spr.proto.docks[i][0] not in ['flow','numend','unavailable','logi-']: + code.append('%nothing%') + return code + +def intern(str): + if str in oblist: return oblist[str] + sym = symbol(str) + oblist[str] = sym + return sym + + +def parseline(str): + split = re.split(r"\s|([\[\]()])", str) + return [x for x in split if x and x != ""] + +def readline(line): + res = [] + while line: + token = line.pop(0) + if isNumberType(token): res.append(token) + elif token.isdigit(): res.append(float(token)) + elif token[0]=='-' and token[1:].isdigit(): res.append(-float(token[1:])) + elif token[0] == '"': res.append(token[1:]) + elif token == '[': res.append(readline(line)) + elif token == ']': return res + else: res.append(intern(token)) + return res + + +def setup_cmd(str): + global iline, step, procstop + stopsignon(); procstop=False + list = readline(str) + step = start_eval(list) + +def start_eval(list): + icall(evline, list); yield True + yield False + +def evline(list): + global cfun, arglist, iline + oldiline = iline + iline = list[:] + arglist = None + while iline: + token = iline[0] + if token==symopar: token=iline[1] + icall(eval); yield True + if procstop: break + if iresult==None: continue + raise logoerror("You don't say what to do with %s" % token) + iline = oldiline + ireturn(); yield True + +def eval(infixarg=False): + token = iline.pop(0) + if type(token) == symtype: + icall(evalsym, token); yield True + res = iresult + else: res = token + if not infixarg: + while infixnext(): + icall(evalinfix, res); yield True + res = iresult + ireturn(res); yield True + +def evalsym(token): + global cfun, arglist + undefined_check(token) + oldcfun, oldarglist = cfun, arglist + cfun, arglist = token, [] + for i in range(token.nargs): + no_args_check() + icall(eval); yield True + arglist.append(iresult) + if cfun.rprim: + if type(cfun.fcn)==listtype: icall(ufuncall, cfun.fcn); yield True + else: icall(cfun.fcn, *arglist); yield True + result = None + else: result = cfun.fcn(*arglist) + cfun, arglist = oldcfun, oldarglist + if arglist!=None and result==None: + raise logoerror("%s didn't output to %s" % (oldcfun.name, cfun.name)) + ireturn(result); yield True + +def evalinfix(firstarg): + global cfun, arglist + token = iline.pop(0) + oldcfun, oldarglist = cfun, arglist + cfun, arglist = token, [firstarg] + no_args_check() + icall(eval,True); yield True + arglist.append(iresult) + result = cfun.fcn(*arglist) + cfun, arglist = oldcfun, oldarglist + ireturn (result); yield True + +def infixnext(): + if len(iline)==0: return False + if type(iline[0])!=symtype: return False + return iline[0].name in ['+', '-', '*', '/','%','and','or'] + +def undefined_check(token): + if token.fcn != None: return False + raise logoerror("I don't know how to %s" % token.name) + + +def no_args_check(): + if iline and iline[0]!=symnothing : return + raise logoerror("Not enough inputs to %s" % cfun.name) + +def prim_wait(time): + turtle_spr.setlayer(630) + endtime = millis()+an_int(time)*100 + while millis()float(y)) + defprim('less?', 2, lambda x,y: float(x)self.x+self.width: return False + if yself.y+self.height: return False + if isinstance(self.image,gtk.gdk.Pixmap): return True + dx,dy = x-self.x, y-self.y + return ord(self.image.get_pixels()[(dy*self.width+dx)*4+3]) == 255 + + def draw_label1(self, label): + fd = pango.FontDescription('Sans') + fd.set_size(7*pango.SCALE) + pl = window.create_pango_layout(str(label)) + pl.set_font_description(fd) + swidth = pl.get_size()[0]/pango.SCALE + sheight = pl.get_size()[1]/pango.SCALE + centerx = self.x+self.width/2 + centery = self.y+self.height/2 + gc.set_foreground(black) + area.draw_layout(gc,centerx-swidth/2,centery-sheight/2,pl) + + def draw_label2(self, label): + fd = pango.FontDescription('Sans') + fd.set_size(9*pango.SCALE) + pl = window.create_pango_layout(str(label)) + pl.set_font_description(fd) + sheight = pl.get_size()[1]/pango.SCALE + centery = self.y+self.height/2 + gc.set_foreground(black) + area.draw_layout(gc,self.x+50,centery-sheight/2,pl) + + +def findsprite(pos): + list = sprites[:] + list.reverse() + for s in list: + if s.hit(pos): return s + return None + +def redrawsprites(): + for s in sprites: s.draw() + +def getpixel(image,x,y): + array = image.get_pixels() + offset = (y*image.get_width()+x)*4 + r,g,b,a = ord(array[offset]),ord(array[offset+1]),ord(array[offset+2]),ord(array[offset+3]) + return (a<<24)+(b<<16)+(g<<8)+r + +def setspritecontext(w,a,g): + global window,area,gc,black + window=w + area =a + gc = g + black = gc.get_colormap().alloc_color('black') + +def spritelist(): return sprites \ No newline at end of file diff --git a/status.gif b/status.gif new file mode 100755 index 0000000..376a5a9 --- /dev/null +++ b/status.gif Binary files differ 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() diff --git a/toolbar/blocks-.gif b/toolbar/blocks-.gif new file mode 100755 index 0000000..d8347ed --- /dev/null +++ b/toolbar/blocks-.gif Binary files differ diff --git a/toolbar/eraseroff.gif b/toolbar/eraseroff.gif new file mode 100755 index 0000000..9da2c2e --- /dev/null +++ b/toolbar/eraseroff.gif Binary files differ diff --git a/toolbar/eraseron.gif b/toolbar/eraseron.gif new file mode 100755 index 0000000..a3db3cc --- /dev/null +++ b/toolbar/eraseron.gif Binary files differ diff --git a/toolbar/hideshowoff.gif b/toolbar/hideshowoff.gif new file mode 100755 index 0000000..25a5d7d --- /dev/null +++ b/toolbar/hideshowoff.gif Binary files differ diff --git a/toolbar/hideshowon.gif b/toolbar/hideshowon.gif new file mode 100755 index 0000000..f727380 --- /dev/null +++ b/toolbar/hideshowon.gif Binary files differ diff --git a/toolbar/project-.gif b/toolbar/project-.gif new file mode 100755 index 0000000..4050808 --- /dev/null +++ b/toolbar/project-.gif Binary files differ diff --git a/toolbar/project.gif b/toolbar/project.gif new file mode 100755 index 0000000..ff0fe4f --- /dev/null +++ b/toolbar/project.gif Binary files differ diff --git a/toolbar/projectmask.gif b/toolbar/projectmask.gif new file mode 100755 index 0000000..8092284 --- /dev/null +++ b/toolbar/projectmask.gif Binary files differ diff --git a/toolbar/stopitoff.gif b/toolbar/stopitoff.gif new file mode 100755 index 0000000..c559ee5 --- /dev/null +++ b/toolbar/stopitoff.gif Binary files differ diff --git a/toolbar/stopiton.gif b/toolbar/stopiton.gif new file mode 100755 index 0000000..4b79aef --- /dev/null +++ b/toolbar/stopiton.gif Binary files differ diff --git a/turtle.py b/turtle.py new file mode 100755 index 0000000..dc1b0b6 --- /dev/null +++ b/turtle.py @@ -0,0 +1,195 @@ +import gtk +from math import sin,cos,pi + +colors = {} +buffer = None +gc = None +window = None +width = 0 +height = 0 +sprite = None +cm = None +bgcolor = None +fgcolor = None +color = 0 +shade = 50 +pensize = 5 +pendown = True +turtle = None + +DEGTOR = 2*pi/360 + +xcor = 0 +ycor = 0 +heading = 0 + +color_table = ( + 0xFF0000,0xFF0D00,0xFF1A00,0xFF2600,0xFF3300,0xFF4000,0xFF4D00,0xFF5900,0xFF6600,0xFF7300, + 0xFF8000,0xFF8C00,0xFF9900,0xFFA600,0xFFB300,0xFFBF00,0xFFCC00,0xFFD900,0xFFE600,0xFFF200, + 0xFFFF00,0xE6FF00,0xCCFF00,0xB3FF00,0x99FF00,0x80FF00,0x66FF00,0x4DFF00,0x33FF00,0x1AFF00, + 0x00FF00,0x00FF0D,0x00FF1A,0x00FF26,0x00FF33,0x00FF40,0x00FF4D,0x00FF59,0x00FF66,0x00FF73, + 0x00FF80,0x00FF8C,0x00FF99,0x00FFA6,0x00FFB3,0x00FFBF,0x00FFCC,0x00FFD9,0x00FFE6,0x00FFF2, + 0x00FFFF,0x00F2FF,0x00E6FF,0x00D9FF,0x00CCFF,0x00BFFF,0x00B3FF,0x00A6FF,0x0099FF,0x008CFF, + 0x0080FF,0x0073FF,0x0066FF,0x0059FF,0x004DFF,0x0040FF,0x0033FF,0x0026FF,0x001AFF,0x000DFF, + 0x0000FF,0x0D00FF,0x1A00FF,0x2600FF,0x3300FF,0x4000FF,0x4D00FF,0x5900FF,0x6600FF,0x7300FF, + 0x8000FF,0x8C00FF,0x9900FF,0xA600FF,0xB300FF,0xBF00FF,0xCC00FF,0xD900FF,0xE600FF,0xF200FF, + 0xFF00FF,0xFF00E6,0xFF00CC,0xFF00B3,0xFF0099,0xFF0080,0xFF0066,0xFF004D,0xFF0033,0xFF001A) + +def init(win, spr, tspr, bg): + global buffer, gc, window, sprite, width, height, bgcolor, fgcolor, cm, turtle + window, sprite, buffer, turtle, bgcolor = win.window, spr, spr.image, tspr, bg + width, height = buffer.get_size() + gc = win.window.new_gc() + cm = gc.get_colormap() + gc = buffer.new_gc() + clearscreen() + +def clearscreen(): + global xcor,ycor,heading, pendown + xcor, ycor, heading = 0,0,0 + rect = gtk.gdk.Rectangle(0,0,width,height) + gc.set_foreground(bgcolor) + buffer.draw_rectangle(gc, True, *rect) + inval(0,0,width,height) + setpensize(5) + setcolor(0) + setshade(50) + pendown = True + move_turtle() + turn_turtle() + return None + +def forward(n): + global xcor,ycor + gc.set_foreground(fgcolor) + oldx, oldy = xcor, ycor + xcor += n*sin(heading*DEGTOR) + ycor += n*cos(heading*DEGTOR) + if pendown: draw_line(oldx,oldy,xcor,ycor) + move_turtle() + return None + +def seth(n): + global heading + heading=n + heading%=360 + turn_turtle() + return None + +def right(n): + global heading + heading+=n + heading%=360 + turn_turtle() + return None + +def arc(a,r): + gc.set_foreground(fgcolor) + if a<0: larc(-a,r) + else: rarc(a,r) + move_turtle() + turn_turtle() + +def rarc(a,r): + global xcor,ycor + if r<0: r=-r; a=-a + cx = xcor+r*cos(heading*DEGTOR) + cy = ycor-r*sin(heading*DEGTOR) + x,y,w,h=width/2+int(cx-r),height/2-int(cy+r),int(2*r),int(2*r) + buffer.draw_arc(gc,False,x,y,w,h,int(180-heading-a)*64,int(a)*64) + inval(x-pensize/2-3,y-pensize/2-3,w+pensize+6,h+pensize+6) + right(a) + xcor=cx-r*cos(heading*DEGTOR) + ycor=cy+r*sin(heading*DEGTOR) + +def larc(a,r): + global xcor,ycor + if r<0: r=-r; a=-a + cx = xcor-r*cos(heading*DEGTOR) + cy = ycor+r*sin(heading*DEGTOR) + x,y,w,h=width/2+int(cx-r),height/2-int(cy+r),int(2*r),int(2*r) + buffer.draw_arc(gc,False,x,y,w,h,int(360-heading)*64,int(a)*64) + inval(x-pensize/2-3,y-pensize/2-3,w+pensize+6,h+pensize+6) + right(-a) + xcor=cx+r*cos(heading*DEGTOR) + ycor=cy-r*sin(heading*DEGTOR) + +def setxy(x,y): + global xcor,ycor + xcor,ycor = x,y + move_turtle() + +def setpensize(ps): + global pensize + pensize = ps + gc.set_line_attributes(int(pensize),gtk.gdk.LINE_SOLID,gtk.gdk.CAP_ROUND,gtk.gdk.JOIN_MITER) + return None + +def setcolor(c): + global color + color = c + set_fgcolor() + return None + +def setshade(s): + global shade + shade = s + set_fgcolor() + return None + +def fillscreen(c,s): + oldc, olds = color,shade + setcolor(c); setshade(s) + rect = gtk.gdk.Rectangle(0,0,width,height) + gc.set_foreground(fgcolor) + buffer.draw_rectangle(gc, True, *rect) + inval(0,0,width,height) + setcolor(oldc); setshade(olds) + return None + +def set_fgcolor(): + global fgcolor + sh = (wrap100(shade)-50)/50.0 + rgb = color_table[wrap100(color)] + r,g,b = (rgb>>8)&0xff00,rgb&0xff00,(rgb<<8)&0xff00 + r,g,b = calc_shade(r,sh),calc_shade(g,sh),calc_shade(b,sh) + fgcolor = cm.alloc_color(r,g,b) + +def wrap100(n): + n = int(n) + n %= 200 + if n>99: n=199-n + return n + +def calc_shade(c,s): + if s<0: return int(c*(1+s*.8)) + return int(c+(65536-c)*s*.9) + +def setpen(bool): + global pendown + pendown = bool + +def draw_line(x1,y1,x2,y2): + x1,y1 = width/2+int(x1), height/2-int(y1) + x2,y2 = width/2+int(x2), height/2-int(y2) + if x1