diff options
author | rafael <rafael@rafael.dirakx> | 2010-02-19 20:40:56 (GMT) |
---|---|---|
committer | rafael <rafael@rafael.dirakx> | 2010-02-19 20:40:56 (GMT) |
commit | 11fc91a50249436c39fee3e12d73528ab80f3ab3 (patch) | |
tree | 9f91cb4810d645936b26157b019df5ea392dcd3f | |
parent | 408aa90d52bda7f126e395f5a0c9ec191878becc (diff) |
-rw-r--r-- | taarduino.py | 50 | ||||
-rw-r--r-- | talogo.py | 2227 | ||||
-rw-r--r-- | tawindow.py | 3343 |
3 files changed, 1910 insertions, 3710 deletions
diff --git a/taarduino.py b/taarduino.py new file mode 100644 index 0000000..f6b6474 --- /dev/null +++ b/taarduino.py @@ -0,0 +1,50 @@ +import firmata + +class TAArduino(object): + def __init__(self, dev='/dev/ttyUSB0', baud=115200): + object.__init__(self) + self._dev = dev + self._baud = baud + self._arduino = None # Do not initialize this now + + self.HIGH = firmata.HIGH + self.LOW = firmata.LOW + self.INPUT = firmata.INPUT + self.OUTPUT = firmata.OUTPUT + self.PWM = firmata.PWM + self.SERVO = firmata.SERVO + + def _check_init(self): + if self._arduino is None: + self._arduino = firmata.Arduino(port = self._dev, \ + baudrate=self._baud) + self._arduino.parse() + + def delay(self, secs): + # Do not use this. The firmata module uses time.sleep() to + # implement this, which breaks gtk+ (unresponsive window) + self._check_init() + self._arduino.delay(secs) + + def pin_mode(self, pin, mode): + self._check_init() + self._arduino.pin_mode(int(pin), mode) + + def analog_write(self, pin, value): + self._check_init() + self._arduino.analog_write(int(pin), int(value)) + + def digital_write(self, pin, value): + self._check_init() + self._arduino.digital_write(int(pin), value) + + def analog_read(self, pin): + self._check_init() + self._arduino.parse() #XXX: Not sure why I have to do this here. + return self._arduino.analog_read(int(pin)) + + def digital_read(self, pin): + self._check_init() + return self._arduino.digital_read(int(pin)) + + @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- #Copyright (c) 2007-8, Playful Invention Company. -#Copyright (c) 2008-10, Walter Bender -#Copyright (c) 2008-10, Raúl Gutiérrez Segalés +#Copyright (c) 2008-9, Walter Bender #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal @@ -21,13 +19,13 @@ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #THE SOFTWARE. -import gtk +import re +from time import * import gobject -from time import clock -from math import sqrt -from random import uniform from operator import isNumberType +import random import audioop +from math import * import subprocess from UserDict import UserDict try: @@ -35,26 +33,27 @@ try: except: pass -from taconstants import PALETTES, PALETTE_NAMES, BOX_STYLE -from tagplay import play_audio, play_movie_from_file, stop_media -from tajail import myfunc, myfunc_import -from tautils import get_pixbuf_from_journal, movie_media_type,\ - audio_media_type, round_int -from gettext import gettext as _ - class noKeyError(UserDict): __missing__=lambda x,y: 0 +class taLogo: pass + +from taturtle import * +from tagplay import * +from tajail import * + +from gettext import gettext as _ + +procstop = False + 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 + def __str__(self): return self.name + def __repr__(self): return '#'+self.name class logoerror(Exception): def __init__(self, value): @@ -62,1244 +61,1050 @@ class logoerror(Exception): def __str__(self): return repr(self.value) -""" -Utility functions -""" - -''' -The strategy for mixing numbers and strings is to first try -converting the string to a float; then if the string is a single -character, try converting it to an ord; finally, just treat it as a -string. Numbers appended to strings are first trreated as ints, then -floats. -''' -def convert(x, fn, try_ord=True): - try: - return fn(x) - except ValueError: - if try_ord: - xx, flag = chr_to_ord(x) - if flag: - return fn(xx) - return x - -def numtype(x): - if type(x) == int: - return True - if type(x) == float: - return True - if type(x) == ord: - return True - return False - -def strtype(x): - if type(x) == str: - return True - if type(x) == unicode: - return True - return False - -def str_to_num(x): - xx = convert(x, float) - if type(xx) is float: - return xx +def run_blocks(lc, spr, blocks, run_flag): + # user-defined stacks + for x in lc.stacks.keys(): + lc.stacks[x]= None + # two built-in stacks + lc.stacks['stack1'] = None + lc.stacks['stack2'] = None + for i in blocks: + if i.proto.name=='hat1': + lc.stacks['stack1']= readline(lc,blocks_to_code(lc,i)) + if i.proto.name=='hat2': + lc.stacks['stack2']= readline(lc,blocks_to_code(lc,i)) + if i.proto.name=='hat': + if (i.connections[1]!=None): + text=i.connections[1].label + lc.stacks['stack3'+text]= readline(lc,blocks_to_code(lc,i)) + code = blocks_to_code(lc,spr) + if run_flag == True: + print code + setup_cmd(lc, code) + else: return code + +def blocks_to_code(lc,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: - xx, xflag = chr_to_ord(x) - if xflag: - return xx + if spr.proto.name=='number': + try: + code.append(float(spr.label)) + except: + code.append(float(ord(spr.label[0]))) + elif spr.proto.name=='string' or spr.proto.name=='title': + if type(spr.label) == float or type(spr.label) == int: + if int(spr.label) == spr.label: + spr.label = int(spr.label) + code.append('#s'+str(spr.label)) + else: + code.append('#s'+spr.label) + elif spr.proto.name=='journal': + if spr.ds_id != None: + code.append('#smedia_'+str(spr.ds_id)) + else: + code.append('#smedia_None') + elif spr.proto.name=='descriptionoff' or \ + spr.proto.name=='descriptionon': + if spr.ds_id != None: + code.append('#sdescr_'+str(spr.ds_id)) + else: + code.append('#sdescr_None') + elif spr.proto.name=='audiooff' or spr.proto.name=='audio': + if spr.ds_id != None: + code.append('#saudio_'+str(spr.ds_id)) + else: + code.append('#saudio_None') else: - raise logoerror("#syntaxerror") - -def chr_to_ord(x): - if strtype(x) and len(x) == 1: - try: - return ord(x[0]), True - except ValueError: - return x, False - return x, False - -def taand(x, y): - return x&y - -def taor(x, y): - return x|y + return ['%nothing%'] + 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(lc,b)) + elif spr.proto.docks[i][0] not in \ + ['flow', 'numend', 'stringend', 'mediaend', \ + 'audioend', 'unavailable', 'logi-']: + code.append('%nothing%') + return code + +def intern(lc, str): + if str in lc.oblist: return lc.oblist[str] + sym = symbol(str) + lc.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(lc, 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[0:2] == "#s": res.append(token[2:]) + elif token == '[': res.append(readline(lc,line)) + elif token == ']': return res + else: res.append(intern(lc, token)) + return res + +def setup_cmd(lc, str): + setlayer(lc.tw.turtle.spr,100) + lc.procstop=False + list = readline(lc, str) + lc.step = start_eval(lc, list) + +def start_eval(lc, list): + icall(lc, evline, list); yield True + # turn off stop icon when execution is finished + if hasattr(lc.tw,"activity"): + lc.tw.activity.stop_button.set_icon("stopitoff") + yield False -def careful_divide(x, y): +def evline(lc, list): + oldiline = lc.iline + lc.iline = list[:] + lc.arglist = None + while lc.iline: + if lc.tw.step_time > 0: + setlayer(lc.tw.turtle.spr,630) + endtime = millis()+an_int(lc,lc.tw.step_time)*100 + while millis()<endtime: + yield True + setlayer(lc.tw.turtle.spr,100) + token = lc.iline[0] + if token==lc.symopar: token=lc.iline[1] + icall(lc, eval); yield True + if lc.procstop: break + if lc.iresult==None: continue + raise logoerror(str(lc.iresult)) + lc.iline = oldiline + ireturn(lc) + display_coordinates(lc.tw) + yield True + +def eval(lc, infixarg=False): + token = lc.iline.pop(0) + if type(token) == lc.symtype: + icall(lc, evalsym, token); yield True + res = lc.iresult + else: res = token + if not infixarg: + while infixnext(lc): + icall(lc, evalinfix, res); yield True + res = lc.iresult + ireturn(lc, res) + yield True + +def evalsym(lc, token): + debug_trace(lc, token) + undefined_check(lc, token) + oldcfun, oldarglist = lc.cfun, lc.arglist + lc.cfun, lc.arglist = token, [] + if token.nargs==None: raise logoerror("#noinput") + for i in range(token.nargs): + no_args_check(lc) + icall(lc, eval); yield True + lc.arglist.append(lc.iresult) + if lc.cfun.rprim: + if type(lc.cfun.fcn)==lc.listtype: + icall(lc, ufuncall, cfun.fcn); yield True + else: + icall(lc, lc.cfun.fcn, *lc.arglist); yield True + result = None + else: + result = lc.cfun.fcn(lc, *lc.arglist) + lc.cfun, lc.arglist = oldcfun, oldarglist + if lc.arglist!=None and result==None: + raise logoerror("%s didn't output to %s" % \ + (oldcfun.name, lc.cfun.name)) + ireturn(lc, result) + yield True + +def evalinfix(lc, firstarg): + token = lc.iline.pop(0) + oldcfun, oldarglist = lc.cfun, lc.arglist + lc.cfun, lc.arglist = token, [firstarg] + no_args_check(lc) + icall(lc, eval,True); yield True + lc.arglist.append(lc.iresult) + result = lc.cfun.fcn(lc,*lc.arglist) + lc.cfun, lc.arglist = oldcfun, oldarglist + ireturn (lc,result); yield True + +def infixnext(lc): + if len(lc.iline)==0: return False + if type(lc.iline[0])!=lc.symtype: return False + return lc.iline[0].name in ['+', '-', '*', '/','%','and','or'] + +def debug_trace(lc, token): + if lc.trace: + if token.name in ['forward', 'right', 'back', 'left', 'seth', 'setxy', \ + 'arc', 'heading', 'xcor', 'ycor']: + my_string = token.name +\ + "\nxcor= " + str(int(lc.tw.turtle.xcor)) +\ + "\nycor= " + str(int(lc.tw.turtle.ycor)) +\ + "\nheading= " + str(int(lc.tw.turtle.heading)) +\ + "\nscale= " + str(lc.scale) + elif token.name in ['penup', 'pendown', 'setcolor', 'setshade', \ + 'settextcolor', 'settextsize', 'shade', 'color', \ + 'fillscreen', 'pensize']: + if lc.tw.turtle.pendown: + penstatus = "\npen down" + else: + penstatus = "\npen up" + my_string = token.name + penstatus +\ + "\ncolor= " + str(int(lc.tw.turtle.color)) +\ + "\nshade= " + str(lc.tw.turtle.shade) +\ + "\npen size= " + str(lc.tw.turtle.pensize) + else: + my_string = token.name + "\nblocks status:\n" + for k,v in lc.boxes.iteritems(): + tmp = k +":" + str(v) + "\n" + my_string += tmp + shp = 'info' + setshape(lc.tw.status_spr, lc.tw.status_shapes[shp]) + setlabel(lc.tw.status_spr, _(my_string)) + setlayer(lc.tw.status_spr, 710) + return + +def undefined_check(lc, token): + if token.fcn != None: return False + raise logoerror("I don't know how to %s" % token.name) + +def no_args_check(lc): + if lc.iline and lc.iline[0]!=lc.symnothing : return + raise logoerror("#noinput") + +def prim_wait(lc,time): + setlayer(lc.tw.turtle.spr,630) + endtime = millis()+an_int(lc,time*1000) + while millis()<endtime: + yield True + setlayer(lc.tw.turtle.spr,100) + ireturn(lc); yield True + +def prim_repeat(lc, num, list): + num = an_int(lc, num) + for i in range(num): + icall(lc, evline, list[:]); yield True + if lc.procstop: break + ireturn(lc); yield True + +def prim_forever(lc, list): + while True: + icall(lc,evline, list[:]); yield True + if lc.procstop: break + ireturn(lc); yield True + +def prim_if(lc, bool, list): + if bool: icall(lc, evline, list[:]); yield True + ireturn(lc); yield True + +def prim_ifelse(lc, bool, list1,list2): + if bool: ijmp(lc, evline, list1[:]); yield True + else: ijmp(lc, evline, list2[:]); yield True + +def prim_opar(lc,val): + lc.iline.pop(0) + return val + +def prim_define(name, body): + if type(name) != symtype: name = intern(name) + name.nargs, name.fcn = 0, body + name.rprim = True + +def prim_stack(lc,stri): + if (not lc.stacks.has_key('stack3'+stri)) or \ + lc.stacks['stack3'+stri]==None: raise logoerror("#nostack") + icall(lc, evline, lc.stacks['stack3'+stri][:]); yield True + lc.procstop = False + ireturn(lc); yield True + +def prim_stack1(lc): + if lc.stacks['stack1']==None: raise logoerror("#nostack") + icall(lc, evline, lc.stacks['stack1'][:]); yield True + lc.procstop = False + ireturn(lc); yield True + +def prim_stack2(lc): + if lc.stacks['stack2']==None: raise logoerror("#nostack") + icall(lc, evline, lc.stacks['stack2'][:]); yield True + lc.procstop = False + ireturn(lc); yield True + +def prim_stopstack(lc): + lc.procstop = True + +def careful_divide(x,y): try: + if y==0: return 0 return x/y - except ZeroDivisionError: - raise logoerror("#zerodivide") - except TypeError: - try: - return str_to_num(x) / str_to_num(y) - except ZeroDivisionError: - raise logoerror("#zerodivide") - except ValueError: - raise logoerror("#syntaxerror") + except: + return 0 + +def ufuncall(body): + ijmp(evline, body); yield True + +def an_int(lc, n): + if type(n) == int: + return n + elif type(n) == float: + return int(n) + elif type(n) == str: + return int(ord(n[0])) + else: + raise logoerror("%s doesn't like %s as input" \ + % (lc.cfun.name, str(n))) -def taequal(x, y): +def defprim(lc, name, args, fcn, rprim=False): + sym = intern(lc, name) + sym.nargs, sym.fcn = args,fcn + sym.rprim = rprim + +def taequal(x,y): try: return float(x)==float(y) - except TypeError: - typex, typey = False, False - if strtype(x): - typex = True - if strtype(y): - typey = True - if typex and typey: - return x == y - try: - return str_to_num(x) == str_to_num(y) - except ValueError: - raise logoerror("#syntaxerror") + except: + if type(x) == str or type(x) == unicode: + xx = ord(x[0]) + else: + xx = x + if type(y) == str or type(y) == unicode: + yy = ord(y[0]) + else: + yy = y + return xx==yy -def taless(x, y): +def taless(x,y): try: return float(x)<float(y) - except ValueError: - typex, typey = False, False - if strtype(x): - typex = True - if strtype(y): - typey = True - if typex and typey: - return x < y - try: - return str_to_num(x) < str_to_num(y) - except TypeError: - raise logoerror("#syntaxerror") - -def tamore(x, y): - return taless(y, x) - -def taplus(x, y): - if numtype(x) and numtype(y): - return(x+y) - else: - if numtype(x): - xx = str(round_int(x)) + except: + if type(x) == str or type(x) == unicode: + xx = ord(x[0]) else: xx = x - if numtype(y): - yy = str(round_int(y)) + if type(y) == str or type(y) == unicode: + yy = ord(y[0]) else: yy = y - return(xx+yy) - -def taminus(x, y): - if numtype(x) and numtype(y): - return(x-y) - try: - return str_to_num(x) - str_to_num(y) - except TypeError: - raise logoerror("#syntaxerror") - -def taproduct(x, y): - if numtype(x) and numtype(y): - return(x*y) + return xx<yy + +def tamore(x,y): + return taless(y,x) + +def taplus(x,y): + if (type(x) == int or type(x) == float) and \ + (type(y) == int or type(y) == float): + return(x+y) + else: + return(str(x) + str(y)) + +def taminus(x,y): try: - return str_to_num(x) * str_to_num(y) - except TypeError: + return(x-y) + except: raise logoerror("#syntaxerror") -def tamod(x, y): - if numtype(x) and numtype(y): - return(x%y) +def taproduct(x,y): try: - return str_to_num(x) % str_to_num(y) - except TypeError: - raise logoerror("#syntaxerror") - except ValueError: + return(x*y) + except: raise logoerror("#syntaxerror") - -def tasqrt(x): - if numtype(x): - if x < 0: - raise logoerror("#negroot") - return sqrt(x) + +def tamod(x,y): try: - return sqrt(str_to_num(x)) - except ValueError: - raise logoerror("#negroot") - except TypeError: + return(x%y) + except: raise logoerror("#syntaxerror") -def tarandom(x, y): - if numtype(x) and numtype(y): - return(int(uniform(x,y))) - xx, xflag = chr_to_ord(x) - yy, yflag = chr_to_ord(y) - print xx, xflag, yy, yflag - if xflag and yflag: - return chr(int(uniform(xx,yy))) - if not xflag: - xx = str_to_num(x) - if not yflag: - yy = str_to_num(y) +def tasqrt(x): try: - return(int(uniform(xx,yy))) - except TypeError: + return sqrt(x) + except: raise logoerror("#syntaxerror") def identity(x): return(x) - -""" -Stop_logo is called from the Stop button on the toolbar -""" -def stop_logo(tw): - tw.step_time = 0 - tw.lc.step = just_stop() - tw.turtles.show_all() - -def just_stop(): - yield False -def millis(): - return int(clock()*1000) - -""" -A class for parsing Logo Code -""" -class LogoCode: - def __init__(self, tw): - - self.tw = tw - self.oblist = {} - - DEFPRIM = { - '(':[1, lambda self, x: self.prim_opar(x)], - 'and':[2, lambda self,x,y: taand(x,y)], - 'arc':[2, lambda self, x, y: self.tw.canvas.arc(x, y)], - 'back':[1, lambda self,x: self.tw.canvas.forward(-x)], - 'blue':[0, lambda self: 70], - 'bpos':[0, lambda self: -self.tw.canvas.height/(self.tw.coord_scale*2)], - 'boty':[0, lambda self: self.tw.bottomy], - 'box1':[0, lambda self: self.boxes['box1']], - 'box':[1, lambda self,x: self.box(x)], - 'box2':[0, lambda self: self.boxes['box2']], - 'bullet':[1, self.prim_bullet, True], - 'bulletlist':[1, self.prim_list, True], - 'clean':[0, lambda self: self.prim_clear()], - 'clearheap':[0, lambda self: self.empty_heap()], - 'color':[0, lambda self: self.tw.canvas.color], - 'comment':[1, lambda self,x: self.prim_print(x, True)], - 'container':[1, lambda self,x: x], - 'cyan':[0, lambda self: 50], - 'define':[2, self.prim_define], - 'division':[2, lambda self,x,y: careful_divide(x,y)], - 'equal?':[2, lambda self,x,y: taequal(x,y)], - 'fillscreen':[2, lambda self, x, y: self.tw.canvas.fillscreen(x, y)], - 'forever':[1, self.prim_forever, True], - 'forward':[1, lambda self, x: self.tw.canvas.forward(x)], - 'fullscreen':[0, lambda self: self.tw.set_fullscreen()], - 'greater?':[2, lambda self,x,y: tamore(x,y)], - 'green':[0, lambda self: 30], - 'heading':[0, lambda self: self.tw.canvas.heading], - 'hideblocks':[0, lambda self: self.tw.hideblocks()], - 'hres':[0, lambda self: self.tw.canvas.width/self.tw.coord_scale], - 'id':[1, lambda self,x: identity(x)], - 'if':[2, self.prim_if, True], - 'ifelse':[3, self.prim_ifelse, True], - 'insertimage':[1, lambda self,x: self.insert_image(x, False)], - 'kbinput':[0, lambda self: self.prim_kbinput()], - 'keyboard':[0, lambda self: self.keyboard], - 'left':[1, lambda self,x: self.tw.canvas.right(-x)], - 'leftx':[0, lambda self: self.tw.leftx], - 'lpos':[0, lambda self: -self.tw.canvas.width/(self.tw.coord_scale*2)], - 'less?':[2, lambda self,x,y: taless(x,y)], - 'minus':[2, lambda self,x,y: taminus(x,y)], - 'mod':[2, lambda self,x,y: tamod(x,y)], - 'myfunc':[1, self.prim_myfunc, True], - 'myfunction':[1, lambda self, x: self.myfunction(x)], - 'nop':[0, lambda self: None], - 'nop1':[0, lambda self: None], - 'nop2':[0, lambda self: None], - 'nop3':[1, lambda self,x: None], - 'not':[1, lambda self,x:not x], - 'orange':[0, lambda self: 10], - 'or':[2, lambda self,x,y: taor(x,y)], - 'pendown':[0, lambda self: self.tw.canvas.setpen(True)], - 'pensize':[0, lambda self: self.tw.canvas.pensize], - 'penup':[0, lambda self: self.tw.canvas.setpen(False)], - 'plus':[2, lambda self,x,y: taplus(x,y)], - 'pop':[0, lambda self: self.prim_pop()], - 'print':[1, lambda self,x: self.prim_print(x, False)], - 'printheap':[0, lambda self: self.prim_print_heap()], - 'product':[2, lambda self,x,y: taproduct(x,y)], - 'purple':[0, lambda self: 90], - 'push':[1, lambda self,x: self.prim_push(x)], - 'random':[2, lambda self,x,y: tarandom(x,y)], - 'red':[0, lambda self: 0], - 'repeat':[2, self.prim_repeat, True], - 'right':[1, lambda self, x: self.tw.canvas.right(x)], - 'rightx':[0, lambda self: self.tw.rightx], - 'rpos':[0, lambda self: self.tw.canvas.width/(self.tw.coord_scale*2)], - 'savepix':[1, lambda self, x: self.save_picture(x)], - 'scale':[0, lambda self: self.scale], - 'setcolor':[1, lambda self, x: self.tw.canvas.setcolor(x)], - 'seth':[1, lambda self, x: self.tw.canvas.seth(x)], - 'setpensize':[1, lambda self, x: self.tw.canvas.setpensize(x)], - 'setscale':[1, lambda self,x: self.set_scale(x)], - 'setshade':[1, lambda self, x: self.tw.canvas.setshade(x)], - 'settextcolor':[1, lambda self, x: self.tw.canvas.settextcolor(x)], - 'settextsize':[1, lambda self, x: self.tw.canvas.settextsize(x)], - 'setxy':[2, lambda self, x, y: self.tw.canvas.setxy(x, y)], - 'shade':[0, lambda self: self.tw.canvas.shade], - 'show':[1, lambda self, x: self.show(x, True)], - 'showaligned':[1,lambda self, x: self.show(x, False)], - 'showblocks':[0, lambda self: self.tw.showblocks()], - 'sound':[1, lambda self,x: self.play_sound(x)], - 'sqrt':[1, lambda self,x: tasqrt(x)], - 'stack1':[0, self.prim_stack1, True], - 'stack':[1, self.prim_stack, True], - 'stack2':[0, self.prim_stack2, True], - 'start':[0, lambda self: self.prim_start()], - 'stopstack':[0, lambda self: self.prim_stopstack()], - 'storeinbox1':[1, lambda self,x: self.prim_setbox('box1', None ,x)], - 'storeinbox2':[1, lambda self,x: self.prim_setbox('box2', None, x)], - 'storeinbox':[2, lambda self,x,y: self.prim_setbox('box3', x, y)], - 't1x1':[2, lambda self,x,y: self.show_template1x1(x, y)], - 't1x1a':[2, lambda self,x,y: self.show_template1x1a(x, y)], - 't1x2':[3, lambda self,x,y,z: self.show_template1x2(x, y, z)], - 't2x1':[3, lambda self,x,y,z: self.show_template2x1(x, y, z)], - 't2x2':[5, lambda self,x,y,z,a,b: self.show_template2x2(x, y, z, a, b)], - 'textcolor':[0, lambda self: self.tw.canvas.textcolor], - 'textsize':[0, lambda self: self.tw.textsize], - 'titlex':[0, lambda self: self.tw.titlex], - 'titley':[0, lambda self: self.tw.titley], - 'topy':[0, lambda self: self.tw.topy], - 'tpos':[0, lambda self: self.tw.canvas.height/(self.tw.coord_scale*2)], - 'turtle':[1, lambda self, x: self.tw.canvas.set_turtle(x)], - 'userdefined':[1, lambda self,x: self.prim_myblock(x)], - 'video':[1, lambda self,x: self.play_movie(x)], - 'vres':[0, lambda self: self.tw.canvas.height/self.tw.coord_scale], - 'wait':[1, self.prim_wait, True], - 'write':[2, lambda self, x,y: self.write(self, x,y)], - 'xcor':[0, lambda self: self.tw.canvas.xcor/self.tw.coord_scale], - 'ycor':[0, lambda self: self.tw.canvas.ycor/self.tw.coord_scale], - 'yellow':[0, lambda self: 20]} - - for p in iter(DEFPRIM): - if len(DEFPRIM[p]) == 2: - self.defprim(p, DEFPRIM[p][0], DEFPRIM[p][1]) - else: - self.defprim(p, DEFPRIM[p][0], DEFPRIM[p][1], DEFPRIM[p][2]) - - self.symtype = type(self.intern('print')) - self.listtype = type([]) - self.symnothing = self.intern('%nothing%') - self.symopar = self.intern('(') - self.iline = None - self.cfun = None - self.arglist = None - self.ufun = None - self.procstop = False - self.running = False - self.istack = [] - self.stacks = {} - self.boxes = {'box1': 0, 'box2': 0} - self.heap = [] - - self.keyboard = 0 - self.trace = 0 - self.gplay = None - self.ag = None - self.title_height = int((self.tw.canvas.height/20)*self.tw.scale) - self.body_height = int((self.tw.canvas.height/40)*self.tw.scale) - self.bullet_height = int((self.tw.canvas.height/30)*self.tw.scale) - - self.scale = 33 - - """ - Define the primitives associated with the blocks - """ - def defprim(self, name, args, fcn, rprim=False): - sym = self.intern(name) - sym.nargs, sym.fcn = args, fcn - sym.rprim = rprim - - """ - Add any new objects to the symbol list. - """ - def intern(self, str): - if str in self.oblist: - return self.oblist[str] - sym = symbol(str) - self.oblist[str] = sym - return sym - - """ - Given a block to run... - """ - def run_blocks(self, blk, blocks, run_flag): - for k in self.stacks.keys(): - self.stacks[k] = None - self.stacks['stack1'] = None - self.stacks['stack2'] = None - - for b in blocks: - b.unhighlight() - if b.name == 'hat1': - code = self.blocks_to_code(b) - self.stacks['stack1'] = self.readline(code) - if b.name=='hat2': - code = self.blocks_to_code(b) - self.stacks['stack2'] = self.readline(code) - if b.name == 'hat': - if b.connections[1] is not None: - code = self.blocks_to_code(b) - x = b.connections[1].values[0] - if type(convert(x, float, False)) == type(float): - if int(float(x)) == x: - x = int(x) - self.stacks['stack3'+str(x)] = self.readline(code) - - code = self.blocks_to_code(blk) - if run_flag is True: - print "running code: %s" % (code) - self.setup_cmd(code) - else: - return code - - """ - Convert a stack of blocks to pseudocode. - Maintains a parallel datastructure for backpointers to blocks. - """ - def blocks_to_code(self, blk): - if blk is None: - return ['%nothing%', '%nothing%'] - code = [] - dock = blk.docks[0] - if len(dock)>4: # There could be a '(', ')', '[' or ']'. - code.append(dock[4]) - if blk.primitive is not None: # make a tuple (prim, blk) - code.append((blk.primitive, self.tw.block_list.list.index(blk))) - elif len(blk.values)>0: # Extract the value from content blocks. - if blk.name=='number': - try: - code.append(float(blk.values[0])) - except ValueError: - code.append(float(ord(blk.values[0][0]))) - elif blk.name=='string' or blk.name=='title': - if type(blk.values[0]) == float or type(blk.values[0]) == int: - if int(blk.values[0]) == blk.values[0]: - blk.values[0] = int(blk.values[0]) - code.append('#s'+str(blk.values[0])) - else: - code.append('#s'+blk.values[0]) - elif blk.name=='journal': - if blk.values[0] is not None: - code.append('#smedia_'+str(blk.values[0])) - else: - code.append('#smedia_None') - elif blk.name=='description': - if blk.values[0] is not None: - code.append('#sdescr_'+str(blk.values[0])) - else: - code.append('#sdescr_None') - elif blk.name=='audio': - if blk.values[0] is not None: - code.append('#saudio_'+str(blk.values[0])) - else: - code.append('#saudio_None') - else: - return ['%nothing%'] - else: - return ['%nothing%'] - for i in range(1, len(blk.connections)): - b = blk.connections[i] - dock = blk.docks[i] - if len(dock)>4: # There could be a '(', ')', '[' or ']'. - for c in dock[4]: - code.append(c) - if b is not None: - code.extend(self.blocks_to_code(b)) - elif blk.docks[i][0] not in ['flow', 'unavailable']: - code.append('%nothing%') - return code +# recenter the canvas when the start block is clicked +def start_stack(lc): + if hasattr(lc.tw,'activity'): + lc.tw.activity.recenter() + +def lcNew(tw): + lc = taLogo() + lc.tw = tw + lc.oblist = {} + + # math primitives + defprim(lc,'print', 1, lambda lc,x: status_print(lc,x)) + defprim(lc,'+', None, lambda lc,x,y:x+y) + defprim(lc,'plus', 2, lambda lc,x,y:taplus(x,y)) + defprim(lc,'-', None, lambda lc,x,y:x-y) + defprim(lc,'minus', 2, lambda lc,x,y:taminus(x,y)) + defprim(lc,'*', None, lambda lc,x,y:x*y) + defprim(lc,'product', 2, lambda lc,x,y:taproduct(x,y)) + defprim(lc,'/', None, lambda lc,x,y:careful_divide(x,y)) + defprim(lc,'division', 2, lambda lc,x,y:careful_divide(x,y)) + defprim(lc,'random', 2, lambda lc,x,y: int(random.uniform(x,y))) + defprim(lc,'greater?', 2, lambda lc,x,y: tamore(x,y)) + defprim(lc,'less?', 2, lambda lc,x,y: taless(x,y)) + defprim(lc,'equal?', 2, lambda lc,x,y: taequal(x,y)) + defprim(lc,'and', None, lambda lc,x,y:x&y) + defprim(lc,'or', None, lambda lc,x,y:x|y) + defprim(lc,'not', 1, lambda lc,x:not x) + defprim(lc,'%', None, lambda lc,x,y:x%y) + defprim(lc,'mod', 2, lambda lc,x,y:tamod(x,y)) + defprim(lc,'sqrt', 1, lambda lc,x: sqrt(x)) + defprim(lc,'id',1, lambda lc,x: identity(x)) - """ - Execute the psuedocode. - """ - def setup_cmd(self, str): - self.tw.active_turtle.hide() # Hide the turtle while we are running. - self.procstop = False - list = self.readline(str) - self.step = self.start_eval(list) - - """ - Convert the pseudocode into a list of commands. - The block associated with the command is stored as the second element - in a tuple, e.g., (#forward, 16) - """ - def readline(self, line): - res = [] - while line: - token = line.pop(0) - bindex = None - if type(token) == tuple: - (token, bindex) = token - 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[0:2] == "#s": - res.append(token[2:]) - elif token == '[': - res.append(self.readline(line)) - elif token == ']': - return res - elif bindex is None or type(bindex) is not int: - res.append(self.intern(token)) - else: - res.append((self.intern(token), bindex)) - return res - - """ - Step through the list. - """ - def start_eval(self, list): - if self.tw.running_sugar: - self.tw.activity.stop_button.set_icon("stopiton") - self.running = True - self.icall(self.evline, list) - yield True - if self.tw.running_sugar: - self.tw.activity.stop_button.set_icon("stopitoff") - yield False - self.running = False - - """ - Add a function and its arguments to the program stack. - """ - def icall(self, fcn, *args): - self.istack.append(self.step) - self.step = fcn(*(args)) - - """ - Evaluate a line of code from the list. - """ - def evline(self, list): - oldiline = self.iline - self.iline = list[:] - self.arglist = None - while self.iline: - token = self.iline[0] - bindex = None - if type(token) == tuple: - (token, bindex) = self.iline[0] - - # If the blocks are visible, highlight the current block. - if not self.tw.hide and bindex is not None: - self.tw.block_list.list[bindex].highlight() - - # In debugging modes, we pause between steps and show the turtle. - if self.tw.step_time > 0: - self.tw.active_turtle.show() - endtime = millis()+self.an_int(self.tw.step_time)*100 - while millis()<endtime: - yield True - self.tw.active_turtle.hide() - - # 'Stand-alone' booleans are handled here. - if token == self.symopar: - token = self.iline[1] - if type(token) == tuple: - (token, bindex) = self.iline[1] - - # Process the token and any arguments. - self.icall(self.eval) - yield True - - # Time to unhighlight the current block. - if not self.tw.hide and bindex is not None: - self.tw.block_list.list[bindex].unhighlight() - - if self.procstop: - break - if self.iresult == None: - continue - - if bindex is not None: - self.tw.block_list.list[bindex].highlight() - raise logoerror(str(self.iresult)) - self.iline = oldiline - self.ireturn() - if self.tw.hide is False: - self.tw.display_coordinates() - yield True - - """ - Evaluate the next token on the line of code we are processing. - """ - def eval(self): - token = self.iline.pop(0) - bindex = None - if type(token) == tuple: - (token, bindex) = token - - # Either we are processing a symbol or a value. - if type(token) == self.symtype: - # We highlight blocks here in case an error occurs... - if not self.tw.hide and bindex is not None: - self.tw.block_list.list[bindex].highlight() - self.icall(self.evalsym, token) - yield True - # and unhighlight if everything was OK. - if not self.tw.hide and bindex is not None: - self.tw.block_list.list[bindex].unhighlight() - res = self.iresult - else: - res = token + # keyboard, sensor, and misc. primitives + defprim(lc,'kbinput', 0, lambda lc: kbinput(lc)) + defprim(lc,'keyboard', 0, lambda lc: lc.keyboard) + defprim(lc,'userdefined', 1, lambda lc,x: loadmyblock(lc,x)) + defprim(lc,'myfunc', 2, lambda lc,f,x: callmyfunc(lc, f, x)) + defprim(lc,'hres', 0, lambda lc: lc.tw.turtle.width/lc.tw.coord_scale) + defprim(lc,'vres', 0, lambda lc: lc.tw.turtle.height/lc.tw.coord_scale) + defprim(lc,'leftpos', 0, lambda lc: \ + -(lc.tw.turtle.width/(lc.tw.coord_scale*2))) + defprim(lc,'toppos', 0, lambda lc: \ + lc.tw.turtle.height/(lc.tw.coord_scale*2)) + defprim(lc,'rightpos', 0, lambda lc: \ + lc.tw.turtle.width/(lc.tw.coord_scale*2)) + defprim(lc,'bottompos', 0, lambda lc: \ + -(lc.tw.turtle.height/(lc.tw.coord_scale*2))) + + # turtle primitives + defprim(lc,'clean', 0, lambda lc: clear(lc)) + defprim(lc,'forward', 1, lambda lc, x: forward(lc.tw.turtle, x)) + defprim(lc,'back', 1, lambda lc,x: forward(lc.tw.turtle,-x)) + defprim(lc,'seth', 1, lambda lc, x: seth(lc.tw.turtle, x)) + defprim(lc,'right', 1, lambda lc, x: right(lc.tw.turtle, x)) + defprim(lc,'left', 1, lambda lc,x: right(lc.tw.turtle,-x)) + defprim(lc,'heading', 0, lambda lc: lc.tw.turtle.heading) + defprim(lc,'setxy', 2, lambda lc, x, y: setxy(lc.tw.turtle, x, y)) + defprim(lc,'show',1,lambda lc, x: show(lc, x, True)) + defprim(lc,'setscale', 1, lambda lc,x: set_scale(lc, x)) + defprim(lc,'scale', 0, lambda lc: lc.scale) + defprim(lc,'write',2,lambda lc, x,y: write(lc, x,y)) + defprim(lc,'insertimage', 1, lambda lc,x: insert_image(lc, x, False)) + defprim(lc,'arc', 2, lambda lc, x, y: arc(lc.tw.turtle, x, y)) + defprim(lc,'xcor', 0, lambda lc: lc.tw.turtle.xcor/lc.tw.coord_scale) + defprim(lc,'ycor', 0, lambda lc: lc.tw.turtle.ycor/lc.tw.coord_scale) + + # pen primitives + defprim(lc,'pendown', 0, lambda lc: setpen(lc.tw.turtle, True)) + defprim(lc,'penup', 0, lambda lc: setpen(lc.tw.turtle, False)) + defprim(lc,'(', 1, lambda lc, x: prim_opar(lc,x)) + defprim(lc,'setcolor', 1, lambda lc, x: setcolor(lc.tw.turtle, x)) + defprim(lc,'settextcolor', 1, lambda lc, x: settextcolor(lc.tw.turtle, x)) + defprim(lc,'settextsize', 1, lambda lc, x: settextsize(lc.tw.turtle, x)) + defprim(lc,'setshade', 1, lambda lc, x: setshade(lc.tw.turtle, x)) + defprim(lc,'setpensize', 1, lambda lc, x: setpensize(lc.tw.turtle, x)) + defprim(lc,'fillscreen', 2, lambda lc, x, y: \ + fillscreen(lc.tw.turtle, x, y)) + defprim(lc,'color', 0, lambda lc: lc.tw.turtle.color) + defprim(lc,'shade', 0, lambda lc: lc.tw.turtle.shade) + defprim(lc,'pensize', 0, lambda lc: lc.tw.turtle.pensize) + defprim(lc,'textcolor', 0, lambda lc: lc.tw.turtle.textcolor) + defprim(lc,'textsize', 0, lambda lc: lc.tw.textsize) + defprim(lc,'red', 0, lambda lc: 0) + defprim(lc,'orange', 0, lambda lc: 10) + defprim(lc,'yellow', 0, lambda lc: 20) + defprim(lc,'green', 0, lambda lc: 30) + defprim(lc,'cyan', 0, lambda lc: 50) + defprim(lc,'blue', 0, lambda lc: 70) + defprim(lc,'purple', 0, lambda lc: 90) + + # flow primitives + defprim(lc,'wait', 1, prim_wait, True) + defprim(lc,'repeat', 2, prim_repeat, True) + defprim(lc,'forever', 1, prim_forever, True) + defprim(lc,'if', 2, prim_if, True) + defprim(lc,'ifelse', 3, prim_ifelse, True) + defprim(lc,'stopstack', 0, prim_stopstack) + + # blocks primitives + defprim(lc,'stack1', 0, prim_stack1, True) + defprim(lc,'stack2', 0, prim_stack2, True) + defprim(lc,'stack', 1, prim_stack, True) + defprim(lc,'box1', 0, lambda lc: lc.boxes['box1']) + defprim(lc,'box2', 0, lambda lc: lc.boxes['box2']) + defprim(lc,'box', 1, lambda lc,x: box(lc,x)) + defprim(lc,'storeinbox1', 1, lambda lc,x: setbox(lc, 'box1',x)) + defprim(lc,'storeinbox2', 1, lambda lc,x: setbox(lc, 'box2',x)) + defprim(lc,'storeinbox', 2, lambda lc,x,y: setbox(lc, 'box3'+str(x),y)) + defprim(lc,'push', 1, lambda lc,x: push_heap(lc,x)) + defprim(lc,'pop', 0, lambda lc: pop_heap(lc)) + defprim(lc,'heap', 0, lambda lc: heap_print(lc)) + defprim(lc,'emptyheap', 0, lambda lc: empty_heap(lc)) + defprim(lc,'start', 0, lambda lc: start_stack(lc)) + defprim(lc,'define', 2, prim_define) + defprim(lc,'nop', 0, lambda lc: None) + defprim(lc,'nop1', 0, lambda lc: None) + defprim(lc,'nop2', 0, lambda lc: None) + defprim(lc,'nop3', 1, lambda lc,x: None) + + # templates primitives + defprim(lc,'container', 1, lambda lc,x: x) + defprim(lc,'tp1', 2, lambda lc,x,y: show_template1(lc, x, y)) + defprim(lc,'tp8', 2, lambda lc,x,y: show_template8(lc, x, y)) + defprim(lc,'tp6', 3, lambda lc,x,y,z: show_template6(lc, x, y, z)) + defprim(lc,'tp3', 8, lambda lc,x,y,z,a,b,c,d,e: \ + show_template3(lc, x, y, z, a, b, c, d, e)) + defprim(lc,'sound', 1, lambda lc,x: play_sound(lc, x)) + defprim(lc,'video', 1, lambda lc,x: play_movie(lc, x)) + defprim(lc,'tp2', 3, lambda lc,x,y,z: \ + show_template2(lc, x, y, z)) + defprim(lc,'tp7', 5, lambda lc,x,y,z,a,b: \ + show_template7(lc, x, y, z, a, b)) + defprim(lc,'hideblocks', 0, lambda lc: hideblocks(lc)) + + # arduino primitives + defprim(lc,'delay', 1, prim_wait, True) + defprim(lc,'setpinmode', 2, lambda lc, x, y: lc.tw.arduino.pin_mode(x, y)) + defprim(lc,'analogwrite', 2, lambda lc, x, y: \ + lc.tw.arduino.analog_write(x, y)) + defprim(lc,'digitalwrite', 2, lambda lc, x, y: \ + lc.tw.arduino.digital_write(x, y)) + defprim(lc,'analogread', 1, lambda lc, x: lc.tw.arduino.analog_read(x)) + defprim(lc,'digitalread', 1, lambda lc, x: lc.tw.arduino.digital_read(x)) + defprim(lc,'high', 0, lambda lc: lc.tw.arduino.HIGH) + defprim(lc,'low', 0, lambda lc: lc.tw.arduino.LOW) + defprim(lc,'input', 0, lambda lc: lc.tw.arduino.INPUT) + defprim(lc,'output', 0, lambda lc: lc.tw.arduino.OUTPUT) + defprim(lc,'pwm', 0, lambda lc: lc.tw.arduino.PWM) + defprim(lc,'servo', 0, lambda lc: lc.tw.arduino.SERVO) + + lc.symtype = type(intern(lc, 'print')) + lc.listtype = type([]) + lc.symnothing = intern(lc, '%nothing%') + lc.symopar = intern(lc, '(') + + lc.istack = [] + lc.stacks = {} + # lc.boxes = noKeyError({'box1': 0, 'box2': 0}) + lc.boxes = {'box1': 0, 'box2': 0} + lc.heap = [] + lc.keyboard = 0 + lc.trace = 0 # flag for enabling debug output via showlabel + lc.gplay = None + lc.ag = None + lc.nobox = "" + lc.title_height = int((lc.tw.turtle.height/30)*lc.tw.scale) + lc.body_height = int((lc.tw.turtle.height/60)*lc.tw.scale) + lc.bullet_height = int((lc.tw.turtle.height/45)*lc.tw.scale) + + lc.iline, lc.cfun, lc.arglist, lc.ufun = None, None, None, None + + # this dictionary is used to define the relative size and postion of + # template elements (w, h, x, y, dx, dy, dx1, dy1...) + lc.templates = { + 'tp1': (0.5, 0.5, 0.0625, 0.125, 1.05, 0), + 'tp2': (0.5, 0.5, 0.0625, 0.125, 1.05, 1.05), + 'tp3': (1, 1, 0.0625, 0.125, 0, 0.1), + 'tp6': (0.45, 0.45, 0.0625, 0.125, 1.05, 1.05), + 'tp7': (0.45, 0.45, 0.0625, 0.125, 1.05, 1.05), + 'tp8': (0.9, 0.9, 0.0625, 0.125, 0, 0), + 'insertimage': (0.333, 0.333) + } + lc.scale = 33 + + return lc + +def display_coordinates(tw): + if hasattr(tw, "activity"): + if hasattr(tw.activity, "coordinates_label"): + x = round_int(tw.turtle.xcor/tw.coord_scale) + y = round_int(tw.turtle.ycor/tw.coord_scale) + h = round_int(tw.turtle.heading) + tw.activity.coordinates_label.set_text(_("xcor") + " = " + \ + str(x) + " " + \ + _("ycor") + " = " + \ + str(y) + " " + \ + _("heading") + " = " + \ + str(h)) + tw.activity.coordinates_label.show() + +def round_int(n): + if int(float(n)) == n: + return int(n) + else: + nn = int(float(n+0.05)*10)/10. + if int(float(nn)) == nn: + return int(nn) + return nn - self.ireturn(res) - yield True +def box(lc,x): + try: + return lc.boxes['box3'+str(x)] + except: + lc.nobox = str(x) + raise logoerror("#emptybox") + +def loadmyblock(lc,x): + # execute code inported from the Journal + if lc.tw.myblock != None: + y = myfunc_import(lc, lc.tw.myblock, x) + else: + raise logoerror("#nocode") + return - """ - Process primitive associated with symbol token - """ - def evalsym(self, token): - self.debug_trace(token) - self.undefined_check(token) - oldcfun, oldarglist = self.cfun, self.arglist - self.cfun, self.arglist = token, [] - - if token.nargs == None: - raise logoerror("#noinput") - for i in range(token.nargs): - self.no_args_check() - self.icall(self.eval) - yield True - self.arglist.append(self.iresult) - if self.cfun.rprim: - if type(self.cfun.fcn) == self.listtype: - self.icall(self.ufuncall, self.cfun.fcn) - yield True - else: - self.icall(self.cfun.fcn, *self.arglist) - yield True - result = None - else: - result = self.cfun.fcn(self, *self.arglist) - self.cfun, self.arglist = oldcfun, oldarglist - if self.arglist is not None and result == None: - raise logoerror("%s didn't output to %s (arglist %s, result %s)" % \ - (oldcfun.name, self.cfun.name, str(self.arglist), str(result))) - self.ireturn(result) - yield True +def callmyfunc(lc, f, x): + y = myfunc(lc, f, x) + if y is None: + raise logoerror("#syntaxerror") + stop_logo(lc.tw) + else: + return y - def ufuncall(self, body): - ijmp(self.evline, body) - yield True - - def doevalstep(self): - starttime = millis() +def show_picture(lc, media, x, y, w, h): + if media == "" or media[6:] == "": + # raise logoerror("#nomedia") + pass + elif media[6:] != "None": try: - while (millis()-starttime)<120: - try: - if self.step is not None: - self.step.next() - else: - return False - except StopIteration: - self.tw.turtles.show_all() - return False - except logoerror, e: - self.tw.showlabel('syntaxerror', str(e)[1:-1]) - self.tw.turtles.show_all() - return False - return True - - def ireturn(self, res=None): - self.step = self.istack.pop() - self.iresult = res - - def ijmp(self, fcn, *args): - self.step = fcn(*(args)) - - def debug_trace(self, token): - if self.trace: - if token.name in PALETTES[PALETTE_NAMES.index('turtle')]: - my_string = "%s\n%s=%d\n%s=%d\n%s=%d\n%s=%d" %\ - (token.name, _('xcor'), int(self.tw.canvas.xcor), - _('ycor'), int(self.tw.canvas.ycor), _('heading'), - int(self.tw.canvas.heading), _('scale'), int(self.scale)) - elif token.name in PALETTES[PALETTE_NAMES.index('pen')]: - if self.tw.canvas.pendown: - penstatus = _('pen down') - else: - penstatus = _('pen up') - my_string = "%s\n%s\n%s=%d\n%s=%d\n%s=%.1f" %\ - (token.name, penstatus, _('color'), - int(self.tw.canvas.color), _('shade'), - int(self.tw.canvas.shade), _('pen size'), - self.tw.canvas.pensize) - else: - my_string = "%s\n%s:\n" % (token.name, _('box')) - for k, v in self.boxes.iteritems(): - tmp = k +":" + str(v) + "\n" - my_string += tmp - self.tw.showlabel('info',my_string) - return - - def undefined_check(self, token): - if token.fcn is not None: - return False - if token.name == '%nothing%': - errormsg = '' + dsobject = datastore.get(media[6:]) + except: + raise logoerror("#nomedia") + # check to see if it is a movie + # print dsobject.file_path + # print "object has file suffix of: " + dsobject.file_path[-4:] + if dsobject.file_path[-4:] == '.ogv' or \ + dsobject.file_path[-4:] == '.vob' or \ + dsobject.file_path[-4:] == '.mp4' or \ + dsobject.file_path[-4:] == '.wmv' or \ + dsobject.file_path[-4:] == '.mov': + # print "playing movie x:" + str(x) + " y:" + str(y) + " w:" + \ + # str(w) + " h:" + str(h) + play_dsobject(lc, dsobject, int(x), int(y), int(w), int(h)) else: - errormsg = "%s %s" % (_("I don't know how to"), _(token.name)) - raise logoerror(errormsg) - - def no_args_check(self): - if self.iline and self.iline[0] is not self.symnothing: - return - raise logoerror("#noinput") - - # - # Primitives - # - - def prim_clear(self): - stop_media(self) - self.tw.canvas.clearscreen() - - def prim_start(self): - if self.tw.running_sugar: - self.tw.activity.recenter() - - def prim_wait(self, time): - self.tw.active_turtle.show() - endtime = millis()+self.an_int(time*1000) - while millis()<endtime: - yield True - self.tw.active_turtle.hide() - self.ireturn() - yield True - - def prim_repeat(self, num, list): - num = self.an_int(num) - for i in range(num): - self.icall(self.evline, list[:]) - yield True - if self.procstop: - break - self.ireturn() - yield True + pixbuf = get_pixbuf_from_journal(dsobject, int(w), int(h)) + if pixbuf != None: + draw_pixbuf(lc.tw.turtle, pixbuf, 0, 0, int(x), int(y), \ + int(w), int(h)) + dsobject.destroy() - def prim_bullet(self, list): # Depreciated block style - self.show_bullets(list) - self.ireturn() - yield True +def get_pixbuf_from_journal(dsobject,w,h): + try: + pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(dsobject.file_path, \ + int(w),int(h)) + except: + try: + # print "Trying preview..." + pixbufloader = \ + gtk.gdk.pixbuf_loader_new_with_mime_type('image/png') + pixbufloader.set_size(min(300,int(w)),min(225,int(h))) + pixbufloader.write(dsobject.metadata['preview']) + pixbufloader.close() + pixbuf = pixbufloader.get_pixbuf() + except: + # print "No preview" + pixbuf = None + return pixbuf - def prim_list(self, list): - self.show_list(list) - self.ireturn() - yield True +def show_description(lc, media, x, y, w, h): + if media == "" or media[6:] == "": + # raise logoerror("#nomedia") + pass + elif media[6:] != "None": + try: + dsobject = datastore.get(media[6:]) + draw_text(lc.tw.turtle, \ + dsobject.metadata['description'],int(x),int(y), \ + lc.body_height, int(w)) + dsobject.destroy() + except: + print "no description?" + +def draw_title(lc,title,x,y): + draw_text(lc.tw.turtle,title,int(x),int(y),lc.title_height, \ + lc.tw.turtle.width-x) + +def calc_position(lc,t): + w,h,x,y,dx,dy = lc.templates[t] + x *= lc.tw.turtle.width + y *= lc.tw.turtle.height + w *= (lc.tw.turtle.width-x) + h *= (lc.tw.turtle.height-y) + dx *= w + dy *= h + return(w,h,x,y,dx,dy) + +# title, one image, and description +def show_template1(lc, title, media): + w,h,xo,yo,dx,dy = calc_position(lc,'tp1') + x = -(lc.tw.turtle.width/2)+xo + y = lc.tw.turtle.height/2 + setxy(lc.tw.turtle, x, y) + # save the text size so we can restore it later + save_text_size = lc.tw.textsize + # set title text + settextsize(lc.tw.turtle, lc.title_height) + show(lc,title) + # calculate and set scale for media blocks + myscale = 45 * (lc.tw.turtle.height - lc.title_height*2) \ + / lc.tw.turtle.height + set_scale(lc,myscale) + # set body text size + settextsize(lc.tw.turtle, lc.body_height) + # render media object + y -= int(lc.title_height*2*lc.tw.lead) # leave some space below the title + setxy(lc.tw.turtle, x, y) + show(lc, media) + x = 0 + setxy(lc.tw.turtle, x, y) + show(lc, media.replace("media_","descr_")) + # restore text size + settextsize(lc.tw.turtle, save_text_size) + +# title, two images (horizontal), two descriptions +def show_template2(lc, title, media1, media2): + w,h,xo,yo,dx,dy = calc_position(lc,'tp2') + x = -(lc.tw.turtle.width/2)+xo + y = lc.tw.turtle.height/2 + setxy(lc.tw.turtle, x, y) + # save the text size so we can restore it later + save_text_size = lc.tw.textsize + # set title text + settextsize(lc.tw.turtle, lc.title_height) + show(lc,title) + # calculate and set scale for media blocks + myscale = 45 * (lc.tw.turtle.height - lc.title_height*2)/lc.tw.turtle.height + set_scale(lc,myscale) + # set body text size + settextsize(lc.tw.turtle, lc.body_height) + # render four quadrents + y -= int(lc.title_height*2*lc.tw.lead) # leave some space below the title + setxy(lc.tw.turtle, x, y) + show(lc, media1) + x = 0 + setxy(lc.tw.turtle, x, y) + show(lc, media2) + y = -lc.title_height + setxy(lc.tw.turtle, x, y) + show(lc, media2.replace("media_","descr_")) + x = -(lc.tw.turtle.width/2)+xo + setxy(lc.tw.turtle, x, y) + show(lc, media1.replace("media_","descr_")) + # restore text size + settextsize(lc.tw.turtle, save_text_size) + +# title and seven bullets +def show_template3(lc, title, s1, s2, s3, s4, s5, s6, s7): + w,h,xo,yo,dx,dy = calc_position(lc,'tp3') + x = -(lc.tw.turtle.width/2)+xo + y = lc.tw.turtle.height/2 + setxy(lc.tw.turtle, x, y) + # save the text size so we can restore it later + save_text_size = lc.tw.textsize + # set title text + settextsize(lc.tw.turtle, lc.title_height) + show(lc,title) + # set body text size + settextsize(lc.tw.turtle, lc.bullet_height) + y -= int(lc.title_height*2*lc.tw.lead) # leave some space below the title + setxy(lc.tw.turtle, x, y) + show(lc, s1) + y -= int(lc.bullet_height*2*lc.tw.lead) + setxy(lc.tw.turtle, x, y) + show(lc, s2) + y -= int(lc.bullet_height*2*lc.tw.lead) + setxy(lc.tw.turtle, x, y) + show(lc, s3) + y -= int(lc.bullet_height*2*lc.tw.lead) + setxy(lc.tw.turtle, x, y) + show(lc, s4) + y -= int(lc.bullet_height*2*lc.tw.lead) + setxy(lc.tw.turtle, x, y) + show(lc, s5) + y -= int(lc.bullet_height*2*lc.tw.lead) + setxy(lc.tw.turtle, x, y) + show(lc, s6) + y -= int(lc.bullet_height*2*lc.tw.lead) + setxy(lc.tw.turtle, x, y) + show(lc, s7) + # restore text size + settextsize(lc.tw.turtle, save_text_size) + +# title, two images (vertical), two desciptions +def show_template6(lc, title, media1, media2): + w,h,xo,yo,dx,dy = calc_position(lc,'tp6') + x = -(lc.tw.turtle.width/2)+xo + y = lc.tw.turtle.height/2 + setxy(lc.tw.turtle, x, y) + # save the text size so we can restore it later + save_text_size = lc.tw.textsize + # set title text + settextsize(lc.tw.turtle, lc.title_height) + show(lc,title) + # calculate and set scale for media blocks + myscale = 45 * (lc.tw.turtle.height - lc.title_height*2)/lc.tw.turtle.height + set_scale(lc,myscale) + # set body text size + settextsize(lc.tw.turtle, lc.body_height) + # render four quadrents + y -= int(lc.title_height*2*lc.tw.lead) # leave some space below the title + setxy(lc.tw.turtle, x, y) + show(lc, media1) + x = 0 + setxy(lc.tw.turtle, x, y) + show(lc, media1.replace("media_","descr_")) + y = -lc.title_height + setxy(lc.tw.turtle, x, y) + show(lc, media2.replace("media_","descr_")) + x = -(lc.tw.turtle.width/2)+xo + setxy(lc.tw.turtle, x, y) + show(lc, media2) + # restore text size + settextsize(lc.tw.turtle, save_text_size) + +# title and four images +def show_template7(lc, title, media1, media2, media3, media4): + w,h,xo,yo,dx,dy = calc_position(lc,'tp7') + x = -(lc.tw.turtle.width/2)+xo + y = lc.tw.turtle.height/2 + setxy(lc.tw.turtle, x, y) + # save the text size so we can restore it later + save_text_size = lc.tw.textsize + # set title text + settextsize(lc.tw.turtle, lc.title_height) + show(lc,title) + # calculate and set scale for media blocks + myscale = 45 * (lc.tw.turtle.height - lc.title_height*2)/lc.tw.turtle.height + set_scale(lc,myscale) + # set body text size + settextsize(lc.tw.turtle, lc.body_height) + # render four quadrents + y -= int(lc.title_height*2*lc.tw.lead) # leave some space below the title + setxy(lc.tw.turtle, x, y) + show(lc, media1) + x = 0 + setxy(lc.tw.turtle, x, y) + show(lc, media2) + y = -lc.title_height + setxy(lc.tw.turtle, x, y) + show(lc, media4) + x = -(lc.tw.turtle.width/2)+xo + setxy(lc.tw.turtle, x, y) + show(lc, media3) + # restore text size + settextsize(lc.tw.turtle, save_text_size) + +# title, one media object +def show_template8(lc, title, media1): + w,h,xo,yo,dx,dy = calc_position(lc,'tp7') + x = -(lc.tw.turtle.width/2)+xo + y = lc.tw.turtle.height/2 + setxy(lc.tw.turtle, x, y) + # save the text size so we can restore it later + save_text_size = lc.tw.textsize + # set title text + settextsize(lc.tw.turtle, lc.title_height) + show(lc,title) + # calculate and set scale for media blocks + myscale = 90 * (lc.tw.turtle.height - lc.title_height*2) \ + / lc.tw.turtle.height + set_scale(lc,myscale) + # set body text size + settextsize(lc.tw.turtle, lc.body_height) + # render media object + y -= int(lc.title_height*2*lc.tw.lead) # leave some space below the title + setxy(lc.tw.turtle, x, y) + show(lc, media1) + # restore text size + settextsize(lc.tw.turtle, save_text_size) + +# image only (at current x,y) +def insert_image(lc, media, center): + w = (lc.tw.turtle.width * lc.scale)/100 + h = (lc.tw.turtle.height * lc.scale)/100 + # convert from Turtle coordinates to screen coordinates + x = lc.tw.turtle.width/2+int(lc.tw.turtle.xcor) + y = lc.tw.turtle.height/2-int(lc.tw.turtle.ycor) + if center == True: + x -= w/2 + y -= h/2 + if media[0:5] == 'media': + show_picture(lc, media, x, y, w, h) + +# description text only (at current x,y) +def insert_desc(lc, media): + w = (lc.tw.turtle.width * lc.scale)/100 + h = (lc.tw.turtle.height * lc.scale)/100 + # convert from Turtle coordinates to screen coordinates + x = lc.tw.turtle.width/2+int(lc.tw.turtle.xcor) + y = lc.tw.turtle.height/2-int(lc.tw.turtle.ycor) + if media[0:5] == 'descr': + show_description(lc, media, x, y, w, h) + +def set_scale(lc, x): + lc.scale = x + +# need to fix export logo to map show to write +def show(lc, string, center=False): + # convert from Turtle coordinates to screen coordinates + x = lc.tw.turtle.width/2+int(lc.tw.turtle.xcor) + y = lc.tw.turtle.height/2-int(lc.tw.turtle.ycor) + if type(string) == str or type(string) == unicode: + if string == "media_None": + pass + elif string[0:6] == 'media_': + insert_image(lc, string, center) + elif string[0:6] == 'descr_': + insert_desc(lc, string) + elif string[0:6] == 'audio_': + play_sound(lc, string) + else: + if center == True: + y -= lc.tw.textsize + draw_text(lc.tw.turtle,string,x,y,lc.tw.textsize,lc.tw.turtle.width-x) + elif type(string) == float or type(string) == int: + string = round_int(string) + if center == True: + y -= lc.tw.textsize + draw_text(lc.tw.turtle,string,x,y,lc.tw.textsize,lc.tw.turtle.width-x) + +# audio only +def play_sound(lc, audio): + play_audio(lc, audio) + +def clear(lc): + stop_media(lc) + clearscreen(lc.tw.turtle) + +def write(lc, string, fsize): + # convert from Turtle coordinates to screen coordinates + x = lc.tw.turtle.width/2+int(lc.tw.turtle.xcor) + y = lc.tw.turtle.height/2-int(lc.tw.turtle.ycor) + draw_text(lc.tw.turtle,string,x,y-15,int(fsize),lc.tw.turtle.width) + +def hideblocks(lc): + from tawindow import hideshow_button + lc.tw.hide = False # force hide + hideshow_button(lc.tw) + for i in lc.tw.selbuttons: + hide(i) + if hasattr(lc.tw,"activity"): + lc.tw.activity.do_hide() + +def doevalstep(lc): + starttime = millis() + try: + while (millis()-starttime)<120: + try: + lc.step.next() + except StopIteration: + setlayer(lc.tw.turtle.spr,630) + return False + except logoerror, e: + showlabel(lc, str(e)[1:-1]) + setlayer(lc.tw.turtle.spr,630) + return False + return True + +def icall(lc, fcn, *args): + lc.istack.append(lc.step) + lc.step = fcn(lc, *(args)) + +def ireturn(lc, res=None): + lc.step = lc.istack.pop() + lc.iresult = res + +def ijmp(lc, fcn, *args): + lc.step = fcn(lc,*(args)) + +def heap_print(lc): + showlabel(lc,lc.heap) + +def status_print(lc,n): + if type(n) == str or type(n) == unicode: + # show title for Journal entries + if n[0:6] == 'media_': + try: + dsobject = datastore.get(n[6:]) + showlabel(lc, dsobject.metadata['title']) + dsobject.destroy() + except: + showlabel(lc,n) + else: + showlabel(lc,n) + elif type(n) == int: + showlabel(lc,n) + else: + showlabel(lc, round_int(n)) - def prim_myfunc(self, list): - new_list = [self.intern('myfunction')] - new_list.append(list) - self.icall(self.evline, new_list) - yield True - self.ireturn() - yield True +def kbinput(lc): + if len(lc.tw.keypress) == 1: + lc.keyboard = ord(lc.tw.keypress[0]) + else: + try: + lc.keyboard = {'Escape': 27, 'space': 32, ' ': 32, 'Return': 13, \ + 'KP_Up': 2, 'KP_Down': 4, 'KP_Left': 1, \ + 'KP_Right': 3,}[lc.tw.keypress] + except: + lc.keyboard = 0 + lc.tw.keypress = "" + +def showlabel(lc,label): + if label=='#nostack': + shp = 'nostack' + label='' + elif label=='#noinput': + shp = 'noinput' + label='' + elif label=='#emptyheap': + shp = 'emptyheap' + label='' + elif label=='#emptybox': + shp = 'emptybox' + label=' '+lc.nobox + elif label=='#nomedia': + shp = 'nomedia' + label='' + elif label=='#nocode': + shp = 'nocode' + label='' + elif label=='#syntaxerror': + shp = 'syntaxerror' + label='' + elif label=='#overflowerror': + shp = 'overflowerror' + label='' + else: + shp = 'status' + setshape(lc.tw.status_spr, lc.tw.status_shapes[shp]) + setlabel(lc.tw.status_spr, label) + setlayer(lc.tw.status_spr, 710) - def myfunction(self, list): - y = myfunc(list[0], list[1:]) - if y == None: - raise logoerror("#syntaxerror") - stop_logo(self.tw) - else: - return y - - def prim_forever(self, list): - while True: - self.icall(self.evline, list[:]) - yield True - if self.procstop: - break - self.ireturn() - yield True +def stop_logo(tw): + tw.step_time = 0 + tw.lc.step = just_stop() - def prim_if(self, bool, list): - if bool: - self.icall(self.evline, list[:]) - yield True - self.ireturn() - yield True +def just_stop(): yield False - def prim_ifelse(self, bool, list1, list2): - if bool: - self.ijmp(self.evline, list1[:]) - yield True - else: - self.ijmp(self.evline, list2[:]) - yield True - - def prim_opar(self, val): - self.iline.pop(0) - return val - - def prim_define(self, name, body): - if type(name) is not symtype: - name = self.intern(name) - name.nargs, name.fcn = 0, body - name.rprim = True - - def prim_stack(self, x): - if type(convert(x, float, False)) == type(float): - if int(float(x)) == x: - x = int(x) - if (not self.stacks.has_key('stack3'+str(x))) or\ - self.stacks['stack3'+str(x)] is None: - raise logoerror("#nostack") - self.icall(self.evline, self.stacks['stack3'+str(x)][:]) - yield True - self.procstop = False - self.ireturn() - yield True +def setbox(lc, name,val): lc.boxes[name]=val - def prim_stack1(self): - if self.stacks['stack1'] is None: - raise logoerror("#nostack") - self.icall(self.evline, self.stacks['stack1'][:]) - yield True - self.procstop = False - self.ireturn() - yield True - - def prim_stack2(self): - if self.stacks['stack2'] is None: - raise logoerror("#nostack") - self.icall(self.evline, self.stacks['stack2'][:]) - yield True - self.procstop = False - self.ireturn() - yield True +def push_heap(lc,val): lc.heap.append(val) - def prim_stopstack(self): - self.procstop = True - - def prim_print_heap(self): - self.tw.showlabel('status', self.heap) - - def an_int(self, n): - if type(n) == int: - return n - elif type(n) == float: - return int(n) - elif type(n) == str: - return int(ord(n[0])) - else: - raise logoerror("%s doesn't like %s as input" \ - % (self.cfun.name, str(n))) +def pop_heap(lc): + try: return lc.heap.pop(-1) + except: raise logoerror ("#emptyheap") - def box(self, x): - if type(convert(x, float, False)) == float: - if int(float(x)) == x: - x = int(x) - try: - return self.boxes['box3'+str(x)] - except: - raise logoerror("#emptybox") - - def prim_myblock(self, x): - if self.tw.myblock is not None: - try: - y = myfunc_import(self, self.tw.myblock, x) - except: - raise logoerror("#nocode") - else: - raise logoerror("#nocode") - return - - def prim_print(self, n, flag): - if flag and (self.tw.hide or self.tw.step_time == 0): - return - if type(n) == str or type(n) == unicode: - if n[0:6] == 'media_': - try: - if self.tw.running_sugar: - dsobject = datastore.get(n[6:]) - self.tw.showlabel('status', dsobject.metadata['title']) - dsobject.destroy() - else: - self.tw.showlabel('status', n[6:]) - except: - self.tw.showlabel('status', n) - else: - self.tw.showlabel('status', n) - elif type(n) == int: - self.tw.showlabel('status', n) - else: - self.tw.showlabel('status', round_int(n)) - - def prim_kbinput(self): - if len(self.tw.keypress) == 1: - self.keyboard = ord(self.tw.keypress[0]) - else: - try: - self.keyboard = {'Escape': 27, 'space': 32, ' ': 32, - 'Return': 13, \ - 'KP_Up': 2, 'KP_Down': 4, 'KP_Left': 1, \ - 'KP_Right': 3,}[self.tw.keypress] - except: - self.keyboard = 0 - self.tw.keypress = "" +def empty_heap(lc): lc.heap = [] - def prim_setbox(self, name, x, val): - if x is None: - self.boxes[name]=val - else: - if type(convert(x, float, False)) == type(float): - if int(float(x)) == x: - x = int(x) - self.boxes[name+str(x)]=val +def tyo(n): print n - def prim_push(self, val): - self.heap.append(val) +def millis(): return int(clock()*1000) - def prim_pop(self): - try: - return self.heap.pop(-1) - except: - raise logoerror ("#emptyheap") - - def empty_heap(self): - self.heap = [] - - def save_picture(self, name): - self.tw.save_as_image(name) - - def show_list(self, sarray): - x = self.tw.canvas.xcor/self.tw.coord_scale - y = self.tw.canvas.ycor/self.tw.coord_scale - for s in sarray: - self.tw.canvas.setxy(x, y) - self.show(s) - y -= int(self.bullet_height*2*self.tw.lead) - - def set_scale(self, x): - self.scale = x - - # need to fix export logo to map show to write - def show(self, string, center=False): - # convert from Turtle coordinates to screen coordinates - x = self.tw.canvas.width/2+int(self.tw.canvas.xcor) - y = self.tw.canvas.height/2-int(self.tw.canvas.ycor) - if type(string) == str or type(string) == unicode: - if string == "media_None": - pass - elif string[0:6] == 'media_': - self.insert_image(string, center) - elif string[0:6] == 'descr_': - self.insert_desc(string) - elif string[0:6] == 'audio_': - self.play_sound(string) - else: - if center is True: - y -= self.tw.textsize - self.tw.canvas.draw_text(string,x,y,self.tw.textsize, - self.tw.canvas.width-x) - elif type(string) == float or type(string) == int: - string = round_int(string) - if center is True: - y -= self.tw.textsize - self.tw.canvas.draw_text(string, x, y, self.tw.textsize, - self.tw.canvas.width-x) - - def play_sound(self, audio): - if audio == "" or audio[6:] == "": - raise logoerror("#nomedia") - if self.tw.running_sugar: - if audio[6:] != "None": - try: - dsobject = datastore.get(audio[6:]) - play_audio(self, dsobject.file_path) - except: - print "Couldn't open id: " + str(audio[6:]) - else: - play_audio(self, audio[6:]) - def show_picture(self, media, x, y, w, h): - if media == "" or media[6:] == "": - pass - elif media[6:] is not "None": - pixbuf = None - if self.tw.running_sugar: - try: - dsobject = datastore.get(media[6:]) - if movie_media_type(dsobject.file_path): - play_movie_from_file(self, dsobject.file_path, - int(x), int(y), int(w), int(h)) - else: - pixbuf = get_pixbuf_from_journal(dsobject, - int(w), int(h)) - dsobject.destroy() - except: - # Maybe it is a pathname instead. - try: - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( - media[6:], int(w), int(h)) - except: - self.tw.showlabel('nojournal', media[6:]) - print "Couldn't open Journal object %s" % (media[6:]) - else: - try: - if movie_media_type(media): - play_movie_from_file(self, media[6:], int(x), int(y), - int(w), int(h)) - else: - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( - media[6:], int(w), int(h)) - except: - self.tw.showlabel('nofile', media[6:]) - print "Couldn't open media object %s" % (media[6:]) - if pixbuf is not None: - self.tw.canvas.draw_pixbuf(pixbuf, 0, 0, int(x), int(y), - int(w), int(h)) - - def show_description(self, media, x, y, w, h): - if media == "" or media[6:] == "": - return - elif media[6:] is not "None": - text = None - if self.tw.running_sugar: - try: - dsobject = datastore.get(media[6:]) - text = str(dsobject.metadata['description']) - dsobject.destroy() - except: - print "no description in %s" % (media[6:]) - else: - try: - f = open(media[6:], 'r') - text = f.read() - f.close() - except: - print "no text in %s?" % (media[6:]) - if text is not None: - print "text: %s" % (text) - self.tw.canvas.draw_text(text, int(x), int(y), - self.body_height, int(w)) - - def draw_title(self, title, x, y): - self.tw.canvas.draw_text(title,int(x),int(y),self.title_height, - self.tw.canvas.width-x) - # image only (at current x,y) - def insert_image(self, media, center): - w = (self.tw.canvas.width * self.scale)/100 - h = (self.tw.canvas.height * self.scale)/100 - # convert from Turtle coordinates to screen coordinates - x = self.tw.canvas.width/2+int(self.tw.canvas.xcor) - y = self.tw.canvas.height/2-int(self.tw.canvas.ycor) - if center is True: - x -= w/2 - y -= h/2 - if media[0:5] == 'media': - self.show_picture(media, x, y, w, h) - - # description text only (at current x,y) - def insert_desc(self, media): - w = (self.tw.canvas.width * self.scale)/100 - h = (self.tw.canvas.height * self.scale)/100 - # convert from Turtle coordinates to screen coordinates - x = self.tw.canvas.width/2+int(self.tw.canvas.xcor) - y = self.tw.canvas.height/2-int(self.tw.canvas.ycor) - if media[0:5] == 'descr': - self.show_description(media, x, y, w, h) - - """ - Depreciated block methods - """ - # title, one image, and description - def show_template1x1(self, title, media): - w,h,xo,yo,dx,dy = self.tw.calc_position('t1x1') - x = -(self.tw.canvas.width/2)+xo - y = self.tw.canvas.height/2 - self.tw.canvas.setxy(x, y) - # save the text size so we can restore it later - save_text_size = self.tw.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self.show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height*2) \ - / self.tw.canvas.height - self.set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render media object - # leave some space below the title - y -= int(self.title_height*2*self.tw.lead) - self.tw.canvas.setxy(x, y) - self.show(media) - if self.tw.running_sugar: - x = 0 - self.tw.canvas.setxy(x, y) - self.show(media.replace("media_","descr_")) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - # title, two images (horizontal), two descriptions - def show_template2x1(self, title, media1, media2): - w,h,xo,yo,dx,dy = self.tw.calc_position('t2x1') - x = -(self.tw.canvas.width/2)+xo - y = self.tw.canvas.height/2 - self.tw.canvas.setxy(x, y) - # save the text size so we can restore it later - save_text_size = self.tw.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self.show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height*2)/\ - self.tw.canvas.height - self.set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render four quadrents - # leave some space below the title - y -= int(self.title_height*2*self.tw.lead) - self.tw.canvas.setxy(x, y) - self.show(media1) - x = 0 - self.tw.canvas.setxy(x, y) - self.show(media2) - y = -self.title_height - if self.tw.running_sugar: - self.tw.canvas.setxy(x, y) - self.show(media2.replace("media_","descr_")) - x = -(self.tw.canvas.width/2)+xo - self.tw.canvas.setxy(x, y) - self.show(media1.replace("media_","descr_")) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - # title and varible number of bullets - def show_bullets(self, sarray): - w,h,xo,yo,dx,dy = self.tw.calc_position('bullet') - x = -(self.tw.canvas.width/2)+xo - y = self.tw.canvas.height/2 - self.tw.canvas.setxy(x, y) - # save the text size so we can restore it later - save_text_size = self.tw.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self.show(sarray[0]) - # set body text size - self.tw.canvas.settextsize(self.bullet_height) - # leave some space below the title - y -= int(self.title_height*2*self.tw.lead) - for s in sarray[1:]: - self.tw.canvas.setxy(x, y) - self.show(s) - y -= int(self.bullet_height*2*self.tw.lead) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - # title, two images (vertical), two desciptions - def show_template1x2(self, title, media1, media2): - w,h,xo,yo,dx,dy = self.tw.calc_position('t1x2') - x = -(self.tw.canvas.width/2)+xo - y = self.tw.canvas.height/2 - self.tw.canvas.setxy(x, y) - # save the text size so we can restore it later - save_text_size = self.tw.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self.show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height*2)/\ - self.tw.canvas.height - self.set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render four quadrents - # leave some space below the title - y -= int(self.title_height*2*self.tw.lead) - self.tw.canvas.setxy(x, y) - self.show(media1) - if self.tw.running_sugar: - x = 0 - self.tw.canvas.setxy(x, y) - self.show(media1.replace("media_","descr_")) - y = -self.title_height - self.tw.canvas.setxy(x, y) - self.show(media2.replace("media_","descr_")) - x = -(self.tw.canvas.width/2)+xo - self.tw.canvas.setxy(x, y) - self.show(media2) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - # title and four images - def show_template2x2(self, title, media1, media2, media3, media4): - w,h,xo,yo,dx,dy = self.tw.calc_position('t2x2') - x = -(self.tw.canvas.width/2)+xo - y = self.tw.canvas.height/2 - self.tw.canvas.setxy(x, y) - # save the text size so we can restore it later - save_text_size = self.tw.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self.show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height*2)/\ - self.tw.canvas.height - self.set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render four quadrents - # leave some space below the title - y -= int(self.title_height*2*self.tw.lead) - self.tw.canvas.setxy(x, y) - self.show(media1) - x = 0 - self.tw.canvas.setxy(x, y) - self.show(media2) - y = -self.title_height - self.tw.canvas.setxy(x, y) - self.show(media4) - x = -(self.tw.canvas.width/2)+xo - self.tw.canvas.setxy(x, y) - self.show(media3) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - # title, one media object - def show_template1x1a(self, title, media1): - w,h,xo,yo,dx,dy = self.tw.calc_position('t1x1a') - x = -(self.tw.canvas.width/2)+xo - y = self.tw.canvas.height/2 - self.tw.canvas.setxy(x, y) - # save the text size so we can restore it later - save_text_size = self.tw.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self.show(title) - # calculate and set scale for media blocks - myscale = 90 * (self.tw.canvas.height - self.title_height*2) /\ - self.tw.canvas.height - self.set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render media object - # leave some space below the title - y -= int(self.title_height*2*self.tw.lead) - self.tw.canvas.setxy(x, y) - self.show(media1) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - def write(self, string, fsize): - # convert from Turtle coordinates to screen coordinates - x = self.tw.canvas.width/2+int(self.tw.canvas.xcor) - y = self.tw.canvas.height/2-int(self.tw.canvas.ycor) - self.tw.canvas.draw_text(string,x,y-15,int(fsize),self.tw.canvas.width) diff --git a/tawindow.py b/tawindow.py index f33d8b6..c626fb9 100644 --- a/tawindow.py +++ b/tawindow.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- #Copyright (c) 2007, Playful Invention Company -#Copyright (c) 2008-10, Walter Bender -#Copyright (c) 2009-10 Raúl Gutiérrez Segalés +#Copyright (c) 2008-9, Walter Bender +#Copyright (c) 2009, Raúl Gutiérrez Segalés #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal @@ -21,13 +21,6 @@ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #THE SOFTWARE. - -# TODO: -# - better comments! -# - many methods could have their logic simplified! -# - verbose flag should be in the scope of the object instance - - import pygtk pygtk.require('2.0') import gtk @@ -36,2540 +29,892 @@ import gobject import os import os.path import time + +# Import from Journal for these blocks +importblocks = ['audiooff', 'descriptionoff','journal'] + +class taWindow: pass + from math import atan2, pi DEGTOR = 2*pi/360 -from gettext import gettext as _ +from taarduino import * +from tasetup import * +from tasprites import * +from talogo import * +from taturtle import * +from taproject import * try: from sugar.graphics.objectchooser import ObjectChooser - from sugar.datastore import datastore - from sugar import profile -except ImportError: +except: pass -from taconstants import * -from talogo import LogoCode, stop_logo, convert, str_to_num -from tacanvas import TurtleGraphics -from tablock import Blocks, Block -from taturtle import Turtles, Turtle -from tautils import magnitude, get_load_name, get_save_name, data_from_file,\ - data_to_file, round_int, get_id, get_pixbuf_from_journal,\ - movie_media_type, audio_media_type, image_media_type,\ - save_picture, calc_image_size -from tasprite_factory import SVG, svg_str_to_pixbuf, svg_from_file -from sprites import Sprites, Sprite - -""" -Dock tests -""" - -def numeric_arg(value): - if type(convert(value, float)) is float: - return True - return False - -def zero_arg(value): - if numeric_arg(value): - if convert(value, float) == 0: - return True - return False - -def neg_arg(value): - if numeric_arg(value): - if convert(value, float) < 0: - return True - return False - -""" -TurtleArt Window class abstraction -""" -class TurtleArtWindow(): - - # Time out for triggering help - timeout_tag = [0] - - def __init__(self, win, path, lang, parent=None, mycolors=None): - self._setup_initial_values(win, path, lang, parent, mycolors) - self._setup_misc() - self._show_toolbar_palette(0, False) - - def _setup_initial_values(self, win, path, lang, parent, mycolors): - self.window = win - self.path = os.path.join(path, 'images') - self.load_save_folder = os.path.join(path, 'samples') - self.save_folder = None - self.save_file_name = None - self.window.set_flags(gtk.CAN_FOCUS) - self.width = gtk.gdk.screen_width() - self.height = gtk.gdk.screen_height() - if parent is not None: - parent.show_all() - self.running_sugar = True - else: - self.window.show_all() - self.running_sugar = False - self._setup_events() - self.keypress = "" - self.keyvalue = 0 - self.dead_key = "" - self.area = self.window.window - self.gc = self.area.new_gc() - if self._OLPC_XO_1(): - self.lead = 1.0 - self.scale = 0.67 - else: - self.lead = 1.0 - self.scale = 1.0 - self.block_scale = BLOCK_SCALE - self.trash_scale = 0.5 - self.cm = self.gc.get_colormap() - self.rgb = [255,0,0] - self.bgcolor = self.cm.alloc_color('#fff8de') - self.msgcolor = self.cm.alloc_color('black') - self.fgcolor = self.cm.alloc_color('red') - self.textcolor = self.cm.alloc_color('blue') - self.textsize = 32 - self.myblock = None - self.nop = 'nop' - self.loaded = 0 - self.step_time = 0 - self.hide = False - self.palette = True - self.coord_scale = 1 - self.buddies = [] - self.saved_string = '' - self.dx = 0 - self.dy = 0 - self.media_shapes = {} - self.cartesian = False - self.polar = False - self.overlay_shapes = {} - self.status_spr = None - self.status_shapes = {} - self.toolbar_spr = None - self.palette_sprs = [] - self.palettes = [] - self.palette_button = [] - self.orientation = 0 - self.trash_index = PALETTE_NAMES.index('trash') - self.trash_stack = [] - self.selected_palette = None - self.previous_palette = None - self.selectors = [] - self.selected_selector = None - self.previous_selector = None - self.selector_shapes = [] - self.selected_blk = None - self.selected_spr = None - self.drag_group = None - self.drag_turtle = 'move', 0, 0 - self.drag_pos = 0, 0 - self.block_list = Blocks(self.scale) - self.sprite_list = Sprites(self.window, self.area, self.gc) - self.turtles = Turtles(self.sprite_list) - if mycolors == None: - Turtle(self.turtles, 1) - else: - Turtle(self.turtles, 1, mycolors.split(',')) - self.active_turtle = self.turtles.get_turtle(1) - self.selected_turtle = None - self.canvas = TurtleGraphics(self, self.width, self.height) - self.titlex = -(self.canvas.width*TITLEXY[0])/(self.coord_scale*2) - self.leftx = -(self.canvas.width*TITLEXY[0])/(self.coord_scale*2) - self.rightx = 0 - self.titley = (self.canvas.height*TITLEXY[1])/(self.coord_scale*2) - self.topy = (self.canvas.height*(TITLEXY[1]-0.125))/(self.coord_scale*2) - self.bottomy = 0 - self.lc = LogoCode(self) - - """ - Register the events we listen to. - """ - def _setup_events(self): - self.window.add_events(gtk.gdk.BUTTON_PRESS_MASK) - self.window.add_events(gtk.gdk.BUTTON_RELEASE_MASK) - self.window.add_events(gtk.gdk.POINTER_MOTION_MASK) - self.window.add_events(gtk.gdk.KEY_PRESS_MASK) - self.window.connect("expose-event", self._expose_cb) - self.window.connect("button-press-event", self._buttonpress_cb) - self.window.connect("button-release-event", self._buttonrelease_cb) - self.window.connect("motion-notify-event", self._move_cb) - self.window.connect("key_press_event", self._keypress_cb) - - """ - Misc. sprites for status, overlays, etc. - """ - def _setup_misc(self): - # media blocks get positioned into other blocks - for name in MEDIA_SHAPES: - if name[0:7] == 'journal' and not self.running_sugar: - filename = 'file'+name[7:] - else: - filename = name - self.media_shapes[name] = \ - svg_str_to_pixbuf(svg_from_file("%s/%s.svg" % ( - self.path, filename))) - - for i, name in enumerate(STATUS_SHAPES): - self.status_shapes[name] = svg_str_to_pixbuf(svg_from_file( - "%s/%s.svg" % (self.path, name))) - self.status_spr = Sprite(self.sprite_list, 0, self.height-200, - self.status_shapes['status']) - self.status_spr.hide() - self.status_spr.type = 'status' - - for name in OVERLAY_SHAPES: - self.overlay_shapes[name] = Sprite(self.sprite_list, - int(self.width/2-600), int(self.height/2-450), - svg_str_to_pixbuf(svg_from_file( - "%s/%s.svg" % (self.path, name)))) - self.overlay_shapes[name].hide() - self.overlay_shapes[name].type = 'overlay' - - """ - Is a chattube available for sharing? - """ - def _sharing(self): - if self.running_sugar and hasattr(self.activity, 'chattube') and\ - self.activity.chattube is not None: - return True - return False +from tahoverhelp import * +from gettext import gettext as _ - """ - Is the an OLPC XO-1? - """ - def _OLPC_XO_1(self): - return os.path.exists('/etc/olpc-release') or \ - os.path.exists('/sys/power/olpc-pm') - - """ - Repaint - """ - def _expose_cb(self, win, event): - self.sprite_list.redraw_sprites() +# dead key dictionaries +dead_grave = {'A':192,'E':200,'I':204,'O':210,'U':217,'a':224,'e':232,'i':236,\ + 'o':242,'u':249} +dead_acute = {'A':193,'E':201,'I':205,'O':211,'U':218,'a':225,'e':233,'i':237,\ + 'o':243,'u':250} +dead_circumflex = {'A':194,'E':202,'I':206,'O':212,'U':219,'a':226,'e':234,\ + 'i':238,'o':244,'u':251} +dead_tilde = {'A':195,'O':211,'N':209,'U':360,'a':227,'o':245,'n':241,'u':361} +dead_diaeresis = {'A':196,'E':203,'I':207,'O':211,'U':218,'a':228,'e':235,\ + 'i':239,'o':245,'u':252} +dead_abovering = {'A':197,'a':229} + +# Time out for triggering help +timeout_tag = [0] + + +# +# Setup +# + +def twNew(win, path, lang, parent=None): + tw = taWindow() + tw.window = win + tw.path = os.path.join(path,'images') + tw.path_lang = os.path.join(path,'images',lang) + tw.path_en = os.path.join(path,'images/en') # en as fallback + tw.load_save_folder = os.path.join(path,'samples') + tw.save_folder = None + tw.save_file_name = None + win.set_flags(gtk.CAN_FOCUS) + tw.width = gtk.gdk.screen_width() + tw.height = gtk.gdk.screen_height() + # starting from command line + if parent is None: + win.show_all() + # starting from Sugar + else: + parent.show_all() + win.add_events(gtk.gdk.BUTTON_PRESS_MASK) + win.add_events(gtk.gdk.BUTTON_RELEASE_MASK) + win.add_events(gtk.gdk.POINTER_MOTION_MASK) + win.add_events(gtk.gdk.KEY_PRESS_MASK) + win.connect("expose-event", expose_cb, tw) + win.connect("button-press-event", buttonpress_cb, tw) + win.connect("button-release-event", buttonrelease_cb, tw) + win.connect("motion-notify-event", move_cb, tw) + win.connect("key_press_event", keypress_cb, tw) + tw.keypress = "" + tw.keyvalue = 0 + tw.dead_key = "" + tw.area = win.window + tw.gc = tw.area.new_gc() + # on an OLPC-XO-1, there is a scaling factor + if os.path.exists('/etc/olpc-release') or \ + os.path.exists('/sys/power/olpc-pm'): + tw.lead = 1.6 + tw.scale = 1.0 + else: + tw.lead = 1.0 + tw.scale = 1.6 + tw.cm = tw.gc.get_colormap() + tw.rgb = [255,0,0] + tw.bgcolor = tw.cm.alloc_color('#fff8de') + tw.msgcolor = tw.cm.alloc_color('black') + tw.fgcolor = tw.cm.alloc_color('red') + tw.textcolor = tw.cm.alloc_color('blue') + tw.textsize = 32 + tw.sprites = [] + tw.selected_block = None + tw.draggroup = None + prep_selectors(tw) + tw.myblock = None + tw.nop = 'nop' + tw.loaded = 0 + for s in selectors: + setup_selectors(tw,s) + setup_misc(tw) + tw.step_time = 0 + tw.hide = False + tw.palette = True + select_category(tw, tw.selbuttons[0]) + tw.coord_scale = 1 + tw.turtle = tNew(tw,tw.width,tw.height) + tw.lc = lcNew(tw) + tw.buddies = [] + tw.dx = 0 + tw.dy = 0 + tw.cartesian = False + tw.polar = False + tw.spr = None # "currently selected spr" + tw.arduino = TAArduino() + return tw + +# +# Button Press +# + +def buttonpress_cb(win, event, tw): + win.grab_focus() + x, y = xy(event) + button_press(tw, event.get_state()>k.gdk.CONTROL_MASK, x, y) + # if sharing, send button press + if hasattr(tw, 'activity') and \ + hasattr(tw.activity, 'chattube') and tw.activity.chattube is not None: + # print "sending button pressed" + if event.get_state()>k.gdk.CONTROL_MASK is True: + tw.activity._send_event("p:"+str(x)+":"+str(y)+":"+'T') + else: + tw.activity._send_event("p:"+str(x)+":"+str(y)+":"+'F') + return True + +def button_press(tw, mask, x, y, verbose=False): + if verbose: + print "processing remote button press: " + str(x) + " " + str(y) + tw.block_operation = 'click' + if tw.selected_block!=None: + unselect(tw) + else: + setlayer(tw.status_spr,400) + spr = findsprite(tw,(x,y)) + tw.x, tw.y = x,y + tw.dx = 0 + tw.dy = 0 + if spr is None: return True - - - """ - Eraser_button (Always hide status block when clearing the screen.) - """ - def eraser_button(self): - if self.status_spr is not None: - self.status_spr.hide() - self.lc.prim_clear() - self.display_coordinates() - - """ - Run turtle! - """ - def run_button(self, time): - if self.running_sugar: - self.activity.recenter() - # Look for a 'start' block - for blk in self.just_blocks(): - if self._find_start_stack(blk): - self.step_time = time - print "running stack starting from %s" % (blk.name) - self._run_stack(blk) - return - # If there is no 'start' block, run stacks that aren't 'def action' - for blk in self.just_blocks(): - if self._find_block_to_run(blk): - self.step_time = time - print "running stack starting from %s" % (blk.name) - self._run_stack(blk) + if spr.type == "canvas": + return True + elif spr.type == 'selbutton': + select_category(tw,spr) + elif spr.type == 'category': + block_selector_pressed(tw,x,y) + elif spr.type == 'block': + block_pressed(tw,mask,x,y,spr) + elif spr.type == 'turtle': + turtle_pressed(tw,x,y) + tw.spr = spr + +def block_selector_pressed(tw,x,y): + proto = get_proto_from_category(tw,x,y) + if proto==None: return + if proto is not 'hide': + new_block_from_category(tw,proto,x,y) + else: + hideshow_palette(tw,False) + +def hideshow_palette(tw,state): + if state is False: + tw.palette == False + if hasattr(tw,'activity'): + # Use new toolbar design + tw.activity.do_hidepalette() + hide_palette(tw) + else: + tw.palette == True + if hasattr(tw,'activity'): + # Use new toolbar design + tw.activity.do_showpalette() + show_palette(tw) + +def show_palette(tw): + for i in tw.selbuttons: setlayer(i,800) + select_category(tw,tw.selbuttons[0]) + tw.palette = True + +def hide_palette(tw): + for i in tw.selbuttons: hide(i) + setshape(tw.category_spr, tw.hidden_palette_icon) + tw.palette = False + +def get_proto_from_category(tw,x,y): + dx,dy = x-tw.category_spr.x, y-tw.category_spr.y, + pixel = getpixel(tw.current_category.mask,dx,dy) + index = ((pixel%256)>>3)-1 + if index==0: + return 'hide' + index-=1 + if index>len(tw.current_category.blockprotos): + return None + return tw.current_category.blockprotos[index] - """ - Stop button - """ - def stop_button(self): - stop_logo(self) - - """ - Change the icon for user-defined blocks after Python code is loaded. - """ - def set_userdefined(self): - for blk in self.just_blocks(): - if blk.name == 'nop': - x, y = self._calc_image_offset('pythonon', blk.spr) - blk.set_image(self.media_shapes['pythonon'], x, y) - self._resize_skin(blk) - self.nop = 'pythonloaded' - - """ - Enter fulscreen mode - """ - def set_fullscreen(self): - if self.running_sugar: - self.activity.fullscreen() - self.activity.recenter() - - """ - Hide/show button - """ - def hideshow_button(self): - if self.hide is False: - for blk in self.just_blocks(): - blk.spr.hide() - self.hide_palette() - self.hide = True - else: - for blk in self.just_blocks(): - if blk.status != 'collapsed': - blk.spr.set_layer(BLOCK_LAYER) - self.show_palette() - self.hide = False - self.canvas.canvas.inval() - - """ - Hide or show palette - """ - def hideshow_palette(self, state): - if state is False: - self.palette == False - if self.running_sugar: - self.activity.do_hidepalette() - self.hide_palette() - else: - self.palette == True - if self.running_sugar: - self.activity.do_showpalette() - self.show_palette() - - """ - Show palette - """ - def show_palette(self, n=0): - self._show_toolbar_palette(n) - self.palette_button[self.orientation].set_layer(TAB_LAYER) - self.toolbar_spr.set_layer(CATEGORY_LAYER) - self.palette = True - - """ - Hide the palette. - """ - def hide_palette(self): - self._hide_toolbar_palette() - self.palette_button[self.orientation].hide() - self.toolbar_spr.hide() - self.palette = False - - """ - Callback from 'hide blocks' block - """ - def hideblocks(self): - self.hide = False - self.hideshow_button() - if self.running_sugar: - self.activity.do_hide() - - """ - Callback from 'show blocks' block - """ - def showblocks(self): - self.hide = True - self.hideshow_button() - if self.running_sugar: - self.activity.do_show() - - """ - Resize all of the blocks - """ - def resize_blocks(self): - # We need to restore collapsed stacks before resizing. - for b in self.just_blocks(): - if b.status == 'collapsed': - bot = self._find_sandwich_bottom(b) - if self._collapsed(bot): - dy = bot.values[0] - self._restore_stack(self._find_sandwich_top(b)) - bot.values[0] = dy - - # Do the resizing. - for b in self.just_blocks(): - b.rescale(self.block_scale) - for b in self.just_blocks(): - self._adjust_dock_positions(b) - - # Re-collapsed stacks after resizing. - for b in self.just_blocks(): - if self._collapsed(b): - self._collapse_stack(self._find_sandwich_top(b)) - for b in self.just_blocks(): - if b.name == 'sandwichtop': - self._grow_stack_arm(b) - - # Resize the skins on some blocks: media content and Python - for b in self.just_blocks(): - if b.name in BLOCKS_WITH_SKIN: - self._resize_skin(b) - - """ - Show the toolbar palettes, creating them on init_only - """ - def _show_toolbar_palette(self, n, init_only=False): - # Create the selectors the first time through. - if self.selectors == []: - svg = SVG() - x, y = 50, 0 - for i, name in enumerate(PALETTE_NAMES): - a = svg_str_to_pixbuf(svg_from_file("%s/%soff.svg" % ( - self.path, name))) - b = svg_str_to_pixbuf(svg_from_file("%s/%son.svg" % ( - self.path, name))) - self.selector_shapes.append([a,b]) - self.selectors.append(Sprite(self.sprite_list, x, y, a)) - self.selectors[i].type = 'selector' - self.selectors[i].name = name - self.selectors[i].set_layer(TAB_LAYER) - w, h = self.selectors[i].get_dimensions() - x += int(w) - self.palette_sprs.append([None,None]) - - # Create the palette orientation button - self.palette_button.append(Sprite(self.sprite_list, 0, ICON_SIZE, - svg_str_to_pixbuf(svg_from_file( - "%s/palettehorizontal.svg" %(self.path))))) - self.palette_button.append(Sprite(self.sprite_list, 0, ICON_SIZE, - svg_str_to_pixbuf(svg_from_file( - "%s/palettevertical.svg" % (self.path))))) - self.palette_button[0].name = 'orientation' - self.palette_button[1].name = 'orientation' - self.palette_button[0].type = 'palette' - self.palette_button[1].type = 'palette' - self.palette_button[self.orientation].set_layer(TAB_LAYER) - self.palette_button[1-self.orientation].hide() - # Create the toolbar background - self.toolbar_spr = Sprite(self.sprite_list, 0, 0, - svg_str_to_pixbuf(svg.toolbar(self.width, ICON_SIZE))) - self.toolbar_spr.type = 'toolbar' - self.toolbar_spr.set_layer(CATEGORY_LAYER) - - # Create the empty palettes - if len(self.palettes) == 0: - for i in range(len(PALETTES)): - self.palettes.append([]); - - if init_only is True: - return +def select_category(tw, spr): + if hasattr(tw, 'current_category'): + setshape(tw.current_category, tw.current_category.offshape) + setshape(spr, spr.onshape) + tw.current_category = spr + setshape(tw.category_spr,spr.group) - # Hide the previously displayed palette - self._hide_previous_palette() - - self.selected_palette = n - self.previous_palette = self.selected_palette - self.selected_selector = self.selectors[n] - - # Make sure all of the selectors are visible. - self.selectors[n].set_shape(self.selector_shapes[n][1]) - for i in range(len(PALETTES)): - self.selectors[i].set_layer(TAB_LAYER) - - # Show the palette with the current orientation. - if self.palette_sprs[n][self.orientation] is not None: - self.palette_sprs[n][self.orientation].set_layer(CATEGORY_LAYER) - - if self.palettes[n] == []: - # Create 'proto' blocks for each palette entry - for i, name in enumerate(PALETTES[n]): - self.palettes[n].append(Block(self.block_list, - self.sprite_list, name, - 0, 0, 'proto', [], PALETTE_SCALE)) - self.palettes[n][i].spr.set_layer(TAB_LAYER) - self.palettes[n][i].unhighlight() - - # Some proto blocks get a skin. - if name in BOX_STYLE_MEDIA: - self._proto_skin(name+'small', n, i) - elif name[:8] == 'template': - self._proto_skin(name[8:], n, i) - elif name[:7] == 'picture': - self._proto_skin(name[7:], n, i) - elif name == 'nop': - self._proto_skin('pythonsmall', n, i) - - self._layout_palette(n) - for blk in self.palettes[n]: - blk.spr.set_layer(TAB_LAYER) - if n == PALETTE_NAMES.index('trash'): - for blk in self.trash_stack: - for b in self._find_group(blk): - if b.status != 'collapsed': - b.spr.set_layer(TAB_LAYER) - - """ - Hide the toolbar palettes - """ - def _hide_toolbar_palette(self): - self._hide_previous_palette() - # Hide the selectors - for i in range(len(PALETTES)): - self.selectors[i].hide() - self.selected_palette = None - self.previous_palette = None - - """ - Hide just the previously viewed toolbar palette - """ - def _hide_previous_palette(self): - # Hide previous palette - if self.previous_palette is not None: - for i in range(len(PALETTES[self.previous_palette])): - self.palettes[self.previous_palette][i].spr.hide() - self.palette_sprs[self.previous_palette][ - self.orientation].hide() - self.selectors[self.previous_palette].set_shape( - self.selector_shapes[self.previous_palette][0]) - if self.previous_palette == PALETTE_NAMES.index('trash'): - for b in self.trash_stack: - for bb in self._find_group(b): - bb.spr.hide() - - """ - Position prototypes in a horizontal palette. - """ - def _horizontal_layout(self, x, y, blocks): - _max_w = 0 - for b in blocks: - _w, _h = self._width_and_height(b) - if y+_h > PALETTE_HEIGHT+ICON_SIZE: - x += int(_max_w+5) - y = ICON_SIZE+5 - _max_w = 0 - (_bx, _by) = b.spr.get_xy() - _dx = x-_bx - _dy = y-_by - for g in self._find_group(b): - g.spr.move_relative((int(_dx), int(_dy))) - y += int(_h+5) - if _w > _max_w: - _max_w = _w - return x, y, _max_w - - """ - Position prototypes in a vertical palette. - """ - def _vertical_layout(self, x, y, blocks): - _row = [] - _row_w = 0 - _max_h = 0 - for _b in blocks: - _w, _h = self._width_and_height(_b) - if x+_w > PALETTE_WIDTH: - # Recenter row. - _dx = int((PALETTE_WIDTH-_row_w)/2) - for _r in _row: - for _g in self._find_group(_r): - _g.spr.move_relative((_dx, 0)) - _row = [] - _row_w = 0 - x = 5 - y += int(_max_h+5) - _max_h = 0 - _row.append(_b) - _row_w += (5+_w) - (_bx, _by) = _b.spr.get_xy() - _dx = int(x-_bx) - _dy = int(y-_by) - for _g in self._find_group(_b): - _g.spr.move_relative((_dx, _dy)) - x += int(_w+5) - if _h > _max_h: - _max_h = _h - # Recenter last row. - _dx = int((PALETTE_WIDTH-_row_w)/2) - for _r in _row: - for _g in self._find_group(_r): - _g.spr.move_relative((_dx, 0)) - return x, y, _max_h - - """ - Layout prototypes in a palette. - """ - def _layout_palette(self, n): - if n is not None: - if self.orientation == 0: - _x, _y = 20, ICON_SIZE+5 - _x, _y, _max = self._horizontal_layout(_x, _y, self.palettes[n]) - if n == PALETTE_NAMES.index('trash'): - _x, _y, _max = self._horizontal_layout(_x+_max, _y, - self.trash_stack) - _w = _x+_max+25 - if self.palette_sprs[n][self.orientation] is None: - svg = SVG() - self.palette_sprs[n][self.orientation] = Sprite( - self.sprite_list, 0, ICON_SIZE, - svg_str_to_pixbuf(svg.palette(_w, PALETTE_HEIGHT))) - self.palette_sprs[n][self.orientation].type = 'category' - if n == PALETTE_NAMES.index('trash'): - svg = SVG() - self.palette_sprs[n][self.orientation].set_shape( - svg_str_to_pixbuf(svg.palette(_w, PALETTE_HEIGHT))) - else: - _x, _y = 5, ICON_SIZE+15 - _x, _y, _max = self._vertical_layout(_x, _y, self.palettes[n]) - if n == PALETTE_NAMES.index('trash'): - _x, _y, _max = self._vertical_layout(_x, _y+_max, - self.trash_stack) - _h = _y+_max+25-ICON_SIZE - if self.palette_sprs[n][self.orientation] is None: - svg = SVG() - self.palette_sprs[n][self.orientation] =\ - Sprite(self.sprite_list, 0, ICON_SIZE, - svg_str_to_pixbuf(svg.palette(PALETTE_WIDTH, _h))) - self.palette_sprs[n][self.orientation].type = 'category' - if n == PALETTE_NAMES.index('trash'): - svg = SVG() - self.palette_sprs[n][self.orientation].set_shape( - svg_str_to_pixbuf(svg.palette(PALETTE_WIDTH, _h))) - self.palette_sprs[n][self.orientation].set_layer(CATEGORY_LAYER) - - """ - Button press - """ - def _buttonpress_cb(self, win, event): - self.window.grab_focus() - x, y = self._xy(event) - self.button_press(event.get_state()>k.gdk.CONTROL_MASK, x, y) - if self._sharing(): - if event.get_state()>k.gdk.CONTROL_MASK is True: - self.activity._send_event("p:%d:%d:T" % (x, y)) - else: - self.activity._send_event("p:%d:%d:F" % (x, y)) +def new_block_from_category(tw,proto,x,y): + if proto is None: return True - - def button_press(self, mask, x, y, verbose=False): - if verbose: - print "processing remote button press: %d, %d" % (x, y) - self.block_operation = 'click' - - # Unselect things that may have been selected earlier - if self.selected_blk is not None: - self._unselect_block() - self.selected_turtle = None - # Always hide the status layer on a click - if self.status_spr is not None: - self.status_spr.hide() - - # Find out what was clicked - spr = self.sprite_list.find_sprite((x,y)) - self.dx = 0 - self.dy = 0 - if spr is None: - return True - self.selected_spr = spr - - # From the sprite at x, y, look for a corresponding block - blk = self.block_list.spr_to_block(spr) - if blk is not None: - if blk.type == 'block': - self.selected_blk = blk - self._block_pressed(mask, x, y, blk) - elif blk.type == 'trash': - self._restore_from_trash(self.find_top_block(blk)) - elif blk.type == 'proto': - if blk.name == 'restoreall': - self._restore_all_from_trash() - elif blk.name == 'restore': - self._restore_latest_from_trash() - elif blk.name == 'empty': - self._empty_trash() - elif MACROS.has_key(blk.name): - self._new_macro(blk.name, x+20, y+20) - else: - blk.highlight() - self._new_block(blk.name, x, y) - blk.unhighlight() - return True - - # Next, look for a turtle - t = self.turtles.spr_to_turtle(spr) - if t is not None: - self.selected_turtle = t - self.canvas.set_turtle(self.turtles.get_turtle_key(t)) - self._turtle_pressed(x, y) - return True - - # Finally, check for anything else - if hasattr(spr, 'type'): - if spr.type == "canvas": - pass - # spr.set_layer(CANVAS_LAYER) - elif spr.type == 'selector': - self._select_category(spr) - elif spr.type == 'category': - if self._hide_button_hit(spr, x, y): - self.hideshow_palette(False) - elif spr.type == 'palette': - self.orientation = 1-self.orientation - self.palette_button[self.orientation].set_layer(TAB_LAYER) - self.palette_button[1-self.orientation].hide() - self.palette_sprs[self.selected_palette][ - 1-self.orientation].hide() - self._layout_palette(self.selected_palette) - self.show_palette(self.selected_palette) - return True - - """ - Select a category from the toolbar. - """ - def _select_category(self, spr): - i = self.selectors.index(spr) - spr.set_shape(self.selector_shapes[i][1]) - if self.selected_selector is not None: - j = self.selectors.index(self.selected_selector) - if i == j: - return - self.selected_selector.set_shape(self.selector_shapes[j][0]) - self.previous_selector = self.selected_selector - self.selected_selector = spr - self.show_palette(i) - - """ - Put a group of blocks into the trash. - """ - def _put_in_trash(self, blk, x=0, y=0): - self.trash_stack.append(blk) - group = self._find_group(blk) - for b in group: - if b.status == 'collapsed': - # Collapsed stacks are restored for rescaling - # and then recollapsed after they are moved to the trash. - bot = self._find_sandwich_bottom(b) - if self._collapsed(bot): - dy = bot.values[0] - self._restore_stack(self._find_sandwich_top(b)) - bot.values[0] = dy - b.type = 'trash' - b.rescale(self.trash_scale) - blk.spr.move((x,y)) - for b in group: - self._adjust_dock_positions(b) - - # Re-collapsing any stacks we had restored for scaling - for b in group: - if self._collapsed(b): - self._collapse_stack(self._find_sandwich_top(b)) - - # And resize any skins. - for b in group: - if b.name in BLOCKS_WITH_SKIN: - self._resize_skin(b) - - self.show_palette(PALETTE_NAMES.index('trash')) - - """ - Restore all the blocks in the trash can - """ - def _restore_all_from_trash(self): - for b in self.block_list.list: - if b.type == 'trash': - self._restore_from_trash(b) - - """ - Restore latest blocks from the trash can - """ - def _restore_latest_from_trash(self): - if len(self.trash_stack) == 0: - return - self._restore_from_trash(self.trash_stack[len(self.trash_stack)-1]) - - def _restore_from_trash(self, blk): - group = self._find_group(blk) - for b in group: - b.rescale(self.block_scale) - b.spr.set_layer(BLOCK_LAYER) - x,y = b.spr.get_xy() - if self.orientation == 0: - b.spr.move((x,y+PALETTE_HEIGHT+ICON_SIZE)) - else: - b.spr.move((x+PALETTE_WIDTH,y)) - b.type = 'block' - for b in group: - self._adjust_dock_positions(b) - # If the stack had been collapsed before going into the trash, - # collapse it again now. - for b in group: - if self._collapsed(b): - self._collapse_stack(self._find_sandwich_top(b)) - # And resize any skins. - for b in group: - if b.name in BLOCKS_WITH_SKIN: - self._resize_skin(b) - - self.trash_stack.remove(blk) - - """ - Permanently remove blocks in the trash can - """ - def _empty_trash(self): - for b in self.block_list.list: - if b.type == 'trash': - b.type = 'deleted' - b.spr.hide() - self.trash_stack = [] - - """ - Is x,y over the trash can? - """ - def _in_the_trash(self, x, y): - if self.selected_palette == self.trash_index and \ - self.palette_sprs[self.trash_index][self.orientation].hit((x,y)): - return True - return False - - """ - Block pressed - """ - def _block_pressed(self, mask, x, y, blk): - if blk is not None: - blk.highlight() - self._disconnect(blk) - self.drag_group = self._find_group(blk) - (sx, sy) = blk.spr.get_xy() - self.drag_pos = x-sx, y-sy - for blk in self.drag_group: - if blk.status != 'collapsed': - blk.spr.set_layer(TOP_LAYER) - self.saved_string = blk.spr.labels[0] - - """ - Unselect block - """ - def _unselect_block(self): - # After unselecting a 'number' block, we need to check its value - if self.selected_blk.name == 'number': - self._number_check() - elif self.selected_blk.name == 'string': - self._string_check() - self.selected_blk.unhighlight() - self.selected_blk = None - - """ - Make a new block. - """ - def _new_block(self, name, x, y): - if name in CONTENT_BLOCKS: - newblk = Block(self.block_list, self.sprite_list, name, x-20, y-20, - 'block', DEFAULTS[name], self.block_scale) - else: - newblk = Block(self.block_list, self.sprite_list, name, x-20, y-20, - 'block', [], self.block_scale) - - # Add a 'skin' to some blocks - if name == 'nop': - if self.nop == 'pythonloaded': - self._block_skin('pythonon', newblk) - else: - self._block_skin('pythonoff', newblk) - elif name in BOX_STYLE_MEDIA: - self._block_skin(name+'off', newblk) - - newspr = newblk.spr - newspr.set_layer(TOP_LAYER) - self.drag_pos = 20, 20 - newblk.connections = [None]*len(newblk.docks) - if DEFAULTS.has_key(newblk.name): - for i, argvalue in enumerate(DEFAULTS[newblk.name]): - # skip the first dock position since it is always a connector - dock = newblk.docks[i+1] - argname = dock[0] - if argname == 'unavailable': - continue - if argname == 'media': - argname = 'journal' - elif argname == 'number' and\ - (type(argvalue) is str or type(argvalue) is unicode): - argname = 'string' - elif argname == 'bool': - argname = argvalue - elif argname == 'flow': - argname = argvalue - (sx, sy) = newspr.get_xy() - if argname is not None: - if argname in CONTENT_BLOCKS: - argblk = Block(self.block_list, self.sprite_list, - argname, 0, 0, 'block', [argvalue], - self.block_scale) - else: - argblk = Block(self.block_list, self.sprite_list, - argname, 0, 0, 'block', [], - self.block_scale) - argdock = argblk.docks[0] - nx, ny = sx+dock[2]-argdock[2], sy+dock[3]-argdock[3] - if argname == 'journal': - self._block_skin('journaloff', argblk) - argblk.spr.move((nx, ny)) - argblk.spr.set_layer(TOP_LAYER) - argblk.connections = [newblk, None] - newblk.connections[i+1] = argblk - self.drag_group = self._find_group(newblk) - self.block_operation = 'new' - - """ - Create a "macro" (predefined stack of blocks) - """ - def _new_macro(self, name, x, y): - macro = MACROS[name] - macro[0][2] = x - macro[0][3] = y - top = self.process_data(macro) - self.block_operation = 'new' - self._check_collapsibles(top) - self.drag_group = self._find_group(top) - - """ - Process data (from a macro, a file, or the clipboard) into blocks. - """ - def process_data(self, data): - # Create the blocks (or turtle). - blocks = [] - for b in data: - if self._found_a_turtle(b) is False: - blk = self.load_block(b) - blocks.append(blk) - - # Make the connections. - for i in range(len(blocks)): - cons=[] - # Normally, it is simply a matter of copying the connections. - if blocks[i].connections == None: - for c in data[i][4]: - if c is None: - cons.append(None) - else: - cons.append(blocks[c]) - elif blocks[i].connections == 'check': - # Corner case to convert old-style boolean and arithmetic blocks - cons.append(None) # Add an extra connection. - for c in data[i][4]: - if c is None: - cons.append(None) - else: - cons.append(blocks[c]) - # If the boolean op was connected, readjust the plumbing. - if blocks[i].name in BOOLEAN_STYLE: - if data[i][4][0] is not None: - c = data[i][4][0] - cons[0] = blocks[data[c][4][0]] - c0 = data[c][4][0] - for j, cj in enumerate(data[c0][4]): - if cj == c: - blocks[c0].connections[j] = blocks[i] - if c<i: - blocks[c].connections[0] = blocks[i] - blocks[c].connections[3] = None - else: - # Connection was to a block we haven't seen yet. - print "WARNING: dock check couldn't see the future" - else: - if data[i][4][0] is not None: - c = data[i][4][0] - cons[0] = blocks[data[c][4][0]] - c0 = data[c][4][0] - for j, cj in enumerate(data[c0][4]): - if cj == c: - blocks[c0].connections[j] = blocks[i] - if c<i: - blocks[c].connections[0] = blocks[i] - blocks[c].connections[1] = None - else: - # Connection was to a block we haven't seen yet. - print "WARNING: dock check couldn't see the future" + # load alternative image of nop block if python code is loaded + if proto.name == 'nop' and tw.nop == 'pythonloaded': + newspr = sprNew(tw,x-20,y-20,tw.media_shapes['pythonloaded']) + else: + newspr = sprNew(tw,x-20,y-20,proto.image) + setlayer(newspr,2000) + tw.dragpos = 20,20 + newspr.type = 'block' + newspr.proto = proto + if tw.defdict.has_key(newspr.proto.name): + newspr.label=tw.defdict[newspr.proto.name] + newspr.connections = [None]*len(proto.docks) + for i in range(len(proto.defaults)): + dock = proto.docks[i+1] + argproto = tw.protodict[tw.valdict[dock[0]]] + argdock = argproto.docks[0] + nx,ny = newspr.x+dock[2]-argdock[2],newspr.y+dock[3]-argdock[3] + argspr = sprNew(tw,nx,ny,argproto.image) + argspr.type = 'block' + argspr.proto = argproto + argspr.label = str(proto.defaults[i]) + setlayer(argspr,2000) + argspr.connections = [newspr,None] + newspr.connections[i+1] = argspr + tw.draggroup = findgroup(newspr) + tw.block_operation = 'new' + +def block_pressed(tw,mask,x,y,spr): + if spr is not None: + tw.draggroup = findgroup(spr) + for b in tw.draggroup: setlayer(b,2000) + if spr.connections[0] != None and spr.proto.name == 'lock': + b = find_top_block(spr) + tw.dragpos = x-b.x,y-b.y + else: + tw.dragpos = x-spr.x,y-spr.y + disconnect(spr) + +def turtle_pressed(tw,x,y): + dx,dy = x-tw.turtle.spr.x-30,y-tw.turtle.spr.y-30 + if dx*dx+dy*dy > 200: + tw.dragpos = ('turn', \ + tw.turtle.heading-atan2(dy,dx)/DEGTOR,0) + else: + tw.dragpos = ('move', x-tw.turtle.spr.x,y-tw.turtle.spr.y) + tw.draggroup = [tw.turtle.spr] + +# +# Mouse move +# + +def move_cb(win, event, tw): + x,y = xy(event) + mouse_move(tw, x, y) + return True + +def mouse_move(tw, x, y, verbose=False, mdx=0, mdy=0): + if verbose: + print "processing remote mouse move: " + str(x) + " " + str(y) + if tw.draggroup is None: + # popup help from RGS + spr = findsprite(tw,(x,y)) + if spr and spr.type == 'category': + proto = get_proto_from_category(tw,x,y) + if proto and proto!='hide': + if timeout_tag[0] == 0: + timeout_tag[0] = showPopup(proto.name,tw) + tw.spr = spr + return else: - print "WARNING: unknown connection state %s" %\ - (str(blocks[i].connections)) - blocks[i].connections = cons[:] - - # Block sizes and shapes may have changed. - for b in blocks: - self._adjust_dock_positions(b) - - # Look for any stacks that need to be collapsed. - for b in blocks: - if self._collapsed(b): - self._collapse_stack(self._find_sandwich_top(b)) - return blocks[0] - - """ - Adjust the dock x,y positions - """ - def _adjust_dock_positions(self, blk): - (sx, sy) = blk.spr.get_xy() - for i, c in enumerate(blk.connections): - if i>0 and c is not None: - bdock = blk.docks[i] - for j in range(len(c.docks)): - if c.connections[j] == blk: - cdock = c.docks[j] - nx, ny = sx+bdock[2]-cdock[2], sy+bdock[3]-cdock[3] - c.spr.move((nx, ny)) - self._adjust_dock_positions(c) - - """ - Turtle pressed - """ - def _turtle_pressed(self, x, y): - (tx, ty) = self.selected_turtle.get_xy() - dx, dy = x-tx-30, y-ty-30 - if dx*dx+dy*dy > 200: - self.drag_turtle = ('turn', - self.canvas.heading-atan2(dy,dx)/DEGTOR, 0) - else: - self.drag_turtle = ('move', x-tx, y-ty) - - """ - Mouse move - """ - def _move_cb(self, win, event): - x, y = self._xy(event) - self._mouse_move(x, y) - return True - - def _mouse_move(self, x, y, verbose=False, mdx=0, mdy=0): - if verbose: - print "processing remote mouse move: %d, %d" % (x, y) - - self.block_operation = 'move' - # First, check to see if we are dragging or rotating a turtle. - if self.selected_turtle is not None: - dtype, dragx, dragy = self.drag_turtle - (sx, sy) = self.selected_turtle.get_xy() - if dtype == 'move': - if mdx != 0 or mdy != 0: - dx, dy = mdx, mdy - else: - dx, dy = x-dragx-sx, y-dragy-sy - self.selected_turtle.move((sx+dx, sy+dy)) - else: - if mdx != 0 or mdy != 0: - dx, dy = mdx, mdy - else: - dx, dy = x-sx-30, y-sy-30 - self.canvas.seth(int(dragx+atan2(dy,dx)/DEGTOR+5)/10*10) - # If we are hoving, show popup help. - elif self.drag_group is None: - self._show_popup(x, y) - return - # If we have a stack of blocks selected, move them. - elif self.drag_group[0] is not None: - blk = self.drag_group[0] - # Don't move a bottom blk is the stack is collapsed - if self._collapsed(blk): - return - - self.selected_spr = blk.spr - dragx, dragy = self.drag_pos - if mdx != 0 or mdy != 0: - dx, dy = mdx, mdy - else: - (sx,sy) = blk.spr.get_xy() - dx, dy = x-dragx-sx, y-dragy-sy - - # Take no action if there was a move of 0,0. - if dx == 0 and dy == 0: - return - self.drag_group = self._find_group(blk) - - # Prevent blocks from ending up with a negative x... - for b in self.drag_group: - (bx, by) = b.spr.get_xy() - if bx+dx < 0: - dx += -(bx+dx) - # ...or under the palette. - if self.selected_palette is not None and\ - self.selected_palette != self.trash_index: - w, h = self.palette_sprs[self.selected_palette][ - self.orientation].get_dimensions() - if self.orientation == 0: - if bx < w and by+dy < ICON_SIZE+PALETTE_HEIGHT: - dy += -(by+dy)+ICON_SIZE+PALETTE_HEIGHT - else: - if by < h+ICON_SIZE and bx+dx < PALETTE_WIDTH: - dx += -(bx+dx)+PALETTE_WIDTH - - # Move the stack. - for b in self.drag_group: - (bx, by) = b.spr.get_xy() - b.spr.move((bx+dx, by+dy)) - if mdx != 0 or mdy != 0: - dx, dy = 0, 0 - else: - self.dx += dx - self.dy += dy - - """ - Let's help our users by displaying a little help. - """ - def _show_popup(self, x, y): - spr = self.sprite_list.find_sprite((x,y)) - blk = self.block_list.spr_to_block(spr) - if spr and blk is not None: - if self.timeout_tag[0] == 0: - self.timeout_tag[0] = self._do_show_popup(blk.name) - self.selected_spr = spr + if timeout_tag[0] > 0: + try: + gobject.source_remove(timeout_tag[0]) + timeout_tag[0] = 0 + except: + timeout_tag[0] = 0 + elif spr and spr.type == 'selbutton': + if timeout_tag[0] == 0: + timeout_tag[0] = showPopup(spr.name,tw) + tw.spr = spr else: - if self.timeout_tag[0] > 0: + if timeout_tag[0] > 0: try: - gobject.source_remove(self.timeout_tag[0]) - self.timeout_tag[0] = 0 + gobject.source_remove(timeout_tag[0]) + timeout_tag[0] = 0 except: - self.timeout_tag[0] = 0 - elif spr and hasattr(spr,'type') and (spr.type == 'selector' or\ - spr.type == 'palette'): - if self.timeout_tag[0] == 0: - self.timeout_tag[0] = self._do_show_popup(spr.name) - self.selected_spr = spr + timeout_tag[0] = 0 + elif spr and spr.type == 'block': + if timeout_tag[0] == 0: + timeout_tag[0] = showPopup(spr.proto.name,tw) + tw.spr = spr else: - if self.timeout_tag[0] > 0: + if timeout_tag[0] > 0: try: - gobject.source_remove(self.timeout_tag[0]) - self.timeout_tag[0] = 0 + gobject.source_remove(timeout_tag[0]) + timeout_tag[0] = 0 except: - self.timeout_tag[0] = 0 + timeout_tag[0] = 0 else: - if self.timeout_tag[0] > 0: + if timeout_tag[0] > 0: try: - gobject.source_remove(self.timeout_tag[0]) - self.timeout_tag[0] = 0 + gobject.source_remove(timeout_tag[0]) + timeout_tag[0] = 0 except: - self.timeout_tag[0] = 0 - - """ - Fetch the help text and display it. - """ - def _do_show_popup(self, block_name): - if SPECIAL_NAMES.has_key(block_name): - block_name_s = SPECIAL_NAMES[block_name] - elif BLOCK_NAMES.has_key(block_name): - block_name_s = BLOCK_NAMES[block_name][0] - else: - block_name_s = _(block_name) - if HELP_STRINGS.has_key(block_name): - label = block_name_s + ": " + HELP_STRINGS[block_name] - else: - label = block_name_s - if self.running_sugar: - self.activity.hover_help_label.set_text(label) - self.activity.hover_help_label.show() + timeout_tag[0] = 0 + return + tw.block_operation = 'move' + spr = tw.draggroup[0] + if spr.type == 'block': + tw.spr = spr + dragx, dragy = tw.dragpos + if mdx != 0 or mdy != 0: + dx,dy = mdx,mdy else: - self.win.set_title(_("Turtle Art") + " — " + label) - return 0 - - """ - Button release - """ - def _buttonrelease_cb(self, win, event): - x, y = self._xy(event) - self.button_release(x, y) - if self._sharing(): - self.activity._send_event("r:"+str(x)+":"+str(y)) - return True - - def button_release(self, x, y, verbose=False): - if self.dx != 0 or self.dy != 0: - if self._sharing(): - if verbose: - print "processing move: %d %d" % (self.dx, self.dy) - self.activity._send_event("m:%d:%d" % (self.dx, self.dy)) - self.dx = 0 - self.dy = 0 - if verbose: - print "processing remote button release: %d, %d" % (x, y) - - # We may have been moving the turtle - if self.selected_turtle is not None: - (tx, ty) = self.selected_turtle.get_xy() - (cx, cy) = self.canvas.canvas.get_xy() - self.canvas.xcor = tx-self.canvas.canvas._width/2+30-cx - self.canvas.ycor = self.canvas.canvas._height/2-ty-30+cy - self.canvas.move_turtle() - if self.running_sugar: - self.display_coordinates() - self.selected_turtle = None - return - - # If we don't have a group of blocks, then there is nothing to do. - if self.drag_group == None: - return - - blk = self.drag_group[0] - # Remove blocks by dragging them onto the trash palette. - if self.block_operation=='move' and self._in_the_trash(x, y): - self._put_in_trash(blk, x, y) - self.drag_group = None - return - - # Pull a stack of new blocks off of the category palette. - if self.block_operation=='new': - for b in self.drag_group: - (bx, by) = b.spr.get_xy() - if self.orientation == 0: - b.spr.move((bx+20, by+PALETTE_HEIGHT+ICON_SIZE)) - else: - b.spr.move((bx+PALETTE_WIDTH, by+20)) - - # Look to see if we can dock the current stack. - self._snap_to_dock() - self._check_collapsibles(blk) - for b in self.drag_group: - if b.status != 'collapsed': - b.spr.set_layer(BLOCK_LAYER) - self.drag_group = None - - # Find the block we clicked on and process it. - if self.block_operation=='click': - self._click_block(x, y) - - """ - Click block - """ - def _click_block(self, x, y): - blk = self.block_list.spr_to_block(self.selected_spr) - if blk is None: + dx,dy = x-dragx-spr.x,y-dragy-spr.y + # skip if there was a move of 0,0 + if dx == 0 and dy == 0: return - self.selected_blk = blk - if blk.name=='number' or blk.name=='string': - self.saved_string = blk.spr.labels[0] - blk.spr.labels[0] += CURSOR - elif blk.name in BOX_STYLE_MEDIA: - self._import_from_journal(self.selected_blk) - elif blk.name=='identity2' or blk.name=='hspace': - group = self._find_group(blk) - if self._hide_button_hit(blk.spr, x, y): - dx = blk.reset_x() - elif self._show_button_hit(blk.spr, x, y): - dx = 20 - blk.expand_in_x(dx) - for b in group: - if b != blk: - b.spr.move_relative((dx*blk.scale, 0)) - elif blk.name=='vspace': - group = self._find_group(blk) - if self._hide_button_hit(blk.spr, x, y): - dy = blk.reset_y() - elif self._show_button_hit(blk.spr, x, y): - dy = 20 - blk.expand_in_y(dy) - else: - dy = 0 - for b in group: - if b != blk: - b.spr.move_relative((0, dy*blk.scale)) - self._grow_stack_arm(self._find_sandwich_top(blk)) - elif blk.name in EXPANDABLE: - if self._show_button_hit(blk.spr, x, y): - n = len(blk.connections) - group = self._find_group(blk.connections[n-1]) - if blk.name == 'myfunc' and n == 4: - blk.spr.labels[1] = 'f(x,y)' - blk.spr.labels[2] = ' ' - if blk.name == 'myfunc' and n == 5: - blk.spr.labels[1] = 'f(x,y,z)' - dy = blk.add_arg(False) - else: - dy = blk.add_arg() - for b in group: - b.spr.move_relative((0, dy)) - blk.connections.append(blk.connections[n-1]) - argname = blk.docks[n-1][0] - argvalue = DEFAULTS[blk.name][len(DEFAULTS[blk.name])-1] - argblk = Block(self.block_list, self.sprite_list, argname, - 0, 0, 'block', [argvalue], self.block_scale) - argdock = argblk.docks[0] - (bx, by) = blk.spr.get_xy() - nx = bx+blk.docks[n-1][2]-argdock[2] - ny = by+blk.docks[n-1][3]-argdock[3] - argblk.spr.move((nx, ny)) - argblk.spr.set_layer(TOP_LAYER) - argblk.connections = [blk, None] - blk.connections[n-1] = argblk - self._grow_stack_arm(self._find_sandwich_top(blk)) - else: - self._run_stack(blk) - elif blk.name in COLLAPSIBLE: - top = self._find_sandwich_top(blk) - if self._collapsed(blk): - self._restore_stack(top) - elif top is not None: - self._collapse_stack(top) - elif blk.name=='nop' and self.myblock==None: - self._import_py() + # drag entire stack if moving lock block + if spr.proto.name == 'lock': + tw.draggroup = findgroup(find_top_block(spr)) else: - self._run_stack(blk) - - """ - Collapsible stacks live between 'sandwichtop' and 'sandwichbottom' blocks - What follows are a number of utilities for managing collapsible stacks. - Alas, corner-cases abound. - """ - - """ - From the top, find and restore any collapsible stacks on forks. - """ - def _uncollapse_forks(self, top, looping=False): - if top == None: - return - if looping and top.name == 'sandwichtop': - self._restore_stack(top) - return - if len(top.connections) == 0: - return - b = top.connections[len(top.connections)-1] - while b is not None: - if b.name in COLLAPSIBLE: - return - if b.name == 'sandwichtop': - self._restore_stack(b) - return - # Follow a fork - if b.name in ['repeat', 'if', 'ifelse', 'forever', 'while']: - top = self._find_sandwich_top_below( - b.connections[len(b.connections)-2]) - if top is not None: - self._uncollapse_forks(top, True) - if b.name == 'ifelse': - top = self._find_sandwich_top_below( - b.connections[len(b.connections)-3]) - if top is not None: - self._uncollapse_forks(top, True) - b = b.connections[len(b.connections)-1] - return - - """ - Find the sandwich top above this block. - """ - def _find_sandwich_top(self, blk): - # Always follow the main branch of a flow: the first connection. - b = blk.connections[0] - while b is not None: - if b.name in COLLAPSIBLE: - return None - if b.name in ['repeat', 'if', 'ifelse', 'forever', 'while']: - if blk != b.connections[len(b.connections)-1]: - return None - if b.name == 'sandwichtop': - return b - blk = b - b = b.connections[0] - return None - - """ - Find the sandwich bottom below this block. - """ - def _find_sandwich_bottom(self, blk): - # Always follow the main branch of a flow: the last connection. - b = blk.connections[len(blk.connections)-1] - while b is not None: - if b.name == 'sandwichtop': - return None - if b.name in COLLAPSIBLE: - return b - b = b.connections[len(b.connections)-1] - return None - - """ - Find the sandwich top below this block. - """ - def _find_sandwich_top_below(self, blk): - if blk.name == 'sandwichtop': - return blk - # Always follow the main branch of a flow: the last connection. - b = blk.connections[len(blk.connections)-1] - while b is not None: - if b.name == 'sandwichtop': - return b - b = b.connections[len(b.connections)-1] - return None - - """ - Hide all the blocks between the sandwich top and sandwich bottom. - """ - def _collapse_stack(self, top): - # First uncollapse any nested stacks - self._uncollapse_forks(top) - hit_bottom = False - bot = self._find_sandwich_bottom(top) - group = self._find_group(top.connections[len(top.connections)-1]) - for b in group: - if not hit_bottom and b == bot: - hit_bottom = True - - # Replace 'sandwichbottom' shape with 'sandwichcollapsed' shape - if len(b.values) == 0: - b.values.append(1) - else: - b.values[0] = 1 - olddx = b.docks[1][2] - olddy = b.docks[1][3] - b.name = 'sandwichcollapsed' - b.svg.set_show(True) - b.svg.set_hide(False) - b._dx = 0 - b._ey = 0 - b.spr.set_label(_('click to open')) - b.resize() - - # Redock to sandwich top in group - you = self._find_sandwich_top(b) - (yx, yy) = you.spr.get_xy() - yd = you.docks[len(you.docks)-1] - (bx, by) = b.spr.get_xy() - dx = yx+yd[2]-b.docks[0][2]-bx - dy = yy+yd[3]-b.docks[0][3]-by - b.spr.move_relative((dx, dy)) - - # Since the shapes have changed, the dock positions have too. - newdx = b.docks[1][2] - newdy = b.docks[1][3] - dx += newdx-olddx - dy += newdy-olddy + tw.draggroup = findgroup(spr) + # check to see if any block ends up with a negative x + for b in tw.draggroup: + if b.x+dx < 0: + dx += -(b.x+dx) + # move the stack + for b in tw.draggroup: + move(b,(b.x+dx, b.y+dy)) + elif spr.type=='turtle': + type,dragx,dragy = tw.dragpos + if type == 'move': + if mdx != 0 or mdy != 0: + dx,dy = mdx,mdy else: - if not hit_bottom: - b.spr.set_layer(HIDE_LAYER) - b.status = 'collapsed' - else: - b.spr.move_relative((dx, dy)) - self._reset_stack_arm(top) - - """ - Restore all the blocks between the sandwich top and sandwich bottom. - """ - def _restore_stack(self, top): - group = self._find_group(top.connections[len(top.connections)-1]) - hit_bottom = False - bot = self._find_sandwich_bottom(top) - for b in group: - if not hit_bottom and b == bot: - hit_bottom = True - if len(b.values) == 0: - b.values.append(0) - else: - b.values[0] = 0 - olddx = b.docks[1][2] - olddy = b.docks[1][3] - # Replace 'sandwichcollapsed' shape with 'sandwichbottom' shape - b.name = 'sandwichbottom' - b.spr.set_label(' ') - b.svg.set_show(False) - b.svg.set_hide(True) - b.refresh() - - # Redock to previous block in group - you = b.connections[0] - (yx, yy) = you.spr.get_xy() - yd = you.docks[len(you.docks)-1] - (bx, by) = b.spr.get_xy() - dx = yx+yd[2]-b.docks[0][2]-bx - dy = yy+yd[3]-b.docks[0][3]-by - b.spr.move_relative((dx, dy)) - - # Since the shapes have changed, the dock positions have too. - newdx = b.docks[1][2] - newdy = b.docks[1][3] - dx += newdx-olddx - dy += newdy-olddy + dx,dy = x-dragx-spr.x,y-dragy-spr.y + move(spr, (spr.x+dx, spr.y+dy)) + else: + if mdx != 0 or mdy != 0: + dx,dy = mdx,mdy else: - if not hit_bottom: - b.spr.set_layer(BLOCK_LAYER) - b.status = None - else: - b.spr.move_relative((dx, dy)) - self._grow_stack_arm(top) - - """ - When we undock, retract the 'arm' that extends down from 'sandwichtop'. - """ - def _reset_stack_arm(self, top): - if top is not None and top.name == 'sandwichtop': - if top.ey > 0: - top.reset_y() - - """ - When we dock, grow an 'arm' the length of the stack from 'sandwichtop'. - """ - def _grow_stack_arm(self, top): - if top is not None and top.name == 'sandwichtop': - bot = self._find_sandwich_bottom(top) - if bot is None: - return - if top.ey > 0: - top.reset_y() - (tx, ty) = top.spr.get_xy() - (tw, th) = top.spr.get_dimensions() - (bx, by) = bot.spr.get_xy() - dy = by-(ty+th) - if dy > 0: - top.expand_in_y(dy/top.scale) - - """ - Check the state of collapsible blocks upon change in dock state. - """ - def _check_collapsibles(self, blk): - group = self._find_group(blk) - for b in group: - if b.name in COLLAPSIBLE: - if self._collapsed(b): - b.svg.set_show(True) - b.svg.set_hide(False) - self._reset_stack_arm(self._find_sandwich_top(b)) - elif self._collapsible(b): - b.svg.set_hide(True) - b.svg.set_show(False) - self._grow_stack_arm(self._find_sandwich_top(b)) + dx,dy = x-spr.x-30,y-spr.y-30 + seth(tw.turtle, int(dragx+atan2(dy,dx)/DEGTOR+5)/10*10) + if mdx != 0 or mdy != 0: + dx,dy = 0,0 + else: + tw.dx += dx + tw.dy += dy + +# +# Button release +# + +def buttonrelease_cb(win, event, tw): + x,y = xy(event) + button_release(tw, x, y) + if hasattr(tw, 'activity') and \ + hasattr(tw.activity, 'chattube') and tw.activity.chattube is not None: + # print "sending release button" + tw.activity._send_event("r:"+str(x)+":"+str(y)) + return True + +def button_release(tw, x, y, verbose=False): + if tw.dx != 0 or tw.dy != 0: + if hasattr(tw, 'activity') and \ + hasattr(tw.activity, 'chattube') and \ + tw.activity.chattube is not None: + if verbose: + print "processing move: " + str(tw.dx) + " " + str(tw.dy) + tw.activity._send_event("m:"+str(tw.dx)+":"+str(tw.dy)) + tw.dx = 0 + tw.dy = 0 + if verbose: + print "processing remote button release: " + str(x) + " " + str(y) + if tw.draggroup == None: + return + spr = tw.draggroup[0] + if spr.type == 'turtle': + tw.turtle.xcor = tw.turtle.spr.x-tw.turtle.canvas.x- \ + tw.turtle.canvas.width/2+30 + tw.turtle.ycor = tw.turtle.canvas.height/2-tw.turtle.spr.y+ \ + tw.turtle.canvas.y-30 + move_turtle(tw.turtle) + display_coordinates(tw) + tw.draggroup = None + return + if tw.block_operation=='move' and hit(tw.category_spr, (x,y)): + for b in tw.draggroup: hide(b) + tw.draggroup = None + return + if tw.block_operation=='new': + for b in tw.draggroup: + move(b, (b.x+200, b.y)) + snap_to_dock(tw) + for b in tw.draggroup: setlayer(b,650) + tw.draggroup = None + if tw.block_operation=='click': + if tw.spr.proto.name=='number': + tw.selected_block = spr + move(tw.select_mask, (spr.x-5,spr.y-5)) + setlayer(tw.select_mask, 660) + tw.firstkey = True + elif tw.defdict.has_key(spr.proto.name): + tw.selected_block = spr + if tw.spr.proto.name=='string': + move(tw.select_mask_string, (spr.x-5,spr.y-5)) + setlayer(tw.select_mask_string, 660) + tw.firstkey = True + elif tw.spr.proto.name in importblocks: + import_from_journal(tw, spr) + elif tw.spr.proto.name=='nop' and tw.myblock==None: + tw.activity.import_py() + else: run_stack(tw, spr) + +def import_from_journal(tw, spr): + if hasattr(tw,"activity"): + chooser = ObjectChooser('Choose image', None,\ + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) + try: + result = chooser.run() + if result == gtk.RESPONSE_ACCEPT: + dsobject = chooser.get_selected_object() + # change block graphic to indicate that object is "loaded" + if spr.proto.name == 'journal': + load_image(tw, dsobject, spr) + elif spr.proto.name == 'audiooff': + setimage(spr,tw.media_shapes['audioon']) else: - b.svg.set_hide(False) - b.svg.set_show(False) - # Ouch: When you tear off the sandwich bottom, you - # no longer have access to the group with the sandwich top - # so check them all. - for bb in self.just_blocks(): - if bb.name == 'sandwichtop': - if self._find_sandwich_bottom(bb) is None: - self._reset_stack_arm(bb) - b.refresh() - - """ - Is this stack collapsed? - """ - def _collapsed(self, blk): - if blk is not None and blk.name in COLLAPSIBLE and\ - len(blk.values) == 1 and blk.values[0] != 0: - return True - return False - - """ - Can this stack be collapsed? - """ - def _collapsible(self, blk): - if blk is None or blk.name not in COLLAPSIBLE: - return False - if self._find_sandwich_top(blk) is None: - return False - return True - - """ - Run a stack of blocks. - """ - def _run_stack(self, blk): - if blk is None: - return - self.lc.ag = None - top = self.find_top_block(blk) - self.lc.run_blocks(top, self.just_blocks(), True) - gobject.idle_add(self.lc.doevalstep) - - """ - Did the sprite's hide (contract) button get hit? - """ - def _hide_button_hit(self, spr, x, y): - r,g,b,a = spr.get_pixel((x, y)) - if (r == 255 and g == 0) or g == 255: - return True - else: - return False - - """ - Did the sprite's show (expand) button get hit? - """ - def _show_button_hit(self, spr, x, y): - r,g,b,a = spr.get_pixel((x, y)) - if g == 254: - return True - else: - return False - - """ - Snap a block to the dock of another block. - """ - def _snap_to_dock(self): - my_block = self.drag_group[0] - d = 200 - for my_dockn in range(len(my_block.docks)): - for i, your_block in enumerate(self.just_blocks()): - # don't link to a block to which you're already connected - if your_block in self.drag_group: + setimage(spr, tw.media_shapes['decson']) + spr.ds_id = dsobject.object_id + dsobject.destroy() + finally: + chooser.destroy() + del chooser + else: + print "Journal Object Chooser unavailable from outside of Sugar" + +# Replace Journal block graphic with preview image +def load_image(tw, picture, spr): + from talogo import get_pixbuf_from_journal + pixbuf = get_pixbuf_from_journal(picture,spr.width,spr.height) + if pixbuf is not None: + setimage(spr, pixbuf) + else: + setimage(spr, tw.media_shapes['texton']) + +# change the icon for user-defined blocks after Python code is loaded +def set_userdefined(tw): + list = tw.sprites[:] + for spr in list: + if hasattr(spr,'proto') and spr.proto.name == 'nop': + setimage(spr,tw.media_shapes['pythonloaded']) + tw.nop = 'pythonloaded' + +def snap_to_dock(tw): + d=200 + me = tw.draggroup[0] + for mydockn in range(len(me.proto.docks)): + for you in blocks(tw): + if you in tw.draggroup: + continue + for yourdockn in range(len(you.proto.docks)): + thisxy = dock_dx_dy(you,yourdockn,me,mydockn) + if magnitude(thisxy)>d: continue - # check each dock of your_block for a possible connection - for your_dockn in range(len(your_block.docks)): - this_xy = self._dock_dx_dy(your_block, your_dockn, - my_block, my_dockn) - if magnitude(this_xy) > d: - continue - d = magnitude(this_xy) - best_xy = this_xy - best_you = your_block - best_your_dockn = your_dockn - best_my_dockn = my_dockn - if d<200: - if self._arithmetic_check(my_block, best_you, best_my_dockn, - best_your_dockn) is False: - return - for blk in self.drag_group: - (sx, sy) = blk.spr.get_xy() - blk.spr.move((sx+best_xy[0], sy+best_xy[1])) - - # If there was already a block docked there, move it to the trash. - blk_in_dock = best_you.connections[best_your_dockn] - if blk_in_dock is not None: - blk_in_dock.connections[0] = None - self._put_in_trash(blk_in_dock) - - best_you.connections[best_your_dockn] = my_block - if my_block.connections is not None: - my_block.connections[best_my_dockn] = best_you - - """ - Additional docking check for arithmetic blocks: dock strings only if they - convert to numbers. Also, avoid /0 and root(-1) - """ - def _arithmetic_check(self, b1, b2, d1, d2): - if b1 == None or b2 == None: - return True - if b1.name in ['sqrt', 'number', 'string'] and\ - b2.name in ['sqrt', 'number', 'string']: - if b1.name == 'number' or b1.name == 'string': - if not numeric_arg(b1.values[0]) or neg_arg(b1.values[0]): - return False - elif b2.name == 'number' or b2.name == 'string': - if not numeric_arg(b2.values[0]) or neg_arg(b2.values[0]): - return False - elif b1.name in ['division2', 'number', 'string'] and\ - b2.name in ['division2', 'number', 'string']: - if b1.name == 'number' or b1.name == 'string': - if not numeric_arg(b1.values[0]): - return False - if d2 == 2 and zero_arg(b1.values[0]): - return False - elif b2.name == 'number' or b2.name == 'string': - if not numeric_arg(b2.values[0]): - return False - if d1 == 2 and zero_arg(b2.values[0]): - return False - elif b1.name in ['product2', 'minus2', 'random', 'remainder2', - 'string'] and\ - b2.name in ['product2', 'minus2', 'random', 'remainder2', - 'string']: - if b1.name == 'string': - if not numeric_arg(b1.values[0]): - return False - elif b1.name == 'string': - if not numeric_arg(b2.values[0]): - return False - elif b1.name in ['greater2', 'less2'] and b2.name == 'string': - # Non-numeric stings are OK if only both args are strings; - # Lots of test conditions... - if d1 == 1 and b1.connections[2] is not None: - if b1.connections[2].name == 'number': - if not numeric_arg(b2.values[0]): - return False - elif d1 == 2 and b1.connections[1] is not None: - if b1.connections[1].name == 'number': - if not numeric_arg(b2.values[0]): - return False - elif b2.name in ['greater2', 'less2'] and b1.name == 'string': - if d2 == 1 and b2.connections[2] is not None: - if b2.connections[2].name == 'number': - if not numeric_arg(b1.values[0]): - return False - elif d2 == 2 and b2.connections[1] is not None: - if b2.connections[1].name == 'number': - if not numeric_arg(b1.values[0]): - return False - elif b1.name in ['greater2', 'less2'] and b2.name == 'number': - if d1 == 1 and b1.connections[2] is not None: - if b1.connections[2].name == 'string': - if not numeric_arg(b1.connections[2].values[0]): - return False - elif d1 == 2 and b1.connections[1] is not None: - if b1.connections[1].name == 'string': - if not numeric_arg(b1.connections[1].values[0]): - return False - elif b2.name in ['greater2', 'less2'] and b1.name == 'number': - if d2 == 1 and b2.connections[2] is not None: - if b2.connections[2].name == 'string': - if not numeric_arg(b2.connections[2].values[0]): - return False - elif d2 == 2 and b2.connections[1] is not None: - if b2.connections[1].name == 'string': - if not numeric_arg(b2.connections[1].values[0]): - return False - return True - - """ - Import a file from the Sugar Journal - """ - def _import_from_journal(self, blk): - if self.running_sugar: - chooser = ObjectChooser('Choose image', None, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) - try: - result = chooser.run() - if result == gtk.RESPONSE_ACCEPT: - dsobject = chooser.get_selected_object() - self._update_media_icon(blk, dsobject, dsobject.object_id) - dsobject.destroy() - finally: - chooser.destroy() - del chooser - else: - fname, self.load_save_folder = \ - get_load_name('.*', self.load_save_folder) - if fname is None: - return - self._update_media_icon(blk, fname) - - """ - Update the icon on a 'loaded' media block. - """ - def _update_media_icon(self, blk, name, value=''): - if blk.name == 'journal': - self._load_image_thumb(name, blk) - elif blk.name == 'audio': - self._block_skin('audioon', blk) - else: - self._block_skin('descriptionon', blk) - if value == '': - value = name - if len(blk.values)>0: - blk.values[0] = value - else: - blk.values.append(value) - blk.spr.set_label(' ') - - """ - Replace icon with a preview image. - """ - def _load_image_thumb(self, picture, blk): - pixbuf = None - self._block_skin('descriptionon', blk) - - if self.running_sugar: - w, h = calc_image_size(blk.spr) - pixbuf = get_pixbuf_from_journal(picture, w, h) - else: - if movie_media_type(picture): - self._block_skin('journalon', blk) - elif audio_media_type(picture): - self._block_skin('audioon', blk) - blk.name = 'audio' - elif image_media_type(picture): - w, h = calc_image_size(blk.spr) - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(picture, w, h) - else: - blk.name = 'description' - if pixbuf is not None: - x, y = self._calc_image_offset('', blk.spr) - blk.set_image(pixbuf, x, y) - self._resize_skin(blk) - - """ - Disconnect block from stack above it. - """ - def _disconnect(self, blk): - if blk.connections[0]==None: - return - if self._collapsed(blk): - return - blk2=blk.connections[0] - blk2.connections[blk2.connections.index(blk)] = None - blk.connections[0] = None - - """ - Find the distance between the dock points of two blocks. - """ - def _dock_dx_dy(self, block1, dock1n, block2, dock2n): - dock1 = block1.docks[dock1n] - dock2 = block2.docks[dock2n] - d1type, d1dir, d1x, d1y = dock1[0:4] - d2type, d2dir, d2x, d2y = dock2[0:4] - if block1 == block2: + d=magnitude(thisxy) + bestxy=thisxy + bestyou=you + bestyourdockn=yourdockn + bestmydockn=mydockn + if d<200: + for b in tw.draggroup: + move(b,(b.x+bestxy[0],b.y+bestxy[1])) + blockindock=bestyou.connections[bestyourdockn] + if blockindock!=None: + for b in findgroup(blockindock): + hide(b) + bestyou.connections[bestyourdockn]=me + me.connections[bestmydockn]=bestyou + +def dock_dx_dy(block1,dock1n,block2,dock2n): + 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 (d2type!='num') or (dock2n!=0): + if block1.connections[dock1n] != None: return (100,100) - if d1dir == d2dir: + if block2.connections[dock2n] != None: return (100,100) - if (d2type is not 'number') or (dock2n is not 0): - if block1.connections is not None and \ - dock1n < len(block1.connections) and \ - block1.connections[dock1n] is not None: - return (100,100) - if block2.connections is not None and \ - dock2n < len(block2.connections) and \ - block2.connections[dock2n] is not None: - return (100,100) - if d1type != d2type: - if block1.name in STRING_OR_NUMBER_ARGS: - if d2type == 'number' or d2type == 'string': + if block1==block2: return (100,100) + if d1type!=d2type: + # some blocks can take strings or nums + if block1.proto.name in ('write', 'plus2', 'equal', 'less', 'greater', \ + 'template1', 'template2', 'template3', \ + 'template4', 'template6', 'template7', 'nop', \ + 'print', 'stack'): + if block1.proto.name == 'write' and d1type == 'string': + if d2type == 'num' or d2type == 'string': pass - elif block1.name in CONTENT_ARGS: - if d2type in CONTENT_BLOCKS: + else: + if d2type == 'num' or d2type == 'string': pass - else: - return (100,100) - (b1x, b1y) = block1.spr.get_xy() - (b2x, b2y) = block2.spr.get_xy() - return ((b1x+d1x)-(b2x+d2x), (b1y+d1y)-(b2y+d2y)) - - - """ - Keyboard - """ - def _keypress_cb(self, area, event): - keyname = gtk.gdk.keyval_name(event.keyval) - keyunicode = gtk.gdk.keyval_to_unicode(event.keyval) - - if event.get_state()>k.gdk.MOD1_MASK: - alt_mask = True - alt_flag = 'T' + # some blocks can take strings, nums, or Journal + elif block1.proto.name in ('show', 'push', 'storein', 'storeinbox1', \ + 'storeinbox2'): + if d2type == 'num' or d2type == 'string' or d2type == 'journal': + pass + # some blocks can take media, audio, movies, of descriptions + elif block1.proto.name in ('containter'): + if d1type == 'audiooff' or d1type == 'journal': + pass else: - alt_mask = False - alt_flag = 'F' - results = self._key_press(alt_mask, keyname, keyunicode) - if keyname is not None and self._sharing(): - self.activity._send_event("k:%s:%s:%s" % (alt_flag, keyname, - str(keyunicode))) + return (100,100) + if d1dir==d2dir: + return (100,100) + return (block1.x+d1x)-(block2.x+d2x),(block1.y+d1y)-(block2.y+d2y) + +def magnitude(pos): + x,y = pos + return x*x+y*y + +# +# Repaint +# + +def expose_cb(win, event, tw): + redrawsprites(tw) + return True + +# +# Keyboard +# + +def keypress_cb(area, event, tw): + keyname = gtk.gdk.keyval_name(event.keyval) +# keyunicode = unichr(gtk.gdk.keyval_to_unicode(event.keyval)).replace("\x00","") + keyunicode = gtk.gdk.keyval_to_unicode(event.keyval) +# print keyname +# if keyunicode > 0: +# print unichr(keyunicode) + + if event.get_state()>k.gdk.MOD1_MASK: + alt_mask = True + else: + alt_mask = False + results = key_press(tw, alt_mask, keyname, keyunicode) + if keyname is not None and hasattr(tw,"activity") and \ + hasattr(tw.activity, 'chattube') and tw.activity.chattube is not None: + # print "key press" + if alt_mask: + tw.activity._send_event("k:"+'T'+":"+keyname+":"+str(keyunicode)) + else: + tw.activity._send_event("k:"+'F'+":"+keyname+":"+str(keyunicode)) + return keyname +''' + if len(keyname)>1: + # print "(" + keyunicode.encode("utf-8") + ")" return keyname - - def _key_press(self, alt_mask, keyname, keyunicode, verbose=False): - if keyname is None: - return False - if verbose: - print "processing remote key press: %s" % (keyname) - - self.keypress = keyname - - # First, process Alt keys. - if alt_mask is True and self.selected_blk==None: - if keyname=="i" and self._sharing(): - self.activity.waiting_for_blocks = True - self.activity._send_event("i") # request sync for sharing - elif keyname=="p": - self.hideshow_button() - elif keyname=='q': - exit() - return True - # Process keyboard input for 'number' blocks - if self.selected_blk is not None and\ - self.selected_blk.name == 'number': - self._process_numeric_input(keyname) - return True - # Process keyboard input for 'string' blocks - elif self.selected_blk is not None and\ - self.selected_blk.name == 'string': - self.process_alphanumeric_input(keyname, keyunicode) - if self.selected_blk is not None: - self.selected_blk.resize() - return True - # Otherwise, use keyboard input to move blocks or turtles - else: - self._process_keyboard_commands(keyname) - if self.selected_blk is None: - return False - - ''' - Make sure numeric input is valid. - ''' - def _process_numeric_input(self, keyname): - oldnum = self.selected_blk.spr.labels[0].replace(CURSOR,'') - if len(oldnum) == 0: - oldnum = '0' - if keyname == 'minus': - if oldnum == '0': - newnum = '-' - elif oldnum[0] != '-': - newnum = '-' + oldnum - else: - newnum = oldnum - elif keyname == 'period' and '.' not in oldnum: - newnum = oldnum + '.' - elif keyname == 'BackSpace': - if len(oldnum) > 0: + else: + # print "[" + keyunicode.encode("utf-8") + "]" + return keyunicode.encode("utf-8") +''' +def key_press(tw, alt_mask, keyname, keyunicode, verbose=False): + if keyname is None: + return False + if verbose: + print "processing remote key press: " + keyname + tw.keypress = keyname + if alt_mask is True and tw.selected_block==None: + if keyname=="i" and hasattr(tw, 'activity'): + tw.activity.waiting_for_blocks = True + tw.activity._send_event("i") # request sync for sharing + elif keyname=="p": + hideshow_button(tw) + elif keyname=='q': + exit() + return True + if tw.selected_block is not None and \ + tw.selected_block.proto.name == 'number': + if keyname in ['minus', 'period']: + keyname = {'minus': '-', 'period': '.'}[keyname] + oldnum = tw.selected_block.label + selblock=tw.selected_block.proto + if keyname == 'BackSpace': + if len(oldnum) > 1: newnum = oldnum[:len(oldnum)-1] else: newnum = '' - elif keyname in ['0','1','2','3','4','5','6','7','8','9']: - if oldnum == '0': - newnum = keyname + setlabel(tw.selected_block, selblock.check(newnum,oldnum)) + if len(newnum) > 0: + tw.firstkey = False else: - newnum = oldnum + keyname - elif keyname == 'Return': - self._unselect_block() - return - else: - newnum = oldnum - if newnum == '.': - newnum = '0.' - if len(newnum) > 0 and newnum != '-': - try: - float(newnum) - except ValueError,e: - newnum = oldnum - self.selected_blk.spr.set_label(newnum + CURSOR) - - """ - Make sure alphanumeric input is properly parsed. - """ - def process_alphanumeric_input(self, keyname, keyunicode): - if len(self.selected_blk.spr.labels[0]) > 0: - c = self.selected_blk.spr.labels[0].count(CURSOR) - if c == 0: - oldleft = self.selected_blk.spr.labels[0] - oldright = '' - elif len(self.selected_blk.spr.labels[0]) == 1: - oldleft = '' - oldright = '' - else: - try: # Why are getting a ValueError on occasion? - oldleft, oldright =\ - self.selected_blk.spr.labels[0].split(CURSOR) - except ValueError: - print "[%s]" % self.selected_blk.spr.labels[0] - oldleft = self.selected_blk.spr.labels[0] - oldright = '' - else: - oldleft = '' - oldright = '' - newleft = oldleft - if keyname in ['Shift_L', 'Shift_R', 'Control_L', 'Caps_Lock',\ - 'Alt_L', 'Alt_R', 'KP_Enter', 'ISO_Level3_Shift']: - keyname = '' - keyunicode = 0 - # Hack until I sort out input and unicode and dead keys, - if keyname[0:5] == 'dead_': - self.dead_key = keyname - keyname = '' - keyunicode = 0 - if keyname in WHITE_SPACE: - keyunicode = 32 - if keyname == 'BackSpace': - if len(oldleft) > 1: - newleft = oldleft[:len(oldleft)-1] - else: - newleft = '' - elif keyname == 'Home': - oldright = oldleft+oldright - newleft = '' - elif keyname == 'Left': - if len(oldleft) > 0: - oldright = oldleft[len(oldleft)-1:]+oldright - newleft = oldleft[:len(oldleft)-1] - elif keyname == 'Right': - if len(oldright) > 0: - newleft = oldleft + oldright[0] - oldright = oldright[1:] - elif keyname == 'End': - newleft = oldleft+oldright - oldright = '' - elif keyname == 'Return' or keyname == 'Down': - self._unselect_block() - return - elif keyname == 'Up' or keyname == 'Escape': # Restore previous state - self.selected_blk.spr.set_label(self.saved_string) - self._unselect_block() - return - else: - if self.dead_key is not '': - keyunicode =\ - DEAD_DICTS[DEAD_KEYS.index(self.dead_key[5:])][keyname] - self.dead_key = '' - if keyunicode > 0: - if unichr(keyunicode) is not '\x00': - newleft = oldleft+unichr(keyunicode) - else: - newleft = oldleft - elif keyunicode == -1: # clipboard text - newleft = oldleft+keyname - self.selected_blk.spr.set_label("%s%s%s" % (newleft, CURSOR, oldright)) - - """ - Use the keyboard to move blocks and turtle - """ - def _process_keyboard_commands(self, keyname): - mov_dict = {'KP_Up':[0,10],'j':[0,10],'Up':[0,10], - 'KP_Down':[0,-10],'k':[0,-10],'Down':[0,-10], - 'KP_Left':[-10,0],'h':[-10,0],'Left':[-10,0], - 'KP_Right':[10,0],'l':[10,0],'Right':[10,0], - 'KP_Page_Down':[0,0], 'KP_Page_Up':[0,0], 'KP_End':[0,0], - 'KP_Home':[-1,-1],'Return':[-1,-1], 'Esc':[0,0]} - if not mov_dict.has_key(keyname): - return - if keyname == 'KP_End': - self.run_button(0) - elif self.selected_spr is not None: - blk = self.block_list.spr_to_block(self.selected_spr) - tur = self.turtles.spr_to_turtle(self.selected_spr) - if not self.lc.running and blk is not None: - if keyname == 'Return' or keyname == 'KP_Page_Up': - (x, y) = blk.spr.get_xy() - self._click_block(x, y) - elif keyname == 'KP_Page_Down': - if self.drag_group == None: - self.drag_group = self._find_group(blk) - for b in self.drag_group: b.spr.hide() - self.drag_group = None - else: - self._jog_block(blk, mov_dict[keyname][0], - mov_dict[keyname][1]) - elif tur is not None: - self._jog_turtle(mov_dict[keyname][0], mov_dict[keyname][1]) - return True - - """ - Jog turtle - """ - def _jog_turtle(self, dx, dy): - if dx == -1 and dy == -1: - self.canvas.xcor = 0 - self.canvas.ycor = 0 - else: - self.canvas.xcor += dx - self.canvas.ycor += dy - self.canvas.move_turtle() - self.display_coordinates() - self.selected_turtle = None - - """ - Jog block - """ - def _jog_block(self, blk, dx, dy): - if self._collapsed(blk): - return - self.drag_group = self._find_group(blk) - # check to see if any block ends up with a negative x - for blk in self.drag_group: - (sx, sy) = blk.spr.get_xy() - if sx+dx < 0: - dx += -(sx+dx) - # move the stack - for blk in self.drag_group: - (sx, sy) = blk.spr.get_xy() - blk.spr.move((sx+dx, sy-dy)) - self._snap_to_dock() - self.drag_group = None - - """ - Make sure a 'number' block contains a number. - """ - def _number_check(self): - n = self.selected_blk.spr.labels[0].replace(CURSOR,'') - if n in ['-', '.', '-.']: - n = 0 - if n is not None: - try: - f = float(n) - if f > 1000000: - n = 1 - self.showlabel("#overflowerror") - elif f < -1000000: - n = -1 - self.showlabel("#overflowerror") - except ValueError: - n = 0 - self.showlabel("#notanumber") - else: - n = 0 - self.selected_blk.spr.set_label(n) - self.selected_blk.values[0] = n - - def _string_check(self): - s = self.selected_blk.spr.labels[0].replace(CURSOR,'') - self.selected_blk.spr.set_label(s) - self.selected_blk.values[0] = s - - """ - Load Python code from a file - """ - def load_python_code(self): - fname, self.load_save_folder = get_load_name('.py', - self.load_save_folder) - if fname==None: - return - f = open(fname, 'r') - self.myblock = f.read() - f.close() - - """ - Import Python code into a block - """ - def _import_py(self): - if self.running_sugar: - self.activity.import_py() - else: - self.load_python_code() - self.set_userdefined() - - """ - Start a new project - """ - def new_project(self): - stop_logo(self) - # Put current project in the trash. - while len(self.just_blocks()) > 0: - b = self.just_blocks()[0] - top = self.find_top_block(b) - self._put_in_trash(top) - self.canvas.clearscreen() - self.save_file_name = None - - """ - Load a project from a file - """ - def load_files(self, ta_file, create_new_project=True): - if create_new_project is True: - self.new_project() - top = self.process_data(data_from_file(ta_file)) - self._check_collapsibles(top) - - def load_file(self, create_new_project=True): - fname, self.load_save_folder = get_load_name('.ta', - self.load_save_folder) - if fname==None: - return - if fname[-3:] == '.ta': - fname=fname[0:-3] - self.load_files(fname+'.ta', create_new_project) - if create_new_project is True: - self.save_file_name = os.path.basename(fname) - - """ - Turtles are either [-1, 'turtle', ...] or [-1, ['turtle', key], ...] - """ - def _found_a_turtle(self, b): - if b[1] == 'turtle': - self.load_turtle(b) + tw.firstkey = True + if len(keyname)>1: return True - elif type(b[1]) == list and b[1][0] == 'turtle': - self.load_turtle(b, b[1][1]) + else: # gtk.keysyms.Left ... + if keyname in ['Escape', 'Return', 'KP_Page_Up', + 'Up', 'Down', 'Left', 'Right', 'KP_Home', 'KP_End', + 'KP_Up', 'KP_Down', 'KP_Left', 'KP_Right', + 'KP_Page_Down']: + # move blocks (except number and text blocks only with arrows) + # or click with Return + if keyname == 'KP_End': + run_button(tw, 0) + elif tw.spr is not None: + if tw.spr.type == 'turtle': # jog turtle with arrow keys + if keyname == 'KP_Up' or keyname == 'Up': + jog_turtle(tw,0,10) + elif keyname == 'KP_Down' or keyname == 'Down': + jog_turtle(tw,0,-10) + elif keyname == 'KP_Left' or keyname == 'Left': + jog_turtle(tw,-10,0) + elif keyname == 'KP_Right' or keyname == 'Right': + jog_turtle(tw,10,0) + elif keyname == 'KP_Home': + jog_turtle(tw,-1,-1) + elif tw.spr.type == 'block': + if keyname == 'Return' or keyname == 'KP_Page_Up': + click_block(tw) + elif keyname == 'KP_Up' or keyname == 'Up': + jog_block(tw,0,10) + elif keyname == 'KP_Down' or keyname == 'Down': + jog_block(tw,0,-10) + elif keyname == 'KP_Left' or keyname == 'Left': + jog_block(tw,-10,0) + elif keyname == 'KP_Right' or keyname == 'Right': + jog_block(tw,10,0) + elif keyname == 'KP_Page_Down': + if tw.draggroup == None: + tw.draggroup = findgroup(tw.spr) + for b in tw.draggroup: hide(b) + tw.draggroup = None + elif tw.spr.type == 'selbutton': + if keyname == 'Return' or keyname == 'KP_Page_Up': + select_category(tw,tw.spr) + elif tw.spr.type == 'category': + if keyname == 'Return' or keyname == 'KP_Page_Up': + (x,y) = tw.window.get_pointer() + block_selector_pressed(tw,x,y) + for b in tw.draggroup: + move(b, (b.x+200, b.y)) + tw.draggroup = None return True - elif type(b[1]) == tuple: - btype, key = b[1] - if btype == 'turtle': - self.load_turtle(b, key) - return True + if tw.selected_block is None: return False - - """ - Restore a turtle from its saved state - """ - def load_turtle(self, b, key=1): - id, name, xcor, ycor, heading, color, shade, pensize = b - self.canvas.set_turtle(key) - self.canvas.setxy(xcor, ycor) - self.canvas.seth(heading) - self.canvas.setcolor(color) - self.canvas.setshade(shade) - self.canvas.setpensize(pensize) - - """ - Restore individual blocks from saved state - """ - def load_block(self, b): - # A block is saved as: (i, (btype, value), x, y, (c0,... cn)) - # The x,y position is saved/loaded for backward compatibility - btype, value = b[1], None - if type(btype) == tuple: - btype, value = btype - elif type(btype) == list: - btype, value = btype[0], btype[1] - if btype in CONTENT_BLOCKS or btype in COLLAPSIBLE: - if btype == 'number': - try: - values = [int(value)] - except ValueError: - values = [float(value)] - elif btype in COLLAPSIBLE: - if value is not None: - values = [int(value)] - else: - values = [] + if keyname in ['Shift_L', 'Shift_R', 'Control_L', 'Caps_Lock', \ + 'Alt_L', 'Alt_R', 'KP_Enter', 'ISO_Level3_Shift']: + keyname = '' + keyunicode = 0 + # Hack until I sort out input and unicode + dead keys + if keyname[0:5] == 'dead_': + tw.dead_key = keyname + keyname = '' + keyunicode = 0 + if keyname == 'Tab': + keyunicode = 32 # substitute a space for a tab + oldnum = tw.selected_block.label + selblock=tw.selected_block.proto + if keyname == 'BackSpace': + if len(oldnum) > 1: + newnum = oldnum[:len(oldnum)-1] + else: + newnum = '' + setlabel(tw.selected_block, selblock.check(newnum,oldnum)) + if len(newnum) > 0: + tw.firstkey = False + else: + tw.firstkey = True + elif keyname is not '': + # Hack until I sort out input and unicode + dead keys + if tw.dead_key == 'dead_grave': + keyunicode = dead_grave[keyname] + elif tw.dead_key == 'dead_acute': + keyunicode = dead_acute[keyname] + elif tw.dead_key == 'dead_circumflex': + keyunicode = dead_circumflex[keyname] + elif tw.dead_key == 'dead_tilde': + keyunicode = dead_tilde[keyname] + elif tw.dead_key == 'dead_diaeresis': + keyunicode = dead_diaeresis[keyname] + elif tw.dead_key == 'dead_abovering': + keyunicode = dead_abovering[keyname] + tw.dead_key = "" + if tw.firstkey: + newnum = selblock.check(unichr(keyunicode), \ + tw.defdict[selblock.name]) + elif keyunicode > 0: + if unichr(keyunicode) is not '\x00': + newnum = oldnum+unichr(keyunicode) else: - values = [value] - else: - values = [] - - if btype in OLD_DOCK: - check_dock = True + newnum = oldnum else: - check_dock = False - if OLD_NAMES.has_key(btype): - btype = OLD_NAMES[btype] - blk = Block(self.block_list, self.sprite_list, - btype, b[2]+self.canvas.cx, b[3]+self.canvas.cy, 'block', - values, self.block_scale) - # Some blocks get transformed. - if btype == 'nop': - if self.nop == 'pythonloaded': - self._block_skin('pythonon', blk) - else: - self._block_skin('pythonoff', blk) - elif btype in EXPANDABLE: - if btype == 'vspace': - if value is not None: - blk.expand_in_y(value) - elif btype == 'hspace' or btype == 'identity2': - if value is not None: - blk.expand_in_x(value) - elif btype == 'templatelist' or btype == 'list': - for i in range(len(b[4])-4): - dy = blk.add_arg() - elif btype in BOX_STYLE_MEDIA: - if len(blk.values) == 0 or blk.values[0] == 'None' or\ - blk.values[0] == None: - self._block_skin(btype+'off', blk) - elif btype == 'audio' or btype == 'description': - self._block_skin(btype+'on', blk) - elif self.running_sugar: - try: - dsobject = datastore.get(blk.values[0]) - if not movie_media_type(dsobject.file_path[-4:]): - w, h, = calc_image_size(blk.spr) - pixbuf = get_pixbuf_from_journal(dsobject, w, h) - if pixbuf is not None: - x, y = self._calc_image_offset('', blk.spr) - blk.set_image(pixbuf, x, y) - else: - self._block_skin('journalon', blk) - dsobject.destroy() - except: - try: - w, h, = calc_image_size(blk.spr) - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( - blk.values[0], w, h) - x, y = self._calc_image_offset('', blk.spr) - blk.set_image(pixbuf, x, y) - except: - print "Warning: Couldn't open dsobject (%s)" %\ - (blk.values[0]) - self._block_skin('journaloff', blk) - else: - if not movie_media_type(blk.values[0][-4:]): - try: - w, h, = calc_image_size(blk.spr) - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( - blk.values[0], w, h) - x, y = self._calc_image_offset('', blk.spr) - blk.set_image(pixbuf, x, y) - except: - self._block_skin('journaloff', blk) - else: - self._block_skin('journalon', blk) - blk.spr.set_label(' ') - blk.resize() - - blk.spr.set_layer(BLOCK_LAYER) - if check_dock is True: - blk.connections = 'check' - return blk - - """ - Start a new project with a 'start' brick - """ - def load_start(self): - top = self.process_data([[0, "start", PALETTE_WIDTH+20, - ICON_SIZE+PALETTE_HEIGHT+20, [None, None]]]) - - """ - Start a project to a file - """ - def save_file(self): - if self.save_folder is not None: - self.load_save_folder = self.save_folder - fname, self.load_save_folder = get_save_name('.ta', - self.load_save_folder, - self.save_file_name) - if fname is None: + newnum = "" + setlabel(tw.selected_block, selblock.check(newnum,oldnum)) + tw.firstkey = False + return True + +def unselect(tw): + if tw.selected_block.label in ['-', '.', '-.']: + setlabel(tw.selected_block,'0') + + # put an upper and lower bound on numbers to prevent OverflowError + if tw.selected_block.proto.name == 'number' and \ + tw.selected_block.label is not None: + try: + i = float(tw.selected_block.label) + if i > 1000000: + setlabel(tw.selected_block,'1') + showlabel(tw.lc,"#overflowerror") + elif i < -1000000: + setlabel(tw.selected_block,'-1') + showlabel(tw.lc,"#overflowerror") + except ValueError: + pass + + hide(tw.select_mask) + hide(tw.select_mask_string) + tw.selected_block = None + +def jog_turtle(tw,dx,dy): + if dx == -1 and dy == -1: + tw.turtle.xcor = 0 + tw.turtle.ycor = 0 + else: + tw.turtle.xcor += dx + tw.turtle.ycor += dy + move_turtle(tw.turtle) + display_coordinates(tw) + tw.draggroup = None + +def jog_block(tw,dx,dy): + # drag entire stack if moving lock block + if tw.spr.proto.name == 'lock': + tw.draggroup = findgroup(find_top_block(tw.spr)) + else: + tw.draggroup = findgroup(tw.spr) + # check to see if any block ends up with a negative x + for b in tw.draggroup: + if b.x+dx < 0: + dx += -(b.x+dx) + # move the stack + for b in tw.draggroup: + move(b,(b.x+dx, b.y-dy)) + snap_to_dock(tw) + tw.draggroup = None + +def click_block(tw): + if tw.spr.proto.name=='number': + tw.selected_block = tw.spr + move(tw.select_mask, (tw.spr.x-5,tw.spr.y-5)) + setlayer(tw.select_mask, 660) + tw.firstkey = True + elif tw.defdict.has_key(tw.spr.proto.name): + tw.selected_block = tw.spr + if tw.spr.proto.name=='string': + move(tw.select_mask_string, (tw.spr.x-5,tw.spr.y-5)) + setlayer(tw.select_mask_string, 660) + tw.firstkey = True + elif tw.spr.proto.name in importblocks: + import_from_journal(tw, tw.spr) + elif tw.spr.proto.name=='nop' and tw.myblock==None: + tw.activity.import_py() + else: run_stack(tw, tw.spr) + +# +# Block utilities +# + +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 run_stack(tw,spr): + tw.lc.ag = None + top = find_top_block(spr) + run_blocks(tw.lc, top, blocks(tw), True) + gobject.idle_add(doevalstep, tw.lc) + +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): + b = spr + while b.connections[0]!=None: + b=b.connections[0] + return b + +def runtool(tw, spr, cmd, *args): + cmd(*(args)) + +def eraser_button(tw): + # hide status block + setlayer(tw.status_spr,400) + clear(tw.lc) + display_coordinates(tw) + +def stop_button(tw): + stop_logo(tw) + +def run_button(tw, time): + print "you better run, turtle, run!!" + # look for the start block + for b in blocks(tw): + if find_start_stack(tw, b): + tw.step_time = time + if hasattr(tw,'activity'): + tw.activity.recenter() + run_stack(tw, b) return - if fname[-3:]=='.ta': - fname=fname[0:-3] - data = self.assemble_data_to_save() - data_to_file(data, fname+'.ta') - self.save_file_name = os.path.basename(fname) - - """ - Pack the project (or stack) into a data stream to be serialized - """ - def assemble_data_to_save(self, save_turtle=True, save_project=True): - data = [] - blks = [] - - if save_project is True: - blks = self.just_blocks() - else: - blks = self._find_group(self.find_top_block(self.selected_blk)) - - for i, b in enumerate(blks): - b.id = i - for b in blks: - if b.name in CONTENT_BLOCKS or b.name in COLLAPSIBLE: - if len(b.values)>0: - name = (b.name, b.values[0]) - else: - name = (b.name) - elif b.name in EXPANDABLE: - ex, ey = b.get_expand_x_y() - if ex > 0: - name = (b.name, ex) - elif ey > 0: - name = (b.name, ey) - else: - name = (b.name, 0) - else: - name = (b.name) - if hasattr(b, 'connections'): - connections = [get_id(c) for c in b.connections] - else: - connections = None - (sx, sy) = b.spr.get_xy() - # Add a slight offset for copy/paste - if save_project is False: - sx+=20 - sy+=20 - data.append((b.id, name, sx-self.canvas.cx, sy-self.canvas.cy, - connections)) - if save_turtle is True: - for k in iter(self.turtles.dict): - self.canvas.set_turtle(k) - data.append((-1,['turtle', k], - self.canvas.xcor, self.canvas.ycor, - self.canvas.heading, - self.canvas.color, self.canvas.shade, - self.canvas.pensize)) - return data - - """ - Display the coordinates of the current turtle on the toolbar - """ - def display_coordinates(self): - x = round_int(self.canvas.xcor/self.coord_scale) - y = round_int(self.canvas.ycor/self.coord_scale) - h = round_int(self.canvas.heading) - if self.running_sugar: - self.activity.coordinates_label.set_text("%s: %d %s: %d %s: %d" % ( - _("xcor"), x, _("ycor"), y, _("heading"), h)) - self.activity.coordinates_label.show() - else: - self.win.set_title("%s — %s: %d %s: %d %s: %d" % (_("Turtle Art"), - _("xcor"), x, _("ycor"), y, _("heading"), h)) - - """ - Display a message on a status block - """ - def showlabel(self, shp, label=''): - if shp == 'syntaxerror' and str(label) != '': - if self.status_shapes.has_key(str(label)[1:]): - shp = str(label)[1:] - label = '' - else: - shp = 'status' - elif shp[0] == '#': - shp = shp[1:] - label = '' - if shp=='notanumber': - shp = 'overflowerror' - self.status_spr.set_shape(self.status_shapes[shp]) - self.status_spr.set_label(str(label)) - self.status_spr.set_layer(STATUS_LAYER) - if shp == 'info': - self.status_spr.move((PALETTE_WIDTH, self.height-300)) - else: - self.status_spr.move((PALETTE_WIDTH, self.height-200)) - - """ - Relative placement of portfolio objects (used by depreciated blocks) - """ - def calc_position(self, t): - w,h,x,y,dx,dy = TEMPLATES[t] - x *= self.canvas.width - y *= self.canvas.height - w *= (self.canvas.width-x) - h *= (self.canvas.height-y) - dx *= w - dy *= h - return(w,h,x,y,dx,dy) - - """ - Grab the current canvas and save it. - """ - def save_as_image(self, name=""): - if len(name) == 0: - filename = "ta.png" - else: - filename = name+".png" + # no start block, so run a stack that isn't a hat + for b in blocks(tw): + if find_block_to_run(tw, b): + print "running " + b.proto.name + tw.step_time = time + run_stack(tw, b) + return + +def hideshow_button(tw): + if tw.hide is False: + for b in blocks(tw): setlayer(b,100) + hide_palette(tw) + hide(tw.select_mask) + hide(tw.select_mask_string) + tw.hide = True + else: + for b in blocks(tw): setlayer(b,650) + show_palette(tw) + tw.hide = False + inval(tw.turtle.canvas) + +# find start stack +def find_start_stack(tw, spr): + top = find_top_block(spr) + if spr.proto.name == 'start': + return True + else: + return False - if self.running_sugar: - datapath = os.path.join(self.activity.get_activity_root(), - "instance") - else: - datapath = os.getcwd() - file_path = os.path.join(datapath, filename) - save_picture(self.canvas, file_path) - - if self.running_sugar: - dsobject = datastore.create() - if len(name) == 0: - dsobject.metadata['title'] = "%s %s" % (self.metadata['title'], - _("image")) - else: - dsobject.metadata['title'] = name - dsobject.metadata['icon-color'] = profile.get_color().to_string() - dsobject.metadata['mime_type'] = 'image/png' - dsobject.set_file_path(file_path) - datastore.write(dsobject) - dsobject.destroy() - - """ - Where is the mouse event? - """ - def _xy(self, event): - return map(int, event.get_coords()) - - """ - Utilities related to finding blocks in stacks. - """ - - """ - Find a stack to run (any stack without a 'def action'on the top). - """ - def _find_block_to_run(self, blk): - top = self.find_top_block(blk) - if blk == top and blk.name[0:3] is not 'def': - return True - else: - return False - - """ - Find the top block in a stack. - """ - def find_top_block(self, blk): - if len(blk.connections) == 0: - return blk - while blk.connections[0] is not None: - blk = blk.connections[0] - return blk - - """ - Find a stack with a 'start' block on top. - """ - def _find_start_stack(self, blk): - top = self.find_top_block(blk) - if top.name == 'start': - return True - else: - return False - - """ - Find the connected group of block in a stack. - """ - def _find_group(self, blk): - if blk is None: - return [] - group=[blk] - if blk.connections is not None: - for blk2 in blk.connections[1:]: - if blk2 is not None: - group.extend(self._find_group(blk2)) - return group - - """ - Filter out 'proto', 'trash', and 'deleted' blocks - """ - def just_blocks(self): - just_blocks_list = [] - for b in self.block_list.list: - if b.type == 'block': - just_blocks_list.append(b) - return just_blocks_list - - """ - What are the width and height of a stack? - """ - def _width_and_height(self, blk): - minx = 10000 - miny = 10000 - maxx = -10000 - maxy = -10000 - for b in self._find_group(blk): - (x, y) = b.spr.get_xy() - w, h = b.spr.get_dimensions() - if x<minx: - minx = x - if y<miny: - miny = y - if x+w>maxx: - maxx = x+w - if y+h>maxy: - maxy = y+h - return(maxx-minx, maxy-miny) - - """ - Utilities related to putting a image 'skin' on a block - """ - - """ - Calculate the postion for placing an image onto a sprite. - """ - def _calc_image_offset(self, name, spr, iw=0, ih=0): - _l, _t = spr.label_left_top() - if name == '': - return _l, _t - _w = spr.label_safe_width() - _h = spr.label_safe_height() - if iw == 0: - iw = self.media_shapes[name].get_width() - ih = self.media_shapes[name].get_height() - return int(_l+(_w-iw)/2), int(_t+(_h-ih)/2) - - """ - Calculate new image size - """ - def _calc_w_h(self, name, spr): - target_w = spr.label_safe_width() - target_h = spr.label_safe_height() - if name == '': - return target_w, target_h - image_w = self.media_shapes[name].get_width() - image_h = self.media_shapes[name].get_height() - if image_w > target_w or image_h > target_h: - scale_factor = float(target_w)/image_w - new_w = target_w - new_h = image_h*scale_factor - if new_h > target_h: - scale_factor = float(target_h)/new_h - new_h = target_h - new_w = target_w*scale_factor - return int(new_w), int(new_h) - return int(target_w), int(target_h) - - """ - Utility for calculating proto skin images - """ - def _proto_skin(self, name, n, i): - x, y = self._calc_image_offset(name, self.palettes[n][i].spr) - self.palettes[n][i].spr.set_image(self.media_shapes[name], 1, x, y) - - """ - Some blocks get a skin - """ - def _block_skin(self, name, blk): - x, y = self._calc_image_offset(name, blk.spr) - blk.set_image(self.media_shapes[name], x, y) - self._resize_skin(blk) - - """ - Resize the 'skin' when block scale changes. - """ - def _resize_skin(self, b): - if b.name == 'nop': - w, h = self._calc_w_h('pythonoff', b.spr) - x, y = self._calc_image_offset('pythonoff', b.spr, w, h) - elif b.name == 'journal': - if len(b.values) == 1 and b.values[0] is not None: - w, h = self._calc_w_h('', b.spr) - x, y = self._calc_image_offset('journaloff', b.spr, w, h) - else: - w, h = self._calc_w_h('journaloff', b.spr) - x, y = self._calc_image_offset('journaloff', b.spr, w, h) - else: - w, h = self._calc_w_h('descriptionoff', b.spr) - x, y = self._calc_image_offset('descriptionoff', b.spr, w, h) - b.scale_image(x, y, w, h) +# find a stack to run (any stack without a hat) +def find_block_to_run(tw, spr): + top = find_top_block(spr) + if spr == top and spr.proto.name[0:3] != 'hat': + return True + else: + return False + +def blocks(tw): + return [spr for spr in tw.sprites if spr.type == 'block'] + +def xy(event): + return map(int, event.get_coords()) + +def showPopup(block_name,tw): + if blocks_dict.has_key(block_name): + block_name_s = _(blocks_dict[block_name]) + else: + block_name_s = _(block_name) + if hover_dict.has_key(block_name): + label = block_name_s + ": " + hover_dict[block_name] + else: + label = block_name_s + if hasattr(tw, "activity"): + tw.activity.hover_help_label.set_text(label) + tw.activity.hover_help_label.show() + elif hasattr(tw, "win"): + tw.win.set_title(_("Turtle Art") + " — " + label) + return 0 |