From b0c68db5e4adce027d9e83e054240c6a5a247f94 Mon Sep 17 00:00:00 2001 From: Raúl Gutiérrez S Date: Sat, 05 Dec 2009 23:44:39 +0000 Subject: tawindow now has a class where all of its functionality is encapsulated. TODO: define how taproject and tawindow relate. --- 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()>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') + 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()>k.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()>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 - 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()>k.gdk.CONTROL_MASK, x, y) + + # if sharing, send button press + if self._sharing(): + # print "sending button pressed" + if event.get_state()>k.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): -- cgit v0.9.1