diff options
-rw-r--r-- | TurtleArt/tabasics.py | 5 | ||||
-rw-r--r-- | TurtleArt/tawindow.py | 34 | ||||
-rw-r--r-- | icons/macrosoff.svg | 69 | ||||
-rw-r--r-- | icons/macroson.svg | 70 | ||||
-rwxr-xr-x | turtleblocks.py | 43 |
5 files changed, 218 insertions, 3 deletions
diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py index 81eba2d..0d88a9d 100644 --- a/TurtleArt/tabasics.py +++ b/TurtleArt/tabasics.py @@ -107,6 +107,11 @@ class Palettes(): self._blocks_palette() + palette = make_palette('macros', + colors=["#FFC000", "#A08000"], + help_string=\ + _('Palette of user-defined operators')) + self._trash_palette() # Palette definitions diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py index 906a7d8..14c0190 100644 --- a/TurtleArt/tawindow.py +++ b/TurtleArt/tawindow.py @@ -40,7 +40,9 @@ except ImportError: import os import subprocess +import errno +from random import uniform from math import atan2, pi DEGTOR = 2 * pi / 360 @@ -68,7 +70,7 @@ from tautils import (magnitude, get_load_name, get_save_name, data_from_file, calc_image_size, get_path, hide_button_hit, show_button_hit, chooser, arithmetic_check, xy, find_block_to_run, find_top_block, journal_check, find_group, find_blk_below, data_to_string, find_start_stack, - get_hardware, debug_output, error_output, convert, + get_hardware, debug_output, error_output, convert, find_hat, find_bot_block, restore_clamp, collapse_clamp, data_from_string, increment_name, get_screen_dpi) from tasprite_factory import (SVG, svg_str_to_pixbuf, svg_from_file) @@ -142,6 +144,8 @@ class TurtleArtWindow(): self.mouse_y = 0 self.update_counter = 0 self.running_blocks = False + self.saving_macro = False + self.macros_path = '' try: locale.setlocale(locale.LC_NUMERIC, '') @@ -1862,6 +1866,34 @@ before making changes to your Turtle Blocks program')) for blk in self.drag_group: if blk.status != 'collapsed': blk.spr.set_layer(TOP_LAYER) + if self.saving_macro: + for blk in self.drag_group: + if blk.status != 'collapsed': + blk.highlight() + self.block_operation = 'copying' + data = self.assemble_data_to_save(False, False) + i = find_hat(data) + if i is not None and data[i][4][1] is not None: + try: + name = str(data[data[i][4][1]][1][1]) + except: + name = 'macro%d' % (int(uniform(0, 10000))) + debug_output('saving macro %s' % (name), + self.running_sugar) + if not os.path.exists(self.macros_path): + try: + os.makedirs(self.macros_path) + except OSError, exc: + if exc.errno == errno.EEXIST: + pass + else: + raise + data_to_file(data, os.path.join(self.macros_path, + '%s.tb' % (name))) + self.parent.get_window().set_cursor( + gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) + self.saving_macro = False + if self.running_sugar and \ (self.activity.copying or self.activity.sharing_blocks): for blk in self.drag_group: diff --git a/icons/macrosoff.svg b/icons/macrosoff.svg new file mode 100644 index 0000000..7d9a28c --- /dev/null +++ b/icons/macrosoff.svg @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <rect + width="45" + height="45" + x="5" + y="5" + id="rect2990" + style="fill:#282828;fill-opacity:1;stroke:none" /> + <g + id="g3789"> + <path + d="m 15.719636,31.331478 0.114372,5.261133 11.437247,6.290486 L 27.5,29.387146" + id="path2463" + style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 27.728744,29.501519 0.05719,13.381578 11.723178,-7.548583 0,-4.689272 -5.947368,3.545548" + id="path2465" + style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 10.001012,27.328441 5.604251,-5.146761 -5.832996,-2.973684 12.123482,-7.091093 5.718623,3.316801 5.489879,-3.088056 12.123482,7.319838 -5.832996,2.401822 5.489878,5.032388 -11.322874,7.205466 -5.947369,-5.261134 -6.290485,5.261134 -11.322875,-6.976721 z" + id="path2459" + style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="M 16.40587,21.952935 27.156883,15.204959 38.937247,22.067308 27.614372,28.815283 16.40587,21.952935 z" + id="path2461" + style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + </g> + <g + transform="matrix(0.39620698,0,0,0.39620698,28.654032,26.094918)" + id="stock-xo_1_" + style="display:block"> + <path + d="m 33.233,35.1 10.102,10.1 c 0.752,0.75 1.217,1.783 1.217,2.932 0,2.287 -1.855,4.143 -4.146,4.143 -1.145,0 -2.178,-0.463 -2.932,-1.211 l -10.102,-10.103 -10.1,10.1 c -0.75,0.75 -1.787,1.211 -2.934,1.211 -2.284,0 -4.143,-1.854 -4.143,-4.141 0,-1.146 0.465,-2.184 1.212,-2.934 L 21.511,35.095 11.409,24.995 c -0.747,-0.748 -1.212,-1.785 -1.212,-2.93 0,-2.289 1.854,-4.146 4.146,-4.146 1.143,0 2.18,0.465 2.93,1.214 L 27.372,29.235 37.474,19.132 c 0.754,-0.749 1.787,-1.214 2.934,-1.214 2.289,0 4.146,1.856 4.146,4.145 0,1.146 -0.467,2.18 -1.217,2.932 L 33.233,35.1 z" + id="path3076" + style="fill:#ffffff;stroke:#010101;stroke-width:3.5" /> + <circle + cx="27.371" + cy="10.849" + r="8.1219997" + id="circle3078" + style="fill:#ffffff;stroke:#010101;stroke-width:3.5" /> + </g> +</svg> diff --git a/icons/macroson.svg b/icons/macroson.svg new file mode 100644 index 0000000..bb8852d --- /dev/null +++ b/icons/macroson.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs4" /> + <rect + width="55" + height="55" + rx="0" + x="0" + y="0" + id="rect2839" + style="fill:#ffd200;fill-opacity:1;fill-rule:evenodd;stroke:none" /> + <g + id="g3788"> + <path + d="m 15.719636,31.331478 0.114372,5.261133 11.437247,6.290486 L 27.5,29.387146" + id="path2463" + style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#804000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 27.728744,29.501519 0.05719,13.381578 11.723178,-7.548583 0,-4.689272 -5.947368,3.545548" + id="path2465" + style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#804000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 10.001012,27.328441 5.604251,-5.146761 -5.832996,-2.973684 12.123482,-7.091093 5.718623,3.316801 5.489879,-3.088056 12.123482,7.319838 -5.832996,2.401822 5.489878,5.032388 -11.322874,7.205466 -5.947369,-5.261134 -6.290485,5.261134 -11.322875,-6.976721 z" + id="path2459" + style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#804000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="M 16.40587,21.952935 27.156883,15.204959 38.937247,22.067308 27.614372,28.815283 16.40587,21.952935 z" + id="path2461" + style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#804000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + </g> + <g + transform="matrix(0.39620698,0,0,0.39620698,28.654032,26.094918)" + id="stock-xo_1_" + style="display:block"> + <path + d="m 33.233,35.1 10.102,10.1 c 0.752,0.75 1.217,1.783 1.217,2.932 0,2.287 -1.855,4.143 -4.146,4.143 -1.145,0 -2.178,-0.463 -2.932,-1.211 l -10.102,-10.103 -10.1,10.1 c -0.75,0.75 -1.787,1.211 -2.934,1.211 -2.284,0 -4.143,-1.854 -4.143,-4.141 0,-1.146 0.465,-2.184 1.212,-2.934 L 21.511,35.095 11.409,24.995 c -0.747,-0.748 -1.212,-1.785 -1.212,-2.93 0,-2.289 1.854,-4.146 4.146,-4.146 1.143,0 2.18,0.465 2.93,1.214 L 27.372,29.235 37.474,19.132 c 0.754,-0.749 1.787,-1.214 2.934,-1.214 2.289,0 4.146,1.856 4.146,4.145 0,1.146 -0.467,2.18 -1.217,2.932 L 33.233,35.1 z" + id="path3076" + style="fill:#ffffff;stroke:#010101;stroke-width:3.5" /> + <circle + cx="27.371" + cy="10.849" + r="8.1219997" + id="circle3078" + style="fill:#ffffff;stroke:#010101;stroke-width:3.5" /> + </g> +</svg> diff --git a/turtleblocks.py b/turtleblocks.py index ed2ebce..d8b256c 100755 --- a/turtleblocks.py +++ b/turtleblocks.py @@ -30,6 +30,7 @@ import getopt import sys import os import os.path +import glob import cStringIO import errno import ConfigParser @@ -48,10 +49,12 @@ sys.argv[1:] = [] # Execution of import gst cannot see '--help' or '-h' import gettext from TurtleArt.taconstants import (OVERLAY_LAYER, DEFAULT_TURTLE_COLORS, - TAB_LAYER, SUFFIX) -from TurtleArt.tautils import (data_to_string, data_from_string, get_save_name) + TAB_LAYER, SUFFIX, MACROS) +from TurtleArt.tautils import (data_to_string, data_from_string, listify, + data_from_file, get_save_name, hat_on_top) from TurtleArt.tawindow import TurtleArtWindow from TurtleArt.taexportlogo import save_logo +from TurtleArt.tapalette import make_palette from util.menubuilder import MenuBuilder @@ -63,6 +66,7 @@ class TurtleMain(): '/usr/local/share/sugar/activities/TurtleArt.activity' _ICON_SUBPATH = 'images/turtle.png' _GNOME_PLUGIN_SUBPATH = 'gnome_plugins' + _MACROS_SUBPATH = 'macros' def __init__(self): self._abspath = os.path.abspath('.') @@ -105,6 +109,7 @@ class TurtleMain(): self._init_gnome_plugins() self._setup_gtk() self._build_window() + self._load_user_macros() self._run_gnome_plugins() self._start_gtk() @@ -166,6 +171,37 @@ class TurtleMain(): if not exists(dpath): makedirs(dpath) + def _load_user_macros(self): + ''' User-defined macros are saved as a json-encoded file; + these get loaded into a palette on startup ''' + macros_path = os.path.join(self._execdirname, self._MACROS_SUBPATH) + self.tw.macros_path = macros_path + if os.path.exists(macros_path): + files = glob.glob(os.path.join(macros_path, '*.tb')) + print 'creating macros palette' + if len(files) > 0: + palette = make_palette('macros', + colors=["#FFC000", "#A08000"], + help_string=\ +_('Palette of user-defined operators')) + + for tafile in files: + data = data_from_file(tafile) + name = os.path.basename(tafile)[:-3] + print 'loading macro %s' % (name) + MACROS['user-defined-' + name] = hat_on_top(listify(data)) + palette.add_block('user-defined-' + name, + style='basic-style-extended-vertical', + label=name) + + def _do_save_macro_cb(self, widget): + if self.saving_macro: + self.win.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) + self.tw.saving_macro = False + else: + self.win.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1)) + self.tw.saving_macro = True + def _start_gtk(self): ''' Get a main window set up. ''' self.win.connect('configure_event', self.tw.update_overlay_position) @@ -216,6 +252,7 @@ class TurtleMain(): self.current_palette = 0 self.scale = 2.0 self.tw = None + self.saving_macro = False self.init_complete = False def _parse_command_line(self): @@ -385,6 +422,8 @@ class TurtleMain(): menu = gtk.Menu() MenuBuilder.make_menu_item(menu, _('Copy'), self._do_copy_cb) MenuBuilder.make_menu_item(menu, _('Paste'), self._do_paste_cb) + MenuBuilder.make_menu_item(menu, _('Save stack'), + self._do_save_macro_cb) edit_menu = MenuBuilder.make_sub_menu(menu, _('Edit')) menu = gtk.Menu() |