Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TurtleArt/tawindow.py
diff options
context:
space:
mode:
Diffstat (limited to 'TurtleArt/tawindow.py')
-rw-r--r--TurtleArt/tawindow.py207
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: