diff options
Diffstat (limited to 'TurtleArt/tawindow.py')
-rw-r--r-- | TurtleArt/tawindow.py | 207 |
1 files changed, 179 insertions, 28 deletions
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py index 5b9a1c6..7880ce0 100644 --- a/TurtleArt/tawindow.py +++ b/TurtleArt/tawindow.py @@ -1662,9 +1662,20 @@ before making changes to your program')) name = blk.name # You can only have one instance of some blocks if blk.name in ['start', 'hat1', 'hat2']: - if len(self.block_list.get_similar_blocks( - 'block', blk.name)) > 0: + blk_list = self.block_list.get_similar_blocks( + 'block', blk.name) + if len(blk_list) > 0: self.showlabel('dupstack') + if blk.name == 'start': + # Recenter the screen and move the start + # stack to the center of the screen + if self.running_sugar: + self.activity.recenter() + dx = 200 - blk_list[0].spr.get_xy()[0] + dy = 200 - blk_list[0].spr.get_xy()[1] + drag_group = find_group(blk_list[0]) + for dblk in drag_group: + dblk.spr.move_relative((dx, dy)) return True # We need to check to see if there is already a # similarly default named stack @@ -2176,7 +2187,7 @@ before making changes to your program')) for gblk in group: if gblk.name == 'sandwichclampcollapsed': restore_clamp(gblk) - self.resize_parent_clamps(gblk) + self._resize_parent_clamps(gblk) for gblk in group: gblk.rescale(self.block_scale) @@ -2542,10 +2553,15 @@ before making changes to your program')) if blk is None: continue if blk.name in EXPANDABLE_FLOW: - if blk.name in block_styles['clamp-style-1arg'] or\ + if blk.name in block_styles['clamp-style-1arg'] or \ blk.name in block_styles['clamp-style-boolean']: if blk.connections[2] is not None: self._resize_clamp(blk, blk.connections[2]) + elif blk.name in block_styles['clamp-style-until']: + if blk.connections[2] is not None: + self._resize_clamp(blk, blk.connections[2]) + if blk.connections[1] is not None: + self._resize_clamp(blk, blk.connections[1], dockn=1) elif blk.name in block_styles['clamp-style']: if blk.connections[1] is not None: self._resize_clamp(blk, blk.connections[1]) @@ -3217,6 +3233,13 @@ before making changes to your program')) if len(self.block_list.get_similar_blocks('block', 'forever')) > 0: debug_output('WARNING: Projects with forever blocks \ may not terminate.', False) + else: + self._hide_text_entry() + self.parent.get_window().set_cursor( + gtk.gdk.Cursor(gtk.gdk.WATCH)) + gobject.idle_add(self.__run_stack, blk) + + def __run_stack(self, blk): if self.status_spr is not None: self.status_spr.hide() self._autohide_shape = True @@ -3229,12 +3252,16 @@ before making changes to your program')) self.start_plugins() # Let the plugins know we are running. top = find_top_block(blk) code = self.lc.generate_code(top, self.just_blocks()) + if self.interactive_mode: + self.parent.get_window().set_cursor( + gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) self.lc.run_blocks(code) if self.interactive_mode: gobject.idle_add(self.lc.doevalstep) else: while self.lc.doevalstep(): pass + self.running_blocks = False def _snap_to_dock(self): ''' Snap a block (selected_block) to the dock of another block @@ -3373,6 +3400,14 @@ before making changes to your program')) if best_destination_dockn == 2: self._resize_clamp(best_destination, self.drag_group[0]) + elif best_destination.name in \ + block_styles['clamp-style-until']: + if best_destination_dockn == 2: + self._resize_clamp(best_destination, + self.drag_group[0]) + elif best_destination_dockn == 1: + self._resize_clamp(best_destination, + self.drag_group[0], dockn=1) elif best_destination.name in block_styles['clamp-style'] or \ best_destination.name in \ block_styles['clamp-style-collapsible']: @@ -3470,16 +3505,19 @@ before making changes to your program')) self._expand_expandable(blk2, blk, dy) self._cascade_expandable(blk2) elif c is not None and blk2.name in EXPANDABLE_FLOW: - if blk2.name in block_styles['clamp-style-1arg'] or\ + if blk2.name in block_styles['clamp-style-1arg'] or \ blk2.name in block_styles['clamp-style-boolean']: if c == 2: - self._resize_clamp(blk2, None, c) + self._resize_clamp(blk2, None, dockn=c) + elif blk2.name in block_styles['clamp-style-until']: + if c in [1, 2]: + self._resize_clamp(blk2, None, dockn=c) elif blk2.name in block_styles['clamp-style'] or \ blk2.name in block_styles['clamp-style-collapsible']: if c == 1: self._resize_clamp(blk2, None) elif blk2.name in block_styles['clamp-style-else']: - if c == 2 or c == 3: + if c in [2, 3]: self._resize_clamp(blk2, None, dockn=c) while blk3 is not None and blk3.connections[dockn] is not None: self._resize_clamp(blk3, blk3.connections[dockn], dockn=dockn) @@ -3495,22 +3533,35 @@ before making changes to your program')) y1 = blk.docks[-1][3] if blk.name in block_styles['clamp-style-else'] and dockn == 3: blk.reset_y2() + elif blk.name in block_styles['clamp-style-until'] and dockn == 1: + blk.reset_y2() else: blk.reset_y() dy = 0 # Calculate height of drag group - while gblk is not None: - delta = int((gblk.docks[-1][3] - gblk.docks[0][3]) / gblk.scale) - if delta == 0: - dy += 21 # Fixme: don't hardcode size of stop action block - else: - dy += delta - gblk = gblk.connections[-1] - # Clamp has room for one 'standard' block by default - if dy > 0: - dy -= 21 # Fixme: don't hardcode + if blk.name in block_styles['clamp-style-until'] and dockn == 1: + if gblk is not None: + dy = int(gblk.spr.rect.height / gblk.scale) + # Room for part of one 'standard' boolean by default + if dy > 0: + dy -= 25 # Fixme: don't hardcode size of slot + if dy < 0: + dy = 0 + else: + while gblk is not None: + delta = int((gblk.docks[-1][3] - gblk.docks[0][3]) / gblk.scale) + if delta == 0: + dy += 21 # Fixme: don't hardcode size of slot + else: + dy += delta + gblk = gblk.connections[-1] + # Clamp has room for one 'standard' block by default + if dy > 0: + dy -= 21 # Fixme: don't hardcode size of slot if blk.name in block_styles['clamp-style-else'] and dockn == 3: blk.expand_in_y2(dy) + elif blk.name in block_styles['clamp-style-until'] and dockn == 1: + blk.expand_in_y2(dy) else: blk.expand_in_y(dy) y2 = blk.docks[-1][3] @@ -3520,12 +3571,18 @@ before making changes to your program')) drag_group = find_group(blk.connections[-1]) for gblk in drag_group: gblk.spr.move_relative((0, y2-y1)) - # We may have to move the else clamp group down too. + # We may have to move the else clamp group up or down too. if blk.name in block_styles['clamp-style-else'] and dockn == 2: if blk.connections[3] is not None: drag_group = find_group(blk.connections[3]) for gblk in drag_group: gblk.spr.move_relative((0, y2 - y1)) + # We may have to move the bool group up or down too. + if blk.name in block_styles['clamp-style-until']: + if blk.connections[1] is not None: + drag_group = find_group(blk.connections[1]) + for gblk in drag_group: + gblk.spr.move_relative((0, y2 - y1)) def _expandable_flow_above(self, blk): ''' Is there an expandable flow block above this one? ''' @@ -3810,11 +3867,8 @@ before making changes to your program')) self._snap_to_dock() self.drag_group = None - def _test_number(self): - ''' Make sure a 'number' block contains a number. ''' + def _hide_text_entry(self): if hasattr(self, '_text_entry'): - bounds = self._text_buffer.get_bounds() - text = self._text_buffer.get_text(bounds[0], bounds[1]) if self._focus_out_id is not None: self._text_entry.disconnect(self._focus_out_id) self._focus_out_id = None @@ -3822,6 +3876,13 @@ before making changes to your program')) self._text_buffer.disconnect(self._insert_text_id) self._insert_text_id = None self._text_entry.hide() + + def _test_number(self): + ''' Make sure a 'number' block contains a number. ''' + if hasattr(self, '_text_entry'): + bounds = self._text_buffer.get_bounds() + text = self._text_buffer.get_text(bounds[0], bounds[1]) + self._hide_text_entry() else: text = self.selected_blk.spr.labels[0] self._number_check(text) @@ -3868,12 +3929,9 @@ before making changes to your program')) def _test_string(self): if hasattr(self, '_text_entry'): - if self._focus_out_id is not None: - self._text_entry.disconnect(self._focus_out_id) - self._focus_out_id = None bounds = self._text_buffer.get_bounds() text = self._text_buffer.get_text(bounds[0], bounds[1]) - self._text_entry.hide() + self._hide_text_entry() else: text = self.selected_blk.spr.labels[0] self.selected_blk.spr.set_label(text.replace('\12', RETURN)) @@ -4552,13 +4610,20 @@ before making changes to your program')) self.status_spr.move((PALETTE_WIDTH, self.height - 400)) else: # Adjust vertical position based on scrolled window adjustment + offset_from_bottom = 60 if self.running_sugar: + if self.activity.toolbox.get_property("visible"): + if self.activity.toolbars_expanded(): + offset_from_bottom += 110 + else: + offset_from_bottom += 60 self.status_spr.move( (0, - self.height - 200 + + self.height - offset_from_bottom + self.activity.sw.get_vadjustment().get_value())) elif self.interactive_mode: - self.status_spr.move((0, self.height - 100)) + self.status_spr.move( + (0, self.activity.win.get_window().get_size()[1] - 80)) def calc_position(self, template): ''' Relative placement of portfolio objects (deprecated) ''' @@ -4584,6 +4649,92 @@ before making changes to your program')) save_picture(self.canvas, image_file) return ta_file, image_file + def save_as_icon(self, name=''): + from util.sugariconify import SugarIconify + + path = self.canvas.get_svg_path() + self._ensure_square_svg(path) # icons are square + + output_dir, basename = os.path.split(path) + + icon = SugarIconify() + icon.set_use_default_colors(True) + icon.set_output_path(output_dir) + icon.set_stroke_color('rgb(0%,0%,0%)') + icon.set_fill_color('rgb(99.215686%,99.215686%,99.215686%)') + icon.iconify(path) + + # replace .svg with .sugar.svg + sugarized_path = os.path.join(output_dir, basename[:-4] + '.sugar.svg') + + if self.running_sugar: + from sugar.datastore import datastore + from sugar import profile + + dsobject = datastore.create() + if len(name) == 0: + dsobject.metadata['title'] = '%s %s' % \ + (self.activity.metadata['title'], _('icon')) + else: + dsobject.metadata['title'] = name + dsobject.metadata['icon-color'] = profile.get_color().to_string() + dsobject.metadata['mime_type'] = 'image/svg+xml' + dsobject.set_file_path(sugarized_path) + datastore.write(dsobject) + dsobject.destroy() + self.saved_pictures.append((dsobject.object_id, True)) + os.remove(sugarized_path) + else: + if svg: + if len(name) == 0: + name = 'turtleblocks-icon.svg' + if self.save_folder is not None: + self.load_save_folder = self.save_folder + name, self.load_save_folder = get_save_name( + '.svg', self.load_save_folder, name) + datapath = self.load_save_folder + else: + datapath = os.getcwd() + if '.svg' not in name: + name = name + '.svg' + subprocess.check_output( + ['cp', TMP_SVG_PATH, os.path.join(datapath, name)]) + + def write_svg_operation(self): + self.canvas.svg_close() + self.canvas.svg_reset() + + def _ensure_square_svg(self, path): + from xml.dom import minidom + + fil = open(path, 'r') + svg_text = fil.read() + fil.close() + + svg_xml = minidom.parseString(svg_text) + svg_element = svg_xml.getElementsByTagName('svg')[0] + + width = int(svg_element.getAttribute('width')[:-2]) + height = int(svg_element.getAttribute('height')[:-2]) + size = min(width, height) + + svg_element.setAttribute('width', str(size) + 'pt') + svg_element.setAttribute('height', str(size) + 'pt') + + if width > height: + dx = int((width - size) / 2) + view_box = '%d 0 %d %d' % (dx, size, size) + else: + dy = int((height - size) / 2) + view_box = '0 %d %d %d' % (dy, size, size) + + svg_element.setAttribute('viewBox', view_box) + svg_text = svg_xml.toxml() + + fil = open(path, 'w+') + fil.write(svg_text) + fil.close() + def save_as_image(self, name='', svg=False): ''' Grab the current canvas and save it. ''' if svg: |