From 75e7bc69d0e36167456b1cb144dee94098037eff Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Sat, 06 Feb 2010 22:00:10 +0000 Subject: rearrnge methods into logical groupings --- (limited to 'tawindow.py') diff --git a/tawindow.py b/tawindow.py index 4959d5d..945bf75 100644 --- a/tawindow.py +++ b/tawindow.py @@ -53,7 +53,7 @@ from tablock import Blocks, Block from taturtle import Turtles, Turtle from tautils import magnitude, get_load_name, get_save_name, data_from_file,\ data_to_file, round_int, get_id, get_pixbuf_from_journal -from sprite_factory import SVG, svg_str_to_pixbuf +from sprite_factory import SVG, svg_str_to_pixbuf, svg_from_file from sprites import Sprites, Sprite """ @@ -69,7 +69,7 @@ class TurtleArtWindow(): # TODO: most of this goes away self._setup_misc() # the new palette - self.show_toolbar_palette(0, False) + self._show_toolbar_palette(0, False) def _setup_initial_values(self, win, path, lang, parent, mycolors): self.window = win @@ -174,20 +174,43 @@ class TurtleArtWindow(): self.window.connect("key_press_event", self._keypress_cb) """ - Resize all of the blocks + Misc. sprites for status, overlays, etc. """ - def resize_blocks(self): - for b in self.just_blocks(): - b.rescale(self.block_scale) - for b in self.just_blocks(): - self._adjust_dock_positions(b) + def _setup_misc(self): + # media blocks get positioned into other blocks + for name in MEDIA_SHAPES: + if name[0:7] == 'journal' and not self.running_sugar: + filename = 'file'+name[7:] + else: + filename = name + self.media_shapes[name] = \ + svg_str_to_pixbuf(svg_from_file("%s/%s.svg" % ( + self.path, filename))) + + for i, name in enumerate(STATUS_SHAPES): + self.status_shapes[name] = svg_str_to_pixbuf(svg_from_file( + "%s/%s.svg" % (self.path, name))) + self.status_spr = Sprite(self.sprite_list, 0, self.height-200, + self.status_shapes['status']) + self.status_spr.hide() + self.status_spr.type = 'status' + + for name in OVERLAY_SHAPES: + self.overlay_shapes[name] = Sprite(self.sprite_list, + int(self.width/2-600), int(self.height/2-450), + svg_str_to_pixbuf(svg_from_file( + "%s/%s.svg" % (self.path, name)))) + self.overlay_shapes[name].hide() + self.overlay_shapes[name].type = 'overlay' """ - Repaint + Is a chattube available for sharing? """ - def _expose_cb(self, win, event): - self.sprite_list.redraw_sprites() - return True + def _sharing(self): + if self.running_sugar and hasattr(self.activity, 'chattube') and\ + self.activity.chattube is not None: + return True + return False """ Is the an OLPC XO-1? @@ -197,6 +220,14 @@ class TurtleArtWindow(): os.path.exists('/sys/power/olpc-pm') """ + Repaint + """ + def _expose_cb(self, win, event): + self.sprite_list.redraw_sprites() + return True + + + """ Eraser_button (Always hide status block when clearing the screen.) """ def eraser_button(self): @@ -206,6 +237,27 @@ class TurtleArtWindow(): self.display_coordinates() """ + Run turtle! + """ + def run_button(self, time): + if self.running_sugar: + self.activity.recenter() + # Look for a 'start' block + for blk in self.just_blocks(): + if self._find_start_stack(blk): + self.step_time = time + print "running stack starting from %s" % (blk.name) + self._run_stack(blk) + return + # If there is no 'start' block, run stacks that aren't 'def action' + for blk in self.just_blocks(): + if self._find_block_to_run(blk): + self.step_time = time + print "running stack starting from %s" % (blk.name) + self._run_stack(blk) + return + + """ Stop button """ def stop_button(self): @@ -256,7 +308,7 @@ class TurtleArtWindow(): Show palette """ def show_palette(self, n=0): - self.show_toolbar_palette(n) + self._show_toolbar_palette(n) self.palette_button[self.orientation].set_layer(TAB_LAYER) self.toolbar_spr.set_layer(CATEGORY_LAYER) self.palette = True @@ -265,7 +317,7 @@ class TurtleArtWindow(): Hide the palette. """ def hide_palette(self): - self.hide_toolbar_palette() + self._hide_toolbar_palette() self.palette_button[self.orientation].hide() self.toolbar_spr.hide() self.palette = False @@ -289,98 +341,27 @@ class TurtleArtWindow(): self.activity.do_show() """ - Where is the mouse event? - """ - def xy(self, event): - return map(int, event.get_coords()) - - """ - Run turtle! - """ - def run_button(self, time): - if self.running_sugar: - self.activity.recenter() - # Look for a 'start' block - for blk in self.just_blocks(): - if self._find_start_stack(blk): - self.step_time = time - print "running stack starting from %s" % (blk.name) - self._run_stack(blk) - return - # If there is no 'start' block, run stacks that aren't 'def action' - for blk in self.just_blocks(): - if self._find_block_to_run(blk): - self.step_time = time - print "running stack starting from %s" % (blk.name) - self._run_stack(blk) - return - - """ - Misc. sprites for status, overlays, etc. + Resize all of the blocks """ - def _setup_misc(self): - # media blocks get positioned into other blocks - for name in MEDIA_SHAPES: - if name[0:7] == 'journal' and not self.running_sugar: - filename = 'file'+name[7:] - else: - filename = name - self.media_shapes[name] = \ - self._load_sprite_from_file("%s/%s.svg" % (self.path, filename)) - - for i, name in enumerate(STATUS_SHAPES): - self.status_shapes[name] = self._load_sprite_from_file( - "%s/%s.svg" % (self.path, name)) - self.status_spr = Sprite(self.sprite_list, 0, self.height-200, - self.status_shapes['status']) - self.status_spr.hide() - self.status_spr.type = 'status' - - for name in OVERLAY_SHAPES: - self.overlay_shapes[name] = Sprite(self.sprite_list, - int(self.width/2-600), int(self.height/2-450), - self._load_sprite_from_file("%s/%s.svg" % (self.path, name))) - self.overlay_shapes[name].hide() - self.overlay_shapes[name].type = 'overlay' - - def _load_sprite_from_file(self, name): - svg = SVG() - return svg_str_to_pixbuf(svg.from_file(name)) + def resize_blocks(self): + for b in self.just_blocks(): + b.rescale(self.block_scale) + for b in self.just_blocks(): + self._adjust_dock_positions(b) """ - Hide turtle palettes + Show the toolbar palettes, creating them on init_only """ - def hide_toolbar_palette(self): - self.hide_previous_palette() - # Hide the selectors - for i in range(len(PALETTES)): - self.selectors[i].hide() - self.selected_palette = None - self.previous_palette = None - - def hide_previous_palette(self): - # Hide previous palette - if self.previous_palette is not None: - for i in range(len(PALETTES[self.previous_palette])): - self.palettes[self.previous_palette][i].spr.hide() - self.palette_sprs[self.previous_palette][ - self.orientation].hide() - self.selectors[self.previous_palette].set_shape( - self.selector_shapes[self.previous_palette][0]) - if self.previous_palette == PALETTE_NAMES.index('trash'): - for b in self.trash_stack: - b.spr.hide() - - def show_toolbar_palette(self, n, init_only=False): + def _show_toolbar_palette(self, n, init_only=False): # Create the selectors the first time through. if self.selectors == []: svg = SVG() x, y = 50, 0 for i, name in enumerate(PALETTE_NAMES): - a = self._load_sprite_from_file("%s/%soff.svg" % (self.path, - name)) - b = self._load_sprite_from_file("%s/%son.svg" % (self.path, - name)) + a = svg_str_to_pixbuf(svg_from_file("%s/%soff.svg" % ( + self.path, name))) + b = svg_str_to_pixbuf(svg_from_file("%s/%son.svg" % ( + self.path, name))) self.selector_shapes.append([a,b]) self.selectors.append(Sprite(self.sprite_list, x, y, a)) self.selectors[i].type = 'selector' @@ -392,11 +373,11 @@ class TurtleArtWindow(): # Create the palette orientation button self.palette_button.append(Sprite(self.sprite_list, 0, 0, - self._load_sprite_from_file( - "%s/palettehorizontal.svg" % (self.path)))) + svg_str_to_pixbuf(svg_from_file( + "%s/palettehorizontal.svg" %(self.path))))) self.palette_button.append(Sprite(self.sprite_list, 0, 0, - self._load_sprite_from_file( - "%s/palettevertical.svg" % (self.path)))) + svg_str_to_pixbuf(svg_from_file( + "%s/palettevertical.svg" % (self.path))))) self.palette_button[0].name = 'orientation' self.palette_button[1].name = 'orientation' self.palette_button[0].type = 'palette' @@ -418,7 +399,7 @@ class TurtleArtWindow(): return # Hide the previously displayed palette - self.hide_previous_palette() + self._hide_previous_palette() self.selected_palette = n self.previous_palette = self.selected_palette @@ -465,6 +446,33 @@ class TurtleArtWindow(): for blk in self.trash_stack: blk.spr.set_layer(TAB_LAYER) + """ + Hide the toolbar palettes + """ + def _hide_toolbar_palette(self): + self._hide_previous_palette() + # Hide the selectors + for i in range(len(PALETTES)): + self.selectors[i].hide() + self.selected_palette = None + self.previous_palette = None + + """ + Hide just the previously viewed toolbar palette + """ + def _hide_previous_palette(self): + # Hide previous palette + if self.previous_palette is not None: + for i in range(len(PALETTES[self.previous_palette])): + self.palettes[self.previous_palette][i].spr.hide() + self.palette_sprs[self.previous_palette][ + self.orientation].hide() + self.selectors[self.previous_palette].set_shape( + self.selector_shapes[self.previous_palette][0]) + if self.previous_palette == PALETTE_NAMES.index('trash'): + for b in self.trash_stack: + b.spr.hide() + def _horizontal_layout(self, x, y, max, blocks): for b in blocks: _w, _h = b.spr.get_dimensions() @@ -544,8 +552,9 @@ class TurtleArtWindow(): svg_str_to_pixbuf(svg.palette(PALETTE_WIDTH, _h))) self.palette_sprs[n][self.orientation].set_layer(CATEGORY_LAYER) + """ - Select a category. + Select a category from the toolbar. """ def _select_category(self, spr): i = self.selectors.index(spr) @@ -559,60 +568,320 @@ class TurtleArtWindow(): self.show_palette(i) """ - Find a stack to run (any stack without a 'def action'on the top). + Button press """ - def _find_block_to_run(self, blk): - top = self.find_top_block(blk) - if blk == top and blk.name[0:3] is not 'def': + def _buttonpress_cb(self, win, event): + self.window.grab_focus() + x, y = self._xy(event) + self.button_press(event.get_state()>k.gdk.CONTROL_MASK, x, y) + if self._sharing(): + if event.get_state()>k.gdk.CONTROL_MASK is True: + self.activity._send_event("p:%d:%d:T" % (x, y)) + else: + self.activity._send_event("p:%d:%d:F" % (x, y)) + return True + + """ + Button press + """ + def button_press(self, mask, x, y, verbose=False): + if verbose: + print "processing remote button press: %d, %d" % (x, y) + self.block_operation = 'click' + + # Unselect things that may have been selected earlier + if self.selected_blk is not None: + self._unselect_block() + self.selected_turtle = None + # Always hide the status layer on a click + if self.status_spr is not None: + self.status_spr.hide() + + # Find out what was clicked + spr = self.sprite_list.find_sprite((x,y)) + self.dx = 0 + self.dy = 0 + if spr is None: return True - else: - return False + self.selected_spr = spr + + # From the sprite at x, y, look for a corresponding block + blk = self.block_list.spr_to_block(spr) + if blk is not None: + if blk.type == 'block': + self.selected_blk = blk + self._block_pressed(mask, x, y, blk) + elif blk.type == 'trash': + self._restore_from_trash(blk) + elif blk.type == 'proto': + if blk.name == 'restoreall': + self._restore_all_from_trash() + elif blk.name == 'restore': + self._restore_latest_from_trash() + elif blk.name == 'empty': + self._empty_trash() + elif MACROS.has_key(blk.name): + self._new_macro(blk.name, x+PALETTE_WIDTH, y+PALETTE_HEIGHT) + else: + blk.highlight() + self._new_block(blk.name, x+PALETTE_WIDTH, y+PALETTE_HEIGHT) + blk.unhighlight() + return True + + # Next, look for a turtle + t = self.turtles.spr_to_turtle(spr) + if t is not None: + self.selected_turtle = t + self.canvas.set_turtle(self.turtles.get_turtle_key(t)) + self._turtle_pressed(x, y) + return True + + # Finally, check for anything else + if hasattr(spr, 'type'): + if spr.type == "canvas": + spr.set_layer(CANVAS_LAYER) + elif spr.type == 'selector': + self._select_category(spr) + elif spr.type == 'category': + if self._hide_button_hit(spr, x, y): + self.hideshow_palette(False) + elif spr.type == 'palette': + self.orientation = 1-self.orientation + self.palette_button[self.orientation].set_layer(TAB_LAYER) + self.palette_button[1-self.orientation].hide() + self.palette_sprs[self.selected_palette][ + 1-self.orientation].hide() + self._layout_palette(self.selected_palette) + self.show_palette(self.selected_palette) + return True + """ - Find the top block in a stack. + Restore all the blocks in the trash can """ - def find_top_block(self, blk): - while blk.connections[0] is not None: - blk = blk.connections[0] - return blk + def _restore_all_from_trash(self): + for b in self.block_list.list: + if b.type == 'trash': + self._restore_from_trash(b) """ - Find a stack with a 'start' block on top. + Restore latest blocks from the trash can """ - def _find_start_stack(self, blk): - top = self.find_top_block(blk) - if top.name == 'start': + def _restore_latest_from_trash(self): + if len(self.trash_stack) == 0: + return + self._restore_from_trash(self.trash_stack[len(self.trash_stack)-1]) + + def _restore_from_trash(self, blk): + group = self._find_group(blk) + for b in group: + b.spr.set_layer(BLOCK_LAYER) + x,y = b.spr.get_xy() + b.spr.move((x+PALETTE_WIDTH,y+PALETTE_HEIGHT)) + b.type = 'block' + self.trash_stack.remove(blk) + + """ + Permanently remove blocks in the trash can + """ + def _empty_trash(self): + for b in self.block_list.list: + if b.type == 'trash': + b.type = 'deleted' + b.spr.hide() + self.trash_stack = [] + + """ + Is x,y over the trash can? + """ + def _in_the_trash(self, x, y): + if self.selected_palette == self.trash_index and \ + self.palette_sprs[self.trash_index][self.orientation].hit((x,y)): return True + return False + + """ + Block pressed + """ + def _block_pressed(self, mask, x, y, blk): + if blk is not None: + blk.highlight() + self._disconnect(blk) + self.drag_group = self._find_group(blk) + (sx, sy) = blk.spr.get_xy() + self.drag_pos = x-sx, y-sy + for blk in self.drag_group: + blk.spr.set_layer(TOP_LAYER) + self.saved_string = blk.spr.labels[0] + + """ + Unselect block + """ + def _unselect_block(self): + # After unselecting a 'number' block, we need to check its value + if self.selected_blk.name == 'number': + self._number_check() + elif self.selected_blk.name == 'string': + self._string_check() + self.selected_blk.unhighlight() + self.selected_blk = None + + """ + Make a new block. + """ + def _new_block(self, name, x, y): + if name in CONTENT_BLOCKS: + newblk = Block(self.block_list, self.sprite_list, name, x-20, y-20, + 'block', DEFAULTS[name], self.block_scale) else: - return False + newblk = Block(self.block_list, self.sprite_list, name, x-20, y-20, + 'block', [], self.block_scale) + # Add special skin to some blocks + if name == 'nop': + if self.nop == 'pythonloaded': + newblk.spr.set_image(self.media_shapes['pythonon'], 1, + PYTHON_X, PYTHON_Y) + else: + newblk.spr.set_image(self.media_shapes['pythonoff'], 1, + PYTHON_X, PYTHON_Y) + elif name in BOX_STYLE_MEDIA: + newblk.spr.set_image(self.media_shapes[name+'off'], 1, + MEDIA_X, MEDIA_Y) + newblk.spr.set_label(' ') + newspr = newblk.spr + newspr.set_layer(TOP_LAYER) + self.drag_pos = 20, 20 + newblk.connections = [None]*len(newblk.docks) + if DEFAULTS.has_key(newblk.name): + for i, argvalue in enumerate(DEFAULTS[newblk.name]): + # skip the first dock position--it is always a connector + dock = newblk.docks[i+1] + argname = dock[0] + if argname == 'unavailable': + continue + if argname == 'media': + argname = 'journal' + elif argname == 'number' and\ + (type(argvalue) is str or type(argvalue) is unicode): + argname = 'string' + elif argname == 'bool': + argname = argvalue + elif argname == 'flow': + argname = argvalue + (sx, sy) = newspr.get_xy() + if argname is not None: + if argname in CONTENT_BLOCKS: + argblk = Block(self.block_list, self.sprite_list, + argname, 0, 0, 'block', [argvalue], + self.block_scale) + else: + argblk = Block(self.block_list, self.sprite_list, + argname, 0, 0, 'block', [], + self.block_scale) + argdock = argblk.docks[0] + nx, ny = sx+dock[2]-argdock[2], sy+dock[3]-argdock[3] + if argname == 'journal': + argblk.spr.set_image(self.media_shapes['journaloff'], + 1, MEDIA_X, MEDIA_Y) + argblk.spr.set_label(' ') + argblk.spr.move((nx, ny)) + argblk.spr.set_layer(TOP_LAYER) + argblk.connections = [newblk, None] + newblk.connections[i+1] = argblk + self.drag_group = self._find_group(newblk) + self.block_operation = 'new' """ - Find the connected group of block in a stack. + Create a "macro" (predefined stack of blocks) """ - def _find_group(self, blk): - if blk is None: - return [] - group=[blk] - if blk.connections is not None: - for blk2 in blk.connections[1:]: - if blk2 is not None: - group.extend(self._find_group(blk2)) - return group + def _new_macro(self, name, x, y): + macro = MACROS[name] + macro[0][2] = x + macro[0][3] = y + self.process_data(macro) """ - Is a chattube available for sharing? + Process data (from a macro, a file, or the clipboard) into blocks. """ - def _sharing(self): - if self.running_sugar and hasattr(self.activity, 'chattube') and\ - self.activity.chattube is not None: - return True - return False + def process_data(self, data): + # Create the blocks (or turtle). + blocks = [] + for b in data: + if self._found_a_turtle(b) is False: + blk = self.load_block(b) + blocks.append(blk) + # Make the connections. + for i in range(len(blocks)): + cons=[] + # Normally, it is simply a matter of copying the connections. + if blocks[i].connections == None: + for c in data[i][4]: + if c is None: + cons.append(None) + else: + cons.append(blocks[c]) + elif blocks[i].connections == 'check': + # Ugly corner case is to convert old-style booleans op. + cons.append(None) # Add an extra connection. + for c in data[i][4]: + if c is None: + cons.append(None) + else: + cons.append(blocks[c]) + # If the boolean op was connected, readjust the plumbing. + if data[i][4][0] is not None: + c = data[i][4][0] + cons[0] = blocks[data[c][4][0]] + c0 = data[c][4][0] + for j, cj in enumerate(data[c0][4]): + if cj == c: + blocks[c0].connections[j] = blocks[i] + if c0 and c is not None: + bdock = blk.docks[i] + for j in range(len(c.docks)): + if c.connections[j] == blk: + cdock = c.docks[j] + nx, ny = sx+bdock[2]-cdock[2], sy+bdock[3]-cdock[3] + c.spr.move((nx, ny)) + self._adjust_dock_positions(c) + + """ + Turtle pressed + """ + def _turtle_pressed(self, x, y): + (tx, ty) = self.selected_turtle.get_xy() + dx, dy = x-tx-30, y-ty-30 + if dx*dx+dy*dy > 200: + self.drag_turtle = ('turn', + self.canvas.heading-atan2(dy,dx)/DEGTOR, 0) + else: + self.drag_turtle = ('move', x-tx, y-ty) """ Mouse move """ def _move_cb(self, win, event): - x, y = self.xy(event) + x, y = self._xy(event) self._mouse_move(x, y) return True @@ -729,319 +998,10 @@ class TurtleArtWindow(): 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 - alt_flag = 'T' - else: - alt_mask = False - alt_flag = 'F' - results = self._key_press(alt_mask, keyname, keyunicode) - if keyname is not None and self._sharing(): - self.activity._send_event("k:%s:%s:%s" % (alt_flag, keyname, - str(keyunicode))) - return keyname - - def _key_press(self, alt_mask, keyname, keyunicode, verbose=False): - if keyname is None: - return False - if verbose: - print "processing remote key press: %s" % (keyname) - - self.keypress = keyname - - # First, process Alt keys. - if alt_mask is True and self.selected_blk==None: - if keyname=="i" and self._sharing(): - self.activity.waiting_for_blocks = True - self.activity._send_event("i") # request sync for sharing - elif keyname=="p": - self.hideshow_button() - elif keyname=='q': - exit() - return True - # Process keyboard input for 'number' blocks - if self.selected_blk is not None and\ - self.selected_blk.name == 'number': - self._process_numeric_input(keyname) - return True - # Process keyboard input for 'string' blocks - elif self.selected_blk is not None and\ - self.selected_blk.name == 'string': - self._process_alphanumeric_input(keyname, keyunicode) - if self.selected_blk is not None: - self.selected_blk.resize() - return True - # Otherwise, use keyboard input to move blocks or turtles - else: - self._process_keyboard_commands(keyname) - if self.selected_blk is None: - return False - - ''' - Make sure numeric input is valid. - ''' - def _process_numeric_input(self, keyname): - oldnum = self.selected_blk.spr.labels[0].replace(CURSOR,'') - if len(oldnum) == 0: - oldnum = '0' - if keyname == 'minus': - if oldnum == '0': - newnum = '-' - elif oldnum[0] != '-': - newnum = '-' + oldnum - else: - newnum = oldnum - elif keyname == 'period' and '.' not in oldnum: - newnum = oldnum + '.' - elif keyname == 'BackSpace': - if len(oldnum) > 0: - newnum = oldnum[:len(oldnum)-1] - else: - newnum = '' - elif keyname in ['0','1','2','3','4','5','6','7','8','9']: - if oldnum == '0': - newnum = keyname - else: - newnum = oldnum + keyname - elif keyname == 'Return': - self._unselect_block() - return - else: - newnum = oldnum - if newnum == '.': - newnum = '0.' - if len(newnum) > 0 and newnum != '-': - try: - float(newnum) - except ValueError,e: - newnum = oldnum - self.selected_blk.spr.set_label(newnum + CURSOR) - - """ - Make sure alphanumeric input is properly parsed. - """ - def _process_alphanumeric_input(self, keyname, keyunicode): - if len(self.selected_blk.spr.labels[0]) > 0: - oldleft, oldright = self.selected_blk.spr.labels[0].split(CURSOR) - else: - oldleft = '' - oldright = '' - newleft = oldleft - if keyname in ['Shift_L', 'Shift_R', 'Control_L', 'Caps_Lock',\ - 'Alt_L', 'Alt_R', 'KP_Enter', 'ISO_Level3_Shift']: - keyname = '' - keyunicode = 0 - print "saw a noise key: %s" % (keyname) - # Hack until I sort out input and unicode and dead keys, - if keyname[0:5] == 'dead_': - self.dead_key = keyname - keyname = '' - keyunicode = 0 - if keyname in WHITE_SPACE: - keyunicode = 32 - print "preparing to process [%s:%s] (%s)" % (oldleft, oldright, keyname) - if keyname == 'BackSpace': - if len(oldleft) > 1: - newleft = oldleft[:len(oldleft)-1] - else: - newleft = '' - elif keyname == 'Home': - oldright = oldleft+oldright - newleft = '' - elif keyname == 'Left': - if len(oldleft) > 0: - oldright = oldleft[len(oldleft)-1:]+oldright - newleft = oldleft[:len(oldleft)-1] - elif keyname == 'Right': - if len(oldright) > 0: - newleft = oldleft + oldright[0] - oldright = oldright[1:] - elif keyname == 'End': - newleft = oldleft+oldright - oldright = '' - elif keyname == 'Return' or keyname == 'Down': - self._unselect_block() - return - elif keyname == 'Up' or keyname == 'Escape': # Restore previous state - self.selected_blk.spr.set_label(self.saved_string) - self._unselect_block() - return - else: - if self.dead_key is not '': - keyunicode =\ - DEAD_DICTS[DEAD_KEYS.index(self.dead_key[5:])][keyname] - self.dead_key = '' - if keyunicode > 0: - if unichr(keyunicode) is not '\x00': - newleft = oldleft+unichr(keyunicode) - else: - newleft = oldleft - ''' - else: - print "setting new left to ''" - newleft = '' - ''' - self.selected_blk.spr.set_label("%s%s%s" % \ - (newleft, CURSOR, oldright)) - - """ - Use the keyboard to move blocks and turtle - """ - def _process_keyboard_commands(self, keyname): - mov_dict = {'KP_Up':[0,10],'j':[0,10],'Up':[0,10], - 'KP_Down':[0,-10],'k':[0,-10],'Down':[0,-10], - 'KP_Left':[-10,0],'h':[-10,0],'Left':[-10,0], - 'KP_Right':[10,0],'l':[10,0],'Right':[10,0], - 'KP_Page_Down':[0,0], 'KP_Page_Up':[0,0], 'KP_End':[0,0], - 'KP_Home':[-1,-1],'Return':[-1,-1], 'Esc':[0,0]} - if not mov_dict.has_key(keyname): - return - if keyname == 'KP_End': - self.run_button(0) - elif self.selected_spr is not None: - blk = self.block_list.spr_to_block(self.selected_spr) - tur = self.turtles.spr_to_turtle(self.selected_spr) - if blk is not None: - if keyname == 'Return' or keyname == 'KP_Page_Up': - (x, y) = blk.spr.get_xy() - self._click_block(x, y) - elif keyname == 'KP_Page_Down': - if self.drag_group == None: - self.drag_group = self._find_group(blk) - for b in self.drag_group: b.spr.hide() - self.drag_group = None - else: - self._jog_block(blk, mov_dict[keyname][0], - mov_dict[keyname][1]) - elif tur is not None: - self._jog_turtle(mov_dict[keyname][0], mov_dict[keyname][1]) - return True - - """ - Button press - """ - def button_press(self, mask, x, y, verbose=False): - if verbose: - print "processing remote button press: %d, %d" % (x, y) - self.block_operation = 'click' - - # Unselect things that may have been selected earlier - if self.selected_blk is not None: - self._unselect_block() - self.selected_turtle = None - # Always hide the status layer on a click - if self.status_spr is not None: - self.status_spr.hide() - - # Find out what was clicked - spr = self.sprite_list.find_sprite((x,y)) - self.dx = 0 - self.dy = 0 - if spr is None: - return True - self.selected_spr = spr - - # From the sprite at x, y, look for a corresponding block - blk = self.block_list.spr_to_block(spr) - if blk is not None: - if blk.type == 'block': - self.selected_blk = blk - self._block_pressed(mask, x, y, blk) - elif blk.type == 'trash': - self._restore_from_trash(blk) - elif blk.type == 'proto': - if blk.name == 'restoreall': - self._restore_all_from_trash() - elif blk.name == 'restore': - self._restore_latest_from_trash() - elif blk.name == 'empty': - self._empty_trash() - elif MACROS.has_key(blk.name): - self._new_macro(blk.name, x+PALETTE_WIDTH, y+PALETTE_HEIGHT) - else: - blk.highlight() - self._new_block(blk.name, x+PALETTE_WIDTH, y+PALETTE_HEIGHT) - blk.unhighlight() - return True - - # Next, look for a turtle - t = self.turtles.spr_to_turtle(spr) - if t is not None: - self.selected_turtle = t - self.canvas.set_turtle(self.turtles.get_turtle_key(t)) - self._turtle_pressed(x, y) - return True - - # Finally, check for anything else - if hasattr(spr, 'type'): - if spr.type == "canvas": - spr.set_layer(CANVAS_LAYER) - elif spr.type == 'selector': - self._select_category(spr) - elif spr.type == 'category': - if self._hide_button_hit(spr, x, y): - self.hideshow_palette(False) - elif spr.type == 'palette': - self.orientation = 1-self.orientation - self.palette_button[self.orientation].set_layer(TAB_LAYER) - self.palette_button[1-self.orientation].hide() - self.palette_sprs[self.selected_palette][ - 1-self.orientation].hide() - self._layout_palette(self.selected_palette) - self.show_palette(self.selected_palette) - return True - - """ - Block pressed - """ - def _block_pressed(self, mask, x, y, blk): - if blk is not None: - blk.highlight() - self._disconnect(blk) - self.drag_group = self._find_group(blk) - (sx, sy) = blk.spr.get_xy() - self.drag_pos = x-sx, y-sy - for blk in self.drag_group: - blk.spr.set_layer(TOP_LAYER) - self.saved_string = blk.spr.labels[0] - - """ - Unselect block - """ - def _unselect_block(self): - # After unselecting a 'number' block, we need to check its value - if self.selected_blk.name == 'number': - self._number_check() - elif self.selected_blk.name == 'string': - self._string_check() - self.selected_blk.unhighlight() - self.selected_blk = None - - """ - Button press - """ - def _buttonpress_cb(self, win, event): - self.window.grab_focus() - x, y = self.xy(event) - self.button_press(event.get_state()>k.gdk.CONTROL_MASK, x, y) - if self._sharing(): - if event.get_state()>k.gdk.CONTROL_MASK is True: - self.activity._send_event("p:%d:%d:T" % (x, y)) - else: - self.activity._send_event("p:%d:%d:F" % (x, y)) - return True - - """ Button release """ def _buttonrelease_cb(self, win, event): - x, y = self.xy(event) + x, y = self._xy(event) self.button_release(x, y) if self._sharing(): self.activity._send_event("r:"+str(x)+":"+str(y)) @@ -1168,7 +1128,38 @@ class TurtleArtWindow(): self._run_stack(blk) """ - Snap a block to the dock of another block + Run a stack of blocks. + """ + def _run_stack(self, blk): + if blk is None: + return + self.lc.ag = None + top = self.find_top_block(blk) + self.lc.run_blocks(top, self.just_blocks(), True) + gobject.idle_add(self.lc.doevalstep) + + """ + Did the sprite's hide (contract) button get hit? + """ + def _hide_button_hit(self, spr, x, y): + r,g,b,a = spr.get_pixel((x, y)) + if (r == 255 and g == 0) or g == 255: + return True + else: + return False + + """ + Did the sprite's show (expand) button get hit? + """ + def _show_button_hit(self, spr, x, y): + r,g,b,a = spr.get_pixel((x, y)) + if (r == 255 and g == 0) or g == 255: + return False + else: + return True + + """ + Snap a block to the dock of another block. """ def _snap_to_dock(self): my_block = self.drag_group[0] @@ -1263,150 +1254,6 @@ class TurtleArtWindow(): MEDIA_Y) """ - Run stack - """ - def _run_stack(self, blk): - if blk is None: - return - self.lc.ag = None - top = self.find_top_block(blk) - self.lc.run_blocks(top, self.just_blocks(), True) - gobject.idle_add(self.lc.doevalstep) - - """ - Restore all the blocks in the trash can - """ - def _restore_all_from_trash(self): - for b in self.block_list.list: - if b.type == 'trash': - self._restore_from_trash(b) - - """ - Restore latest blocks from the trash can - """ - def _restore_latest_from_trash(self): - if len(self.trash_stack) == 0: - return - self._restore_from_trash(self.trash_stack[len(self.trash_stack)-1]) - - def _restore_from_trash(self, blk): - group = self._find_group(blk) - for b in group: - b.spr.set_layer(BLOCK_LAYER) - x,y = b.spr.get_xy() - b.spr.move((x+PALETTE_WIDTH,y+PALETTE_HEIGHT)) - b.type = 'block' - self.trash_stack.remove(blk) - - """ - Permanently remove blocks in the trash can - """ - def _empty_trash(self): - for b in self.block_list.list: - if b.type == 'trash': - b.type = 'deleted' - b.spr.hide() - self.trash_stack = [] - - """ - Is x,y over the trash can? - """ - def _in_the_trash(self, x, y): - if self.selected_palette == self.trash_index and \ - self.palette_sprs[self.trash_index][self.orientation].hit((x,y)): - return True - return False - - """ - Filter out 'proto' blocks - """ - def just_blocks(self): - just_blocks_list = [] - for b in self.block_list.list: - if b.type == 'block': - just_blocks_list.append(b) - return just_blocks_list - - - """ - Make a new block. - """ - def _new_block(self, name, x, y): - if name in CONTENT_BLOCKS: - newblk = Block(self.block_list, self.sprite_list, name, x-20, y-20, - 'block', DEFAULTS[name], self.block_scale) - else: - newblk = Block(self.block_list, self.sprite_list, name, x-20, y-20, - 'block', [], self.block_scale) - # Add special skin to some blocks - if name == 'nop': - if self.nop == 'pythonloaded': - newblk.spr.set_image(self.media_shapes['pythonon'], 1, - PYTHON_X, PYTHON_Y) - else: - newblk.spr.set_image(self.media_shapes['pythonoff'], 1, - PYTHON_X, PYTHON_Y) - elif name in BOX_STYLE_MEDIA: - newblk.spr.set_image(self.media_shapes[name+'off'], 1, - MEDIA_X, MEDIA_Y) - newblk.spr.set_label(' ') - newspr = newblk.spr - newspr.set_layer(TOP_LAYER) - self.drag_pos = 20, 20 - newblk.connections = [None]*len(newblk.docks) - if DEFAULTS.has_key(newblk.name): - for i, argvalue in enumerate(DEFAULTS[newblk.name]): - # skip the first dock position--it is always a connector - dock = newblk.docks[i+1] - argname = dock[0] - if argname == 'unavailable': - continue - if argname == 'media': - argname = 'journal' - elif argname == 'number' and\ - (type(argvalue) is str or type(argvalue) is unicode): - argname = 'string' - elif argname == 'bool': - argname = argvalue - elif argname == 'flow': - argname = argvalue - (sx, sy) = newspr.get_xy() - if argname is not None: - if argname in CONTENT_BLOCKS: - argblk = Block(self.block_list, self.sprite_list, - argname, 0, 0, 'block', [argvalue], - self.block_scale) - else: - argblk = Block(self.block_list, self.sprite_list, - argname, 0, 0, 'block', [], - self.block_scale) - argdock = argblk.docks[0] - nx, ny = sx+dock[2]-argdock[2], sy+dock[3]-argdock[3] - if argname == 'journal': - argblk.spr.set_image(self.media_shapes['journaloff'], - 1, MEDIA_X, MEDIA_Y) - argblk.spr.set_label(' ') - argblk.spr.move((nx, ny)) - argblk.spr.set_layer(TOP_LAYER) - argblk.connections = [newblk, None] - newblk.connections[i+1] = argblk - self.drag_group = self._find_group(newblk) - self.block_operation = 'new' - - """ - Debugging tools - """ - def _print_blk_list(self, blk_list): - s = "" - for blk in blk_list: - if blk == None: - s+="None" - else: - s+=blk.name - s += " " - return s - - """ Disconnect block from stack above it. """ def _disconnect(self, blk): @@ -1417,18 +1264,6 @@ class TurtleArtWindow(): blk.connections[0] = None """ - Turtle pressed - """ - def _turtle_pressed(self, x, y): - (tx, ty) = self.selected_turtle.get_xy() - dx, dy = x-tx-30, y-ty-30 - if dx*dx+dy*dy > 200: - self.drag_turtle = ('turn', - self.canvas.heading-atan2(dy,dx)/DEGTOR, 0) - else: - self.drag_turtle = ('move', x-tx, y-ty) - - """ Find the distance between the dock points of two blocks. """ def _dock_dx_dy(self, block1, dock1n, block2, dock2n): @@ -1462,6 +1297,202 @@ class TurtleArtWindow(): (b2x, b2y) = block2.spr.get_xy() return ((b1x+d1x)-(b2x+d2x), (b1y+d1y)-(b2y+d2y)) + + """ + Keyboard + """ + def _keypress_cb(self, area, event): + keyname = gtk.gdk.keyval_name(event.keyval) + keyunicode = gtk.gdk.keyval_to_unicode(event.keyval) + + if event.get_state()>k.gdk.MOD1_MASK: + alt_mask = True + alt_flag = 'T' + else: + alt_mask = False + alt_flag = 'F' + results = self._key_press(alt_mask, keyname, keyunicode) + if keyname is not None and self._sharing(): + self.activity._send_event("k:%s:%s:%s" % (alt_flag, keyname, + str(keyunicode))) + return keyname + + def _key_press(self, alt_mask, keyname, keyunicode, verbose=False): + if keyname is None: + return False + if verbose: + print "processing remote key press: %s" % (keyname) + + self.keypress = keyname + + # First, process Alt keys. + if alt_mask is True and self.selected_blk==None: + if keyname=="i" and self._sharing(): + self.activity.waiting_for_blocks = True + self.activity._send_event("i") # request sync for sharing + elif keyname=="p": + self.hideshow_button() + elif keyname=='q': + exit() + return True + # Process keyboard input for 'number' blocks + if self.selected_blk is not None and\ + self.selected_blk.name == 'number': + self._process_numeric_input(keyname) + return True + # Process keyboard input for 'string' blocks + elif self.selected_blk is not None and\ + self.selected_blk.name == 'string': + self._process_alphanumeric_input(keyname, keyunicode) + if self.selected_blk is not None: + self.selected_blk.resize() + return True + # Otherwise, use keyboard input to move blocks or turtles + else: + self._process_keyboard_commands(keyname) + if self.selected_blk is None: + return False + + ''' + Make sure numeric input is valid. + ''' + def _process_numeric_input(self, keyname): + oldnum = self.selected_blk.spr.labels[0].replace(CURSOR,'') + if len(oldnum) == 0: + oldnum = '0' + if keyname == 'minus': + if oldnum == '0': + newnum = '-' + elif oldnum[0] != '-': + newnum = '-' + oldnum + else: + newnum = oldnum + elif keyname == 'period' and '.' not in oldnum: + newnum = oldnum + '.' + elif keyname == 'BackSpace': + if len(oldnum) > 0: + newnum = oldnum[:len(oldnum)-1] + else: + newnum = '' + elif keyname in ['0','1','2','3','4','5','6','7','8','9']: + if oldnum == '0': + newnum = keyname + else: + newnum = oldnum + keyname + elif keyname == 'Return': + self._unselect_block() + return + else: + newnum = oldnum + if newnum == '.': + newnum = '0.' + if len(newnum) > 0 and newnum != '-': + try: + float(newnum) + except ValueError,e: + newnum = oldnum + self.selected_blk.spr.set_label(newnum + CURSOR) + + """ + Make sure alphanumeric input is properly parsed. + """ + def _process_alphanumeric_input(self, keyname, keyunicode): + if len(self.selected_blk.spr.labels[0]) > 0: + oldleft, oldright = self.selected_blk.spr.labels[0].split(CURSOR) + else: + oldleft = '' + oldright = '' + newleft = oldleft + if keyname in ['Shift_L', 'Shift_R', 'Control_L', 'Caps_Lock',\ + 'Alt_L', 'Alt_R', 'KP_Enter', 'ISO_Level3_Shift']: + keyname = '' + keyunicode = 0 + print "saw a noise key: %s" % (keyname) + # Hack until I sort out input and unicode and dead keys, + if keyname[0:5] == 'dead_': + self.dead_key = keyname + keyname = '' + keyunicode = 0 + if keyname in WHITE_SPACE: + keyunicode = 32 + print "preparing to process [%s:%s] (%s)" % (oldleft, oldright, keyname) + if keyname == 'BackSpace': + if len(oldleft) > 1: + newleft = oldleft[:len(oldleft)-1] + else: + newleft = '' + elif keyname == 'Home': + oldright = oldleft+oldright + newleft = '' + elif keyname == 'Left': + if len(oldleft) > 0: + oldright = oldleft[len(oldleft)-1:]+oldright + newleft = oldleft[:len(oldleft)-1] + elif keyname == 'Right': + if len(oldright) > 0: + newleft = oldleft + oldright[0] + oldright = oldright[1:] + elif keyname == 'End': + newleft = oldleft+oldright + oldright = '' + elif keyname == 'Return' or keyname == 'Down': + self._unselect_block() + return + elif keyname == 'Up' or keyname == 'Escape': # Restore previous state + self.selected_blk.spr.set_label(self.saved_string) + self._unselect_block() + return + else: + if self.dead_key is not '': + keyunicode =\ + DEAD_DICTS[DEAD_KEYS.index(self.dead_key[5:])][keyname] + self.dead_key = '' + if keyunicode > 0: + if unichr(keyunicode) is not '\x00': + newleft = oldleft+unichr(keyunicode) + else: + newleft = oldleft + ''' + else: + print "setting new left to ''" + newleft = '' + ''' + self.selected_blk.spr.set_label("%s%s%s" % \ + (newleft, CURSOR, oldright)) + + """ + Use the keyboard to move blocks and turtle + """ + def _process_keyboard_commands(self, keyname): + mov_dict = {'KP_Up':[0,10],'j':[0,10],'Up':[0,10], + 'KP_Down':[0,-10],'k':[0,-10],'Down':[0,-10], + 'KP_Left':[-10,0],'h':[-10,0],'Left':[-10,0], + 'KP_Right':[10,0],'l':[10,0],'Right':[10,0], + 'KP_Page_Down':[0,0], 'KP_Page_Up':[0,0], 'KP_End':[0,0], + 'KP_Home':[-1,-1],'Return':[-1,-1], 'Esc':[0,0]} + if not mov_dict.has_key(keyname): + return + if keyname == 'KP_End': + self.run_button(0) + elif self.selected_spr is not None: + blk = self.block_list.spr_to_block(self.selected_spr) + tur = self.turtles.spr_to_turtle(self.selected_spr) + if blk is not None: + if keyname == 'Return' or keyname == 'KP_Page_Up': + (x, y) = blk.spr.get_xy() + self._click_block(x, y) + elif keyname == 'KP_Page_Down': + if self.drag_group == None: + self.drag_group = self._find_group(blk) + for b in self.drag_group: b.spr.hide() + self.drag_group = None + else: + self._jog_block(blk, mov_dict[keyname][0], + mov_dict[keyname][1]) + elif tur is not None: + self._jog_turtle(mov_dict[keyname][0], mov_dict[keyname][1]) + return True + """ Jog turtle """ @@ -1495,16 +1526,6 @@ class TurtleArtWindow(): self.drag_group = None """ - Import Python code into a block - """ - def _import_py(self): - if self.running_sugar: - self.activity.import_py() - else: - self.load_python_code() - self.set_userdefined() - - """ Make sure a 'number' block contains a number. """ def _number_check(self): @@ -1546,12 +1567,28 @@ class TurtleArtWindow(): f.close() """ + Import Python code into a block + """ + def _import_py(self): + if self.running_sugar: + self.activity.import_py() + else: + self.load_python_code() + self.set_userdefined() + + """ Start a new project """ def new_project(self): stop_logo(self) - for b in self.just_blocks(): - b.spr.hide() + # Put current project in the trash. + while len(self.just_blocks()) > 0: + b = self.just_blocks()[0] + top = self.find_top_block(b) + self.trash_stack.append(top) + for b in self._find_group(top): + b.type = 'trash' + b.spr.hide() self.canvas.clearscreen() self.save_file_name = None @@ -1573,65 +1610,6 @@ class TurtleArtWindow(): self.load_files(fname+'.ta', create_new_project) if create_new_project is True: self.save_file_name = os.path.basename(fname) - - """ - Create a "macro" (predefined stack of blocks) - """ - def _new_macro(self, name, x, y): - macro = MACROS[name] - macro[0][2] = x - macro[0][3] = y - self.process_data(macro) - - """ - Process data (from a file or clipboard) into blocks - """ - def process_data(self, data): - # Create the blocks (or turtle). - blocks = [] - for b in data: - if self._found_a_turtle(b) is False: - blk = self.load_block(b) - blocks.append(blk) - # Make the connections. - for i in range(len(blocks)): - cons=[] - # Normally, it is simply a matter of copying the connections. - if blocks[i].connections == None: - for c in data[i][4]: - if c is None: - cons.append(None) - else: - cons.append(blocks[c]) - elif blocks[i].connections == 'check': - # Ugly corner case is to convert old-style booleans op. - cons.append(None) # Add an extra connection. - for c in data[i][4]: - if c is None: - cons.append(None) - else: - cons.append(blocks[c]) - # If the boolean op was connected, readjust the plumbing. - if data[i][4][0] is not None: - c = data[i][4][0] - cons[0] = blocks[data[c][4][0]] - c0 = data[c][4][0] - for j, cj in enumerate(data[c0][4]): - if cj == c: - blocks[c0].connections[j] = blocks[i] - if c0 and c is not None: - bdock = blk.docks[i] - for j in range(len(c.docks)): - if c.connections[j] == blk: - cdock = c.docks[j] - nx, ny = sx+bdock[2]-cdock[2], sy+bdock[3]-cdock[3] - c.spr.move((nx, ny)) - self._adjust_dock_positions(c) + def load_turtle(self, b, key=1): + id, name, xcor, ycor, heading, color, shade, pensize = b + self.canvas.set_turtle(key) + self.canvas.setxy(xcor, ycor) + self.canvas.seth(heading) + self.canvas.setcolor(color) + self.canvas.setshade(shade) + self.canvas.setpensize(pensize) """ Restore individual blocks from saved state @@ -1761,18 +1736,6 @@ class TurtleArtWindow(): if check_dock is True: blk.connections = 'check' return blk - - """ - Restore a turtle from its saved state - """ - def load_turtle(self, b, key=1): - id, name, xcor, ycor, heading, color, shade, pensize = b - self.canvas.set_turtle(key) - self.canvas.setxy(xcor, ycor) - self.canvas.seth(heading) - self.canvas.setcolor(color) - self.canvas.setshade(shade) - self.canvas.setpensize(pensize) """ Start a new project with a 'start' brick @@ -1848,7 +1811,7 @@ class TurtleArtWindow(): self.canvas.color, self.canvas.shade, self.canvas.pensize)) return data - + """ Display the coordinates of the current turtle """ @@ -1864,26 +1827,6 @@ class TurtleArtWindow(): self.win.set_title("%s — %s: %d %s: %d %s: %d" % (_("Turtle Art"), _("xcor"), x, _("ycor"), y, _("heading"), h)) - """ - Did the sprite's hide (contract) button get hit? - """ - def _hide_button_hit(self, spr, x, y): - r,g,b,a = spr.get_pixel((x, y)) - if (r == 255 and g == 0) or g == 255: - return True - else: - return False - - """ - Did the sprite's show (expand) button get hit? - """ - def _show_button_hit(self, spr, x, y): - r,g,b,a = spr.get_pixel((x, y)) - if (r == 255 and g == 0) or g == 255: - return False - else: - return True - def showlabel(self, shp, label=''): if shp == 'syntaxerror' and label != '': shp = label[1:] @@ -1901,6 +1844,9 @@ class TurtleArtWindow(): else: self.status_spr.move((PALETTE_WIDTH, self.height-200)) + """ + Relative placement of portfolio objects + """ def calc_position(self, t): w,h,x,y,dx,dy = TEMPLATES[t] x *= self.canvas.width @@ -1910,3 +1856,61 @@ class TurtleArtWindow(): dx *= w dy *= h return(w,h,x,y,dx,dy) + + """ + Where is the mouse event? + """ + def _xy(self, event): + return map(int, event.get_coords()) + + """ + Find a stack to run (any stack without a 'def action'on the top). + """ + def _find_block_to_run(self, blk): + top = self.find_top_block(blk) + if blk == top and blk.name[0:3] is not 'def': + return True + else: + return False + + """ + Find the top block in a stack. + """ + def find_top_block(self, blk): + while blk.connections[0] is not None: + blk = blk.connections[0] + return blk + + """ + Find a stack with a 'start' block on top. + """ + def _find_start_stack(self, blk): + top = self.find_top_block(blk) + if top.name == 'start': + return True + else: + return False + + """ + Find the connected group of block in a stack. + """ + def _find_group(self, blk): + if blk is None: + return [] + group=[blk] + if blk.connections is not None: + for blk2 in blk.connections[1:]: + if blk2 is not None: + group.extend(self._find_group(blk2)) + return group + + """ + Filter out 'proto', 'trash', and 'deleted' blocks + """ + def just_blocks(self): + just_blocks_list = [] + for b in self.block_list.list: + if b.type == 'block': + just_blocks_list.append(b) + return just_blocks_list + -- cgit v0.9.1