Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TurtleArtActivity.py55
-rw-r--r--tawindow.py1708
-rwxr-xr-xturtleart.py14
3 files changed, 955 insertions, 822 deletions
diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py
index 55e9c55..a622098 100644
--- a/TurtleArtActivity.py
+++ b/TurtleArtActivity.py
@@ -226,7 +226,7 @@ class TurtleArtActivity(activity.Activity):
FILE = open(dsobject.file_path, "r")
self.tw.myblock = FILE.read()
FILE.close()
- tawindow.set_userdefined(self.tw)
+ self.tw.set_userdefined()
# save reference to Pythin code in the project metadata
self.metadata['python code'] = dsobject.object_id
except:
@@ -244,6 +244,8 @@ class TurtleArtActivity(activity.Activity):
# Write the file to the instance directory of this activity's root.
file_path = os.path.join(datapath, filename)
+ # FIXME: this was like this before refactoring, the save_pict
+ # belongs to taproject (not tawindow)
tawindow.save_pict(self.tw,file_path)
# Create a datastore object
@@ -278,6 +280,7 @@ class TurtleArtActivity(activity.Activity):
tafile = os.path.join(tmppath,"tmpfile.ta")
print tafile
try:
+ # FIXME: encapsulation?
tawindow.save_data(self.tw,tafile)
except:
_logger.debug("couldn't save snapshot to journal")
@@ -303,11 +306,11 @@ class TurtleArtActivity(activity.Activity):
""" Show/hide palette """
def _do_palette_cb(self, button):
if self.tw.palette == True:
- tawindow.hideshow_palette(self.tw,False)
+ self.tw.hideshow_palette(False)
self.palette_button.set_icon("blockson")
self.palette_button.set_tooltip(_('Show palette'))
else:
- tawindow.hideshow_palette(self.tw,True)
+ self.tw.hideshow_palette(True)
self.palette_button.set_icon("blocksoff")
self.palette_button.set_tooltip(_('Hide palette'))
@@ -323,7 +326,7 @@ class TurtleArtActivity(activity.Activity):
self.palette_button.set_tooltip(_('Hide palette'))
def _do_hideshow_cb(self, button):
- tawindow.hideshow_button(self.tw)
+ self.tw.hideshow_button()
if self.tw.hide == True: # we just hid the blocks
self.blocks_button.set_icon("hideshowon")
self.blocks_button.set_tooltip(_('Show blocks'))
@@ -353,42 +356,43 @@ class TurtleArtActivity(activity.Activity):
def _do_eraser_cb(self, button):
self.eraser_button.set_icon("eraseroff")
self.recenter()
- tawindow.eraser_button(self.tw)
+ self.tw.eraser_button()
gobject.timeout_add(250,self.eraser_button.set_icon,"eraseron")
def _do_run_cb(self, button):
self.run_button.set_icon("run-faston")
self.stop_button.set_icon("stopiton")
self.tw.lc.trace = 0
- tawindow.run_button(self.tw, 0)
+ self.tw.run_button(0)
gobject.timeout_add(1000,self.run_button.set_icon,"run-fastoff")
def _do_step_cb(self, button):
self.step_button.set_icon("run-slowon")
self.stop_button.set_icon("stopiton")
self.tw.lc.trace = 0
- tawindow.run_button(self.tw, 3)
+ self.tw.run_button(3)
gobject.timeout_add(1000,self.step_button.set_icon,"run-slowoff")
def _do_debug_cb(self, button):
self.debug_button.set_icon("debugon")
self.stop_button.set_icon("stopiton")
self.tw.lc.trace = 1
- tawindow.run_button(self.tw, 6)
+ self.tw.run_button(6)
gobject.timeout_add(1000,self.debug_button.set_icon,"debugoff")
def _do_stop_cb(self, button):
self.stop_button.set_icon("stopitoff")
- tawindow.stop_button(self.tw)
+ self.tw.stop_button()
self.step_button.set_icon("run-slowoff")
self.run_button.set_icon("run-fastoff")
""" Sample projects open dialog """
def _do_samples_cb(self, button):
+ # FIXME: encapsulation!
tawindow.load_file(self.tw, True)
# run the activity
self.stop_button.set_icon("stopiton")
- tawindow.run_button(self.tw, 0)
+ self.tw.run_button(0)
"""
Recenter scrolled window around canvas
@@ -412,17 +416,21 @@ class TurtleArtActivity(activity.Activity):
"""
def _do_cartesian_cb(self, button):
if self.tw.cartesian is True:
+ # FIXME: encapsulation
tawindow.hide(self.tw.cartesian_coordinates_spr)
self.tw.cartesian = False
else:
+ # FIXME: encapsulation
tawindow.setlayer(self.tw.cartesian_coordinates_spr,610)
self.tw.cartesian = True
def _do_polar_cb(self, button):
if self.tw.polar is True:
+ # FIXME: encapsulation
tawindow.hide(self.tw.polar_coordinates_spr)
self.tw.polar = False
else:
+ # FIXME: encapsulation
tawindow.setlayer(self.tw.polar_coordinates_spr,610)
self.tw.polar = True
@@ -434,12 +442,12 @@ class TurtleArtActivity(activity.Activity):
self.tw.coord_scale = self.tw.height/200
self.rescale_button.set_icon("contract-coordinates")
self.rescale_button.set_tooltip(_('Rescale coordinates down'))
- tawindow.eraser_button(self.tw)
+ self.tw.eraser_button()
else:
self.tw.coord_scale = 1
self.rescale_button.set_icon("expand-coordinates")
self.rescale_button.set_tooltip(_('Rescale coordinates up'))
- tawindow.eraser_button(self.tw)
+ self.tw.eraser_button()
"""
Either set up initial share...
@@ -540,31 +548,31 @@ class TurtleArtActivity(activity.Activity):
e,x,y,mask = re.split(":",text)
# _logger.debug("receiving button press: "+x+" "+y+" "+mask)
if mask == 'T':
- tawindow.button_press(self.tw,True,int(x),int(y),False)
+ self.tw.button_press(True,int(x),int(y),False)
else:
- tawindow.button_press(self.tw,False,int(x),int(y),False)
+ self.tw.button_press(False,int(x),int(y),False)
elif text[0] == 'r': # block release
e,x,y = re.split(":",text)
# _logger.debug("receiving button release: " + x + " " + y)
- tawindow.button_release(self.tw,int(x),int(y),False)
+ self.tw.button_release(int(x),int(y),False)
elif text[0] == 'm': # mouse move
e,x,y = re.split(":",text)
_logger.debug("receiving move: " + x + " " + y)
- tawindow.mouse_move(self.tw,0,0,False,int(x),int(y))
+ self.tw.mouse_move(0,0,False,int(x),int(y))
elif text[0] == 'k': # typing
e,mask,keyname = re.split(":",text,3)
# _logger.debug("recieving key press: " + mask + " " + keyname)
if mask == 'T':
- tawindow.key_press(self.tw,True,keyname,False)
+ self.tw.key_press(True,keyname,False)
else:
- tawindow.key_press(self.tw,False,keyname,False)
+ self.tw.key_press(False,keyname,False)
elif text[0] == 'i': # request for current state
# sharer should send current state to joiner
if self.initiating is True:
_logger.debug("serialize the project and send to joiner")
text = tawindow.save_string(self.tw)
self._send_event("I:" + text)
- tawindow.show_palette(self.tw)
+ self.tw.show_palette()
elif text[0] == 'I': # receiving current state
if self.waiting_for_blocks:
_logger.debug("receiving project from sharer")
@@ -870,8 +878,9 @@ class TurtleArtActivity(activity.Activity):
self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.sw.show()
canvas = gtk.DrawingArea()
- canvas.set_size_request(gtk.gdk.screen_width()*2, \
- gtk.gdk.screen_height()*2)
+ width = gtk.gdk.screen_width() * 2
+ height = gtk.gdk.screen_height() * 2
+ canvas.set_size_request(width, height)
self.sw.add_with_viewport(canvas)
canvas.show()
return canvas
@@ -936,7 +945,7 @@ class TurtleArtActivity(activity.Activity):
"""
def _setup_canvas(self, canvas, lang):
bundle_path = activity.get_bundle_path()
- self.tw = tawindow.twNew(canvas, bundle_path, lang, self)
+ self.tw = tawindow.TurtleArtWindow(canvas, bundle_path, lang, self)
self.tw.activity = self
self.tw.window.grab_focus()
path = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'data')
@@ -1043,7 +1052,7 @@ class TurtleArtActivity(activity.Activity):
# Use pre-0.86 toolbar design
self.projectToolbar.stop.set_icon("stopiton")
- tawindow.run_button(self.tw, 0)
+ self.tw.run_button(0)
else:
_logger.debug("Deferring reading file %s" % file_path)
diff --git a/tawindow.py b/tawindow.py
index d3241cd..5af0600 100644
--- a/tawindow.py
+++ b/tawindow.py
@@ -21,6 +21,15 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
+
+# TODO:
+# - we need a method to know if we are running inside Sugar (vs. stand-alone)
+# - we need helper methods to discriminate what XO version we are using (if any)
+# - verbose flag should be in the scope of the object instance
+# - better comments!
+#
+
+
import pygtk
pygtk.require('2.0')
import gtk
@@ -33,7 +42,6 @@ import time
# Import from Journal for these blocks
importblocks = ['audiooff', 'descriptionoff','journal']
-class taWindow: pass
from math import atan2, pi
DEGTOR = 2*pi/360
@@ -67,248 +75,391 @@ dead_abovering = {'A':197,'a':229}
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"
- return tw
+"""
+TurtleArt Window class abstraction
+"""
+class TurtleArtWindow():
+
+ def __init__(self, win, path, lang, parent=None):
+ self.window = win
+ self.path = os.path.join(path,'images')
+ self.path_lang = os.path.join(path,'images',lang)
+ self.path_en = os.path.join(path,'images/en') # en as fallback
+ self.load_save_folder = os.path.join(path,'samples')
+ self.save_folder = None
+ self.save_file_name = None
+ win.set_flags(gtk.CAN_FOCUS)
+ self.width = gtk.gdk.screen_width()
+ self.height = gtk.gdk.screen_height()
+
+ # starting from command line
+ if parent is None:
+ win.show_all()
+ # starting from Sugar
+ else:
+ parent.show_all()
+
+ self._setup_events()
+
+ self.keypress = ""
+ self.keyvalue = 0
+ self.dead_key = ""
+ self.area = self.window.window
+ self.gc = self.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'):
+ self.lead = 1.6
+ self.scale = 1.0
+ else:
+ self.lead = 1.0
+ self.scale = 1.6
+ 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.sprites = []
+ self.selected_block = None
+ self.draggroup = None
+ prep_selectors(self)
+ self.myblock = None
+ self.nop = 'nop'
+ self.loaded = 0
+ for s in selectors:
+ setup_selectors(self,s)
+ setup_misc(self)
+ self.step_time = 0
+ self.hide = False
+ self.palette = True
+ self._select_category(self.selbuttons[0])
+ self.coord_scale = 1
+ self.turtle = tNew(self,self.width,self.height)
+ self.lc = lcNew(self)
+ self.buddies = []
+ self.dx = 0
+ self.dy = 0
+ self.cartesian = False
+ self.polar = False
+ self.spr = None # "currently selected spr"
+
+
+ """
+ DEPRECATED
+ """
+ def runtool(self, spr, cmd, *args):
+ cmd(*(args))
+
+ """
+ eraser_button: hide status block
+ """
+ def eraser_button(self):
+ setlayer(self.status_spr,400)
+ clear(self.lc)
+ display_coordinates(self)
+
+ """
+ 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):
+ list = self.sprites[:]
+ for spr in list:
+ if hasattr(spr,'proto') and spr.proto.name == 'nop':
+ setimage(spr,self.media_shapes['pythonloaded'])
+ self.nop = 'pythonloaded'
+
+
+ """
+ hideshow button
+ """
+ def hideshow_button(self):
+ if self.hide is False:
+ for b in self._blocks(): setlayer(b,100)
+ self._hide_palette()
+ hide(self.select_mask)
+ hide(self.select_mask_string)
+ self.hide = True
+ else:
+ for b in self._blocks(): setlayer(b,650)
+ self.show_palette()
+ self.hide = False
+ inval(self.turtle.canvas)
+
+
+ """
+ run turtle!
+ """
+ def run_button(self, time):
+ print "you better run, turtle, run!!"
+ # look for the start block
+ for b in self._blocks():
+ if self._find_start_stack(b):
+ self.step_time = time
+ if hasattr(self, 'activity'):
+ self.activity.recenter()
+ self._run_stack(b)
+ return
+ # no start block, so run a stack that isn't a hat
+ for b in self._blocks():
+ if self._find_block_to_run(b):
+ print "running " + b.proto.name
+ self.step_time = time
+ self._run_stack(b)
+ return
-#
-# Button Press
-#
+ """
+ button_press
+ """
+ def button_press(self, mask, x, y, verbose=False):
+ if verbose:
+ print "processing remote button press: " + str(x) + " " + str(y)
+ self.block_operation = 'click'
+ if self.selected_block != None:
+ self._unselect()
+ else:
+ setlayer(self.status_spr,400)
+ spr = findsprite(self,(x,y))
+ self.x, self.y = x,y
+ self.dx = 0
+ self.dy = 0
+ if spr is None:
+ return True
+ if spr.type == "canvas":
+ return True
+ elif spr.type == 'selbutton':
+ self._select_category(spr)
+ elif spr.type == 'category':
+ self._block_selector_pressed(x,y)
+ elif spr.type == 'block':
+ self._block_pressed(mask,x,y,spr)
+ elif spr.type == 'turtle':
+ self._turtle_pressed(x,y)
+ self.spr = spr
+
+
+ """
+ hideshow_palette
+ """
+ def hideshow_palette(self, state):
+ if state is False:
+ self.palette == False
+ if hasattr(self, 'activity'):
+ # Use new toolbar design
+ self.activity.do_hidepalette()
+ self._hide_palette()
+ else:
+ self.palette == True
+ if hasattr(self, 'activity'):
+ # Use new toolbar design
+ self.activity.do_showpalette()
+ self.show_palette()
+
+ """
+ show palette
+ """
+ def show_palette(self):
+ for i in self.selbuttons: setlayer(i,800)
+ self._select_category(self.selbuttons[0])
+ self.palette = True
+
+
+ """
+ unselect
+ """
+ def _unselect(self):
+ if self.selected_block.label in ['-', '.', '-.']:
+ setlabel(self.selected_block,'0')
+
+ # put an upper and lower bound on numbers to prevent OverflowError
+ if self.selected_block.proto.name == 'number' and \
+ self.selected_block.label is not None:
+ try:
+ i = float(self.selected_block.label)
+ if i > 1000000:
+ setlabel(self.selected_block,'1')
+ showlabel(self.lc,"#overflowerror")
+ elif i < -1000000:
+ setlabel(self.selected_block,'-1')
+ showlabel(self.lc,"#overflowerror")
+ except ValueError:
+ pass
-def buttonpress_cb(win, event, tw):
- win.grab_focus()
- x, y = xy(event)
- button_press(tw, event.get_state()&gtk.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()&gtk.gdk.CONTROL_MASK is True:
- tw.activity._send_event("p:"+str(x)+":"+str(y)+":"+'T')
+ hide(self.select_mask)
+ hide(self.select_mask_string)
+ self.selected_block = None
+
+
+ """
+ select category
+ """
+ def _select_category(self, spr):
+ if hasattr(self, 'current_category'):
+ setshape(self.current_category, self.current_category.offshape)
+ setshape(spr, spr.onshape)
+ self.current_category = spr
+ setshape(self.category_spr,spr.group)
+
+ """
+ hide palette
+ """
+ def _hide_palette(self):
+ for i in self.selbuttons: hide(i)
+ setshape(self.category_spr, self.hidden_palette_icon)
+ self.palette = False
+
+
+ """
+ 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)
+
+ def xy(self, event):
+ return map(int, event.get_coords())
+
+
+ """
+ find a stack to run (any stack without a hat)
+ """
+ def _find_block_to_run(self, spr):
+ top = self._find_top_block(spr)
+ if spr == top and spr.proto.name[0:3] != 'hat':
+ return True
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
- 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]
-
-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)
-
-def new_block_from_category(tw,proto,x,y):
- if proto is None:
- return True
- # 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
+ return False
+
+ """
+ find top block
+ """
+ def _find_top_block(self, spr):
+ b = spr
+ while b.connections[0]!=None:
+ b=b.connections[0]
+ return b
+
+ """
+ find start stack
+ """
+ def _find_start_stack(self, spr):
+ top = self._find_top_block(spr)
+ if spr.proto.name == 'start':
+ return True
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]
+ return False
+
+ """
+ tube available?
+ """
+ def _sharing(self):
+ ret = False
+ if hasattr(self, 'activity') and hasattr(self.activity, 'chattube'):
+ if self.activity.chattube is not None:
+ ret = True
+ return ret
+
+
+ """
+ Mouse move
+ """
+ def _move_cb(self, win, event):
+ x,y = self.xy(event)
+ self._mouse_move(x, y)
+ return True
-#
-# Mouse move
-#
+ def _mouse_move(self, x, y, verbose=False, mdx=0, mdy=0):
+ if verbose:
+ print "processing remote mouse move: " + str(x) + " " + str(y)
+ if self.draggroup is None:
+ self._show_popup(x, y)
+ return
-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))
+ self.block_operation = 'move'
+ spr = self.draggroup[0]
+ if spr.type == 'block':
+ self.spr = spr
+ dragx, dragy = self.dragpos
+ if mdx != 0 or mdy != 0:
+ dx,dy = mdx,mdy
+ else:
+ 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
+ # drag entire stack if moving lock block
+ if spr.proto.name == 'lock':
+ self.draggroup = findgroup(find_top_block(spr))
+ else:
+ self.draggroup = findgroup(spr)
+ # check to see if any block ends up with a negative x
+ for b in self.draggroup:
+ if b.x+dx < 0:
+ dx += -(b.x+dx)
+ # move the stack
+ for b in self.draggroup:
+ move(b,(b.x+dx, b.y+dy))
+ elif spr.type=='turtle':
+ type,dragx,dragy = self.dragpos
+ if type == 'move':
+ if mdx != 0 or mdy != 0:
+ dx,dy = mdx,mdy
+ else:
+ 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:
+ dx,dy = x-spr.x-30,y-spr.y-30
+ seth(self.turtle, int(dragx+atan2(dy,dx)/DEGTOR+5)/10*10)
+ if mdx != 0 or mdy != 0:
+ dx,dy = 0,0
+ else:
+ self.dx += dx
+ self.dy += dy
+
+ """
+ get_proto_from_category
+ """
+ def _get_proto_from_category(self, x, y):
+ dx, dy = x-self.category_spr.x, y-self.category_spr.y,
+ pixel = getpixel(self.current_category.mask,dx,dy)
+ index = ((pixel%256)>>3)-1
+ if index==0:
+ return 'hide'
+ index-=1
+ if index>len(self.current_category.blockprotos):
+ return None
+ return self.current_category.blockprotos[index]
+
+ """
+ lets help our our user by displaying a little help
+ """
+ def _show_popup(self, x, y):
+ spr = findsprite(self, (x,y))
if spr and spr.type == 'category':
- proto = get_proto_from_category(tw,x,y)
+ proto = self._get_proto_from_category(x, y)
if proto and proto!='hide':
if timeout_tag[0] == 0:
- timeout_tag[0] = showPopup(proto.name,tw)
- tw.spr = spr
+ timeout_tag[0] = self._do_show_popup(proto.name)
+ self.spr = spr
return
else:
if timeout_tag[0] > 0:
@@ -319,8 +470,8 @@ def mouse_move(tw, x, y, verbose=False, mdx=0, mdy=0):
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
+ timeout_tag[0] = self._do_show_popup(spr.name)
+ self.spr = spr
else:
if timeout_tag[0] > 0:
try:
@@ -330,8 +481,8 @@ def mouse_move(tw, x, y, verbose=False, mdx=0, mdy=0):
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
+ timeout_tag[0] = self._do_show_popup(spr.proto.name)
+ self.spr = spr
else:
if timeout_tag[0] > 0:
try:
@@ -346,580 +497,553 @@ def mouse_move(tw, x, y, verbose=False, mdx=0, mdy=0):
timeout_tag[0] = 0
except:
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
+
+ """
+ fetch the help text and display it
+ """
+ def _do_show_popup(self, block_name):
+ if blocks_dict.has_key(block_name):
+ block_name_s = _(blocks_dict[block_name])
else:
- 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
- # drag entire stack if moving lock block
- if spr.proto.name == 'lock':
- tw.draggroup = findgroup(find_top_block(spr))
+ block_name_s = _(block_name)
+ if hover_dict.has_key(block_name):
+ label = block_name_s + ": " + hover_dict[block_name]
else:
- 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:
- dx,dy = x-dragx-spr.x,y-dragy-spr.y
- move(spr, (spr.x+dx, spr.y+dy))
+ label = block_name_s
+ if hasattr(self, "activity"):
+ self.activity.hover_help_label.set_text(label)
+ self.activity.hover_help_label.show()
+ elif hasattr(self, "win"):
+ self.win.set_title(_("Turtle Art") + " — " + label)
+ return 0
+
+
+ """
+ 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()&gtk.gdk.MOD1_MASK:
+ alt_mask = True
else:
- if mdx != 0 or mdy != 0:
- dx,dy = mdx,mdy
+ alt_mask = False
+ results = self._key_press(alt_mask, keyname, keyunicode)
+ if keyname is not None and self._sharing():
+ if alt_mask:
+ self.activity._send_event("k:"+'T'+":"+keyname+":"+str(keyunicode))
else:
- 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
+ self.activity._send_event("k:"+'F'+":"+keyname+":"+str(keyunicode))
+ return keyname
-#
-# 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'])
+ def _key_press(self, alt_mask, keyname, keyunicode, verbose=False):
+ if keyname is None:
+ return False
+ if verbose:
+ print "processing remote key press: " + keyname
+ self.keypress = keyname
+ if alt_mask is True and self.selected_block==None:
+ if keyname=="i" and hasattr(self, 'activity'):
+ 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
+ if self.selected_block is not None and \
+ self.selected_block.proto.name == 'number':
+ if keyname in ['minus', 'period']:
+ keyname = {'minus': '-', 'period': '.'}[keyname]
+ oldnum = self.selected_block.label
+ selblock=self.selected_block.proto
+ if keyname == 'BackSpace':
+ if len(oldnum) > 1:
+ newnum = oldnum[:len(oldnum)-1]
else:
- 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
- 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 block2.connections[dock2n] != None:
- return (100,100)
- 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
- else:
- if d2type == 'num' or d2type == 'string':
- pass
- # 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:
- 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()&gtk.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
- 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
+ newnum = ''
+ setlabel(self.selected_block, selblock.check(newnum,oldnum))
+ if len(newnum) > 0:
+ self.firstkey = False
+ else:
+ self.firstkey = True
+ if len(keyname)>1:
+ return True
+ else: # gtk.keysyms.Left ...
+ if keyname in ['Escape', 'Return', 'j', 'k', 'h', 'l', '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':
+ self.run_button(0)
+ elif self.spr is not None:
+ if self.spr.type == 'turtle': # jog turtle with arrow keys
+ if keyname == 'KP_Up' or keyname == 'j' or keyname == 'Up':
+ self._jog_turtle(0,10)
+ elif keyname == 'KP_Down' or keyname == 'k' or \
+ keyname == 'Down':
+ self._jog_turtle(0,-10)
+ elif keyname == 'KP_Left' or keyname == 'h' or \
+ keyname == 'Left':
+ self._jog_turtle(-10,0)
+ elif keyname == 'KP_Right' or keyname == 'l' or \
+ keyname == 'Right':
+ self._jog_turtle(10,0)
+ elif keyname == 'KP_Home':
+ self._jog_turtle(-1,-1)
+ elif self.spr.type == 'block':
+ if keyname == 'Return' or keyname == 'KP_Page_Up':
+ self._click_block()
+ elif keyname == 'KP_Up' or keyname == 'j' or \
+ keyname == 'Up':
+ self._jog_block(0,10)
+ elif keyname == 'KP_Down' or keyname == 'k' or \
+ keyname == 'Down':
+ self._jog_block(0,-10)
+ elif keyname == 'KP_Left' or keyname == 'h' or \
+ keyname == 'Left':
+ self._jog_block(-10,0)
+ elif keyname == 'KP_Right' or keyname == 'l' or \
+ keyname == 'Right':
+ self._jog_block(10,0)
+ elif keyname == 'KP_Page_Down':
+ if self.draggroup == None:
+ self.draggroup = findgroup(self.spr)
+ for b in self.draggroup: hide(b)
+ self.draggroup = None
+ elif self.spr.type == 'selbutton':
+ if keyname == 'Return' or keyname == 'KP_Page_Up':
+ self._select_category(self.spr)
+ elif self.spr.type == 'category':
+ if keyname == 'Return' or keyname == 'KP_Page_Up':
+ (x,y) = self.window.get_pointer()
+ self._block_selector_pressed(x, y)
+ for b in self.draggroup:
+ move(b, (b.x+200, b.y))
+ self.draggroup = None
+ return True
+ if self.selected_block is None:
+ return False
+ 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_':
+ self.dead_key = keyname
+ keyname = ''
+ keyunicode = 0
+ if keyname == 'Tab':
+ keyunicode = 32 # substitute a space for a tab
+ oldnum = self.selected_block.label
+ selblock=self.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))
+ setlabel(self.selected_block, selblock.check(newnum,oldnum))
if len(newnum) > 0:
- tw.firstkey = False
+ self.firstkey = False
else:
- tw.firstkey = True
- if len(keyname)>1:
- return True
- else: # gtk.keysyms.Left ...
- if keyname in ['Escape', 'Return', 'j', 'k', 'h', 'l', '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 == 'j' or keyname == 'Up':
- jog_turtle(tw,0,10)
- elif keyname == 'KP_Down' or keyname == 'k' or \
- keyname == 'Down':
- jog_turtle(tw,0,-10)
- elif keyname == 'KP_Left' or keyname == 'h' or \
- keyname == 'Left':
- jog_turtle(tw,-10,0)
- elif keyname == 'KP_Right' or keyname == 'l' 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 == 'j' or \
- keyname == 'Up':
- jog_block(tw,0,10)
- elif keyname == 'KP_Down' or keyname == 'k' or \
- keyname == 'Down':
- jog_block(tw,0,-10)
- elif keyname == 'KP_Left' or keyname == 'h' or \
- keyname == 'Left':
- jog_block(tw,-10,0)
- elif keyname == 'KP_Right' or keyname == 'l' 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
+ self.firstkey = True
+ elif keyname is not '':
+ # Hack until I sort out input and unicode + dead keys
+ if self.dead_key == 'dead_grave':
+ keyunicode = dead_grave[keyname]
+ elif self.dead_key == 'dead_acute':
+ keyunicode = dead_acute[keyname]
+ elif self.dead_key == 'dead_circumflex':
+ keyunicode = dead_circumflex[keyname]
+ elif self.dead_key == 'dead_tilde':
+ keyunicode = dead_tilde[keyname]
+ elif self.dead_key == 'dead_diaeresis':
+ keyunicode = dead_diaeresis[keyname]
+ elif self.dead_key == 'dead_abovering':
+ keyunicode = dead_abovering[keyname]
+ self.dead_key = ""
+ if self.firstkey:
+ newnum = selblock.check(unichr(keyunicode), \
+ self.defdict[selblock.name])
+ elif keyunicode > 0:
+ if unichr(keyunicode) is not '\x00':
+ newnum = oldnum+unichr(keyunicode)
+ else:
+ newnum = oldnum
+ else:
+ newnum = ""
+ setlabel(self.selected_block, selblock.check(newnum,oldnum))
+ self.firstkey = False
+ return True
+
+
+
+
+ """
+ Button release
+ """
+ def _buttonrelease_cb(self, win, event):
+ x,y = self.xy(event)
+ self.button_release(x, y)
+ if self._sharing():
+ # print "sending release button"
+ 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: " + str(self.dx) + " " + str(self.dy)
+ self.activity._send_event("m:"+str(self.dx)+":"+str(self.dy))
+ self.dx = 0
+ self.dy = 0
+
+ if verbose:
+ print "processing remote button release: " + str(x) + " " + str(y)
+ if self.draggroup == None:
+ return
+ spr = self.draggroup[0]
+ if spr.type == 'turtle':
+ self.turtle.xcor = self.turtle.spr.x-self.turtle.canvas.x- \
+ self.turtle.canvas.width/2+30
+ self.turtle.ycor = self.turtle.canvas.height/2-self.turtle.spr.y+ \
+ self.turtle.canvas.y-30
+ move_turtle(self.turtle)
+ display_coordinates(self)
+ self.draggroup = None
+ return
+ if self.block_operation=='move' and hit(self.category_spr, (x,y)):
+ for b in self.draggroup: hide(b)
+ self.draggroup = None
+ return
+ if self.block_operation=='new':
+ for b in self.draggroup:
+ move(b, (b.x+200, b.y))
+ self._snap_to_dock()
+ for b in self.draggroup: setlayer(b,650)
+ self.draggroup = None
+ if self.block_operation=='click':
+ if self.spr.proto.name=='number':
+ self.selected_block = spr
+ move(self.select_mask, (spr.x-5,spr.y-5))
+ setlayer(self.select_mask, 660)
+ self.firstkey = True
+ elif self.defdict.has_key(spr.proto.name):
+ self.selected_block = spr
+ if self.spr.proto.name=='string':
+ move(self.select_mask_string, (spr.x-5,spr.y-5))
+ setlayer(self.select_mask_string, 660)
+ self.firstkey = True
+ elif self.spr.proto.name in importblocks:
+ self._import_from_journal(spr)
+ elif self.spr.proto.name=='nop' and self.myblock==None:
+ self.activity.import_py()
+ else: self._run_stack(spr)
+
+ """
+ click block
+ """
+ def _click_block(self):
+ if self.spr.proto.name=='number':
+ self.selected_block = self.spr
+ move(self.select_mask, (self.spr.x-5,self.spr.y-5))
+ setlayer(self.select_mask, 660)
+ self.firstkey = True
+ elif self.defdict.has_key(self.spr.proto.name):
+ self.selected_block = self.spr
+ if self.spr.proto.name=='string':
+ move(self.select_mask_string, (self.spr.x-5,self.spr.y-5))
+ setlayer(self.select_mask_string, 660)
+ self.firstkey = True
+ elif self.spr.proto.name in importblocks:
+ self._import_from_journal(self.spr)
+ elif self.spr.proto.name=='nop' and self.myblock==None:
+ self.activity.import_py()
+ else: self._run_stack(self.spr)
+
+ """
+ Repaint
+ """
+ def _expose_cb(self, win, event):
+ # FIXME
+ redrawsprites(self)
+ return True
+
+ """
+ Button Press
+ """
+ def _buttonpress_cb(self, win, event):
+ self.window.grab_focus()
+ x, y = self.xy(event)
+ self.button_press(event.get_state()&gtk.gdk.CONTROL_MASK, x, y)
+
+ # if sharing, send button press
+ if self._sharing():
+ # print "sending button pressed"
+ if event.get_state()&gtk.gdk.CONTROL_MASK is True:
+ self.activity._send_event("p:"+str(x)+":"+str(y)+":"+'T')
+ else:
+ self.activity._send_event("p:"+str(x)+":"+str(y)+":"+'F')
+ return True
+
+
+ """
+ snap_to_dock
+ """
+ def _snap_to_dock(self):
+ d=200
+ me = self.draggroup[0]
+ for mydockn in range(len(me.proto.docks)):
+ for you in self._blocks():
+ if you in self.draggroup:
+ continue
+ for yourdockn in range(len(you.proto.docks)):
+ thisxy = self._dock_dx_dy(you,yourdockn,me,mydockn)
+ if self._magnitude(thisxy) > d:
+ continue
+ d = self._magnitude(thisxy)
+ bestxy=thisxy
+ bestyou=you
+ bestyourdockn=yourdockn
+ bestmydockn=mydockn
+ if d<200:
+ for b in self.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
+
+
+ """
+ import from Journal
+ """
+ def _import_from_journal(self, spr):
+ if hasattr(self, "activity"): # this should be a method: _inside_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()
+ # change block graphic to indicate that object is "loaded"
+ if spr.proto.name == 'journal':
+ self._load_image(dsobject, spr)
+ elif spr.proto.name == 'audiooff':
+ setimage(spr,self.media_shapes['audioon'])
+ else:
+ setimage(spr, self.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"
+
+ """
+ run stack
+ """
+ def _run_stack(self, spr):
+ self.lc.ag = None
+ top = self._find_top_block(spr)
+ run_blocks(self.lc, top, self._blocks(), True)
+ gobject.idle_add(doevalstep, self.lc)
+
+ """
+ filter out blocks
+ """
+ def _blocks(self):
+ return [spr for spr in self.sprites if spr.type == 'block']
+
+ """
+ block selector pressed
+ """
+ def _block_selector_pressed(self, x, y):
+ proto = self._get_proto_from_category(x, y)
+ if proto==None:
+ return
+ if proto is not 'hide':
+ self._new_block_from_category(proto, x, y)
+ else:
+ self.hideshow_palette(False)
+
+
+ """
+ new block from category
+ """
+ def _new_block_from_category(self, proto, x, y):
+ if proto is None:
return True
- if tw.selected_block is None:
- return False
- 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]
+ # load alternative image of nop block if python code is loaded
+ if proto.name == 'nop' and self.nop == 'pythonloaded':
+ newspr = sprNew(self,x-20,y-20,self.media_shapes['pythonloaded'])
else:
- newnum = ''
- setlabel(tw.selected_block, selblock.check(newnum,oldnum))
- if len(newnum) > 0:
- tw.firstkey = False
+ newspr = sprNew(self,x-20,y-20,proto.image)
+ setlayer(newspr,2000)
+ self.dragpos = 20,20
+ newspr.type = 'block'
+ newspr.proto = proto
+ if self.defdict.has_key(newspr.proto.name):
+ newspr.label=self.defdict[newspr.proto.name]
+ newspr.connections = [None]*len(proto.docks)
+ for i in range(len(proto.defaults)):
+ dock = proto.docks[i+1]
+ argproto = self.protodict[self.valdict[dock[0]]]
+ argdock = argproto.docks[0]
+ nx,ny = newspr.x+dock[2]-argdock[2],newspr.y+dock[3]-argdock[3]
+ argspr = sprNew(self,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
+ self.draggroup = findgroup(newspr)
+ self.block_operation = 'new'
+
+
+ """
+ block pressed
+ """
+ def _block_pressed(self, mask, x, y, spr):
+ if spr is not None:
+ self.draggroup = findgroup(spr)
+ for b in self.draggroup: setlayer(b,2000)
+ if spr.connections[0] != None and spr.proto.name == 'lock':
+ b = self._find_top_block(spr)
+ self.dragpos = x-b.x,y-b.y
+ else:
+ self.dragpos = x-spr.x,y-spr.y
+ self._disconnect(spr)
+
+
+ """
+ disconnect block
+ """
+ def _disconnect(self, b):
+ if b.connections[0]==None:
+ return
+ b2=b.connections[0]
+ b2.connections[b2.connections.index(b)] = None
+ b.connections[0] = None
+
+ """
+ turtle pressed
+ """
+ def _turtle_pressed(self, x, y):
+ dx,dy = x-self.turtle.spr.x-30,y-self.turtle.spr.y-30
+ if dx*dx+dy*dy > 200:
+ self.dragpos = ('turn', \
+ self.turtle.heading-atan2(dy,dx)/DEGTOR,0)
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)
+ self.dragpos = ('move', x-self.turtle.spr.x,y-self.turtle.spr.y)
+ self.draggroup = [self.turtle.spr]
+
+
+ """
+ Replace Journal block graphic with preview image
+ """
+ def _load_image(self, 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, self.media_shapes['texton'])
+
+
+ """
+ dock_dx_dy
+ """
+ def _dock_dx_dy(self, 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 block2.connections[dock2n] != None:
+ return (100,100)
+ 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
+ else:
+ if d2type == 'num' or d2type == 'string':
+ pass
+ # 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:
- newnum = oldnum
+ return (100,100)
+ if d1dir==d2dir:
+ return (100,100)
+ return (block1.x+d1x)-(block2.x+d2x),(block1.y+d1y)-(block2.y+d2y)
+
+ """
+ magnitude
+ """
+ def _magnitude(self, pos):
+ x,y = pos
+ return x*x+y*y
+
+ """
+ jog turtle
+ """
+ def _jog_turtle(self, dx, dy):
+ if dx == -1 and dy == -1:
+ self.turtle.xcor = 0
+ self.turtle.ycor = 0
else:
- 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)
+ self.turtle.xcor += dx
+ self.turtle.ycor += dy
+ move_turtle(self.turtle)
+ display_coordinates(self)
+ self.draggroup = None
+
+ """
+ jog block
+ """
+ def _jog_block(self,dx,dy):
+ # drag entire stack if moving lock block
+ if self.spr.proto.name == 'lock':
+ self.draggroup = findgroup(self._find_top_block(self.spr))
+ else:
+ self.draggroup = findgroup(self.spr)
+ # check to see if any block ends up with a negative x
+ for b in self.draggroup:
+ if b.x+dx < 0:
+ dx += -(b.x+dx)
+ # move the stack
+ for b in self.draggroup:
+ move(b,(b.x+dx, b.y-dy))
+ self._snap_to_dock()
+ self.draggroup = None
+
+
+
+
-#
-# 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
- # 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
-# 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
diff --git a/turtleart.py b/turtleart.py
index f9b9ce1..9304e79 100755
--- a/turtleart.py
+++ b/turtleart.py
@@ -135,7 +135,7 @@ class TurtleMain():
menu_bar.append(project_menu)
win.show_all()
- self.tw = twNew(canvas, os.path.abspath('.'), lang)
+ self.tw = TurtleArtWindow(canvas, os.path.abspath('.'), lang)
self.tw.win = win
def _do_open_cb(self, widget):
@@ -146,25 +146,25 @@ class TurtleMain():
def _do_palette_cb(self, widget):
if self.tw.palette == True:
- hideshow_palette(self.tw,False)
+ self.tw.hideshow_palette(False)
else:
- hideshow_palette(self.tw,True)
+ self.tw.hideshow_palette(True)
def _do_hideshow_cb(self, widget):
- hideshow_button(self.tw)
+ self.tw.hideshow_button()
def _do_eraser_cb(self, widget):
- eraser_button(self.tw)
+ self.tw.eraser_button()
return
def _do_run_cb(self, widget):
self.tw.lc.trace = 0
- runbutton(self.tw, 0)
+ self.tw.runbutton(0)
return
def _do_step_cb(self, widget):
self.tw.lc.trace = 0
- runbutton(self.tw, 3)
+ self.tw.runbutton(3)
return
def _do_stop_cb(self, widget):