Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--TurtleArt/tabasics.py5
-rw-r--r--TurtleArt/tawindow.py10
-rw-r--r--TurtleArtActivity.py17
-rw-r--r--activity/activity.info2
-rw-r--r--icons/save-macro.svg78
-rw-r--r--plugins/turtle_blocks_extras/turtle_blocks_extras.py51
-rwxr-xr-xturtleblocks.py27
8 files changed, 149 insertions, 46 deletions
diff --git a/NEWS b/NEWS
index 0fc53e0..89434c5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+176
+
+ENHANCEMENT:
+* Add facility for saving and restoring individual stacks
+
175
ENHANCEMENT:
diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py
index 0d88a9d..81eba2d 100644
--- a/TurtleArt/tabasics.py
+++ b/TurtleArt/tabasics.py
@@ -107,11 +107,6 @@ 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 14c0190..06c0276 100644
--- a/TurtleArt/tawindow.py
+++ b/TurtleArt/tawindow.py
@@ -91,6 +91,7 @@ class TurtleArtWindow():
''' TurtleArt Window class abstraction '''
timeout_tag = [0]
_PLUGIN_SUBPATH = 'plugins'
+ _MACROS_SUBPATH = 'macros'
def __init__(self, canvas_window, path, parent=None,
mycolors=None, mynick=None, turtle_canvas=None,
@@ -113,6 +114,10 @@ class TurtleArtWindow():
self.running_sugar = True
from sugar import profile
self.nick = profile.get_nick_name()
+ self.macros_path = os.path.join(
+ get_path(parent, 'data'), self._MACROS_SUBPATH)
+ else:
+ self.macros_path = os.path.join(self.path, self._MACROS_SUBPATH)
self._setup_events()
else:
self.interactive_mode = False
@@ -145,7 +150,6 @@ class TurtleArtWindow():
self.update_counter = 0
self.running_blocks = False
self.saving_macro = False
- self.macros_path = ''
try:
locale.setlocale(locale.LC_NUMERIC, '')
@@ -170,9 +174,9 @@ class TurtleArtWindow():
self.orientation = VERTICAL_PALETTE
else:
self.scale = 1.0
- self.entry_scale = 1.0
+ self.entry_scale = 1.0
self.color_mode = '888' # TODO: Read visual mode from gtk image
- self._set_screen_dpi()
+ self._set_screen_dpi()
self.block_scale = BLOCK_SCALE[3]
self.trash_scale = 0.5
diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py
index 2583a0c..49e4a39 100644
--- a/TurtleArtActivity.py
+++ b/TurtleArtActivity.py
@@ -621,6 +621,8 @@ class TurtleArtActivity(activity.Activity):
edit_toolbar, '<Ctrl>v')
self._add_button('edit-undo', _('Restore blocks from trash'),
self._undo_cb, edit_toolbar)
+ self._add_button('save-macro', _('Save stack'), self._save_macro_cb,
+ edit_toolbar)
self._add_button('view-fullscreen', _('Fullscreen'),
self.do_fullscreen_cb, self._view_toolbar,
@@ -766,6 +768,7 @@ class TurtleArtActivity(activity.Activity):
add_section(help_box, _('Edit'), icon='toolbar-edit')
add_paragraph(help_box, _('Copy'), icon='edit-copy')
add_paragraph(help_box, _('Paste'), icon='edit-paste')
+ add_paragraph(help_box, _('Save stack'), icon='save-macro')
help_box = gtk.VBox()
help_box.set_homogeneous(False)
@@ -1089,6 +1092,7 @@ class TurtleArtActivity(activity.Activity):
self._old_cursor = None
self.copying = False
self.sharing_blocks = False
+ self.tw.saving_macro = False
def _setup_sharing(self):
''' Setup the Collabora stack. '''
@@ -1351,6 +1355,7 @@ in order to use the plugin.'))
def _copy_cb(self, button):
''' Copy to the clipboard. '''
if self.copying:
+ self.copying = False
self.restore_cursor()
else:
self.copying = True
@@ -1359,6 +1364,18 @@ in order to use the plugin.'))
self._old_cursor = self.get_window().get_cursor()
self.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1))
+ def _save_macro_cb(self, button):
+ ''' Save stack macros_path '''
+ if self.tw.saving_macro:
+ self.tw.saving_macro = False
+ self.restore_cursor()
+ else:
+ self.tw.saving_macro = True
+ if hasattr(self, 'get_window'):
+ if hasattr(self.get_window(), 'get_cursor'):
+ self._old_cursor = self.get_window().get_cursor()
+ self.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1))
+
def send_to_clipboard(self):
''' Send selected stack to clipboard. '''
self.restore_cursor()
diff --git a/activity/activity.info b/activity/activity.info
index 3d1e9d5..df3b388 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -1,6 +1,6 @@
[Activity]
name = TurtleBlocks
-activity_version = 175
+activity_version = 176
license = MIT
bundle_id = org.laptop.TurtleArtActivity
exec = sugar-activity TurtleArtActivity.TurtleArtActivity
diff --git a/icons/save-macro.svg b/icons/save-macro.svg
new file mode 100644
index 0000000..c2cff38
--- /dev/null
+++ b/icons/save-macro.svg
@@ -0,0 +1,78 @@
+<?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.1"
+ width="55"
+ height="55"
+ viewBox="0 0 55 55"
+ id="svg2"
+ xml:space="preserve"><metadata
+ id="metadata25"><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="defs33" /><g
+ id="g3830"><g
+ transform="matrix(0.55205508,0,0,0.55205508,75.618464,18.235971)"
+ id="g4382"><g
+ transform="translate(-80.093659,12.220029)"
+ id="g4308"
+ style="fill:none;stroke:#ffffff;stroke-opacity:1"><g
+ id="g4310"
+ style="fill:none;stroke:#ffffff;stroke-opacity:1"><path
+ d="m 6.736,49.002 h 24.52 c 2.225,0 3.439,-1.447 3.439,-3.441 v -27.28 c 0,-1.73 -1.732,-3.441 -3.439,-3.441 h -4.389"
+ id="path4312"
+ style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /></g></g><g
+ transform="translate(-80.093659,12.220029)"
+ id="g4314"
+ style="fill:none;stroke:#ffffff;stroke-opacity:1"><g
+ id="g4316"
+ style="fill:none;stroke:#ffffff;stroke-opacity:1"><path
+ d="m 26.867,38.592 c 0,1.836 -1.345,3.201 -3.441,4.047 L 6.736,49.002 V 14.84 l 16.69,-8.599 c 2.228,-0.394 3.441,0.84 3.441,2.834 v 29.517 z"
+ id="path4318"
+ style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /></g></g><path
+ d="m -70.669659,54.827029 c 0,0 -1.351,-0.543 -2.702,-0.543 -1.351,0 -2.703,0.543 -2.703,0.543"
+ id="path4320"
+ style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><path
+ d="m -70.669659,44.226029 c 0,0 -1.239,-0.543 -2.815,-0.543 -1.577,0 -2.59,0.543 -2.59,0.543"
+ id="path4322"
+ style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><path
+ d="m -70.669659,33.898029 c 0,0 -1.125,-0.544 -2.927,-0.544 -1.802,0 -2.478,0.544 -2.478,0.544"
+ id="path4324"
+ style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><line
+ id="line4326"
+ y2="23.725029"
+ y1="58.753029"
+ x2="-66.884659"
+ x1="-66.884659"
+ style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /></g><g
+ transform="matrix(1,0,0,-1,-30.386573,49.171266)"
+ id="g4770"><g
+ transform="translate(34.0803,-1006.42)"
+ id="g4772"><polyline
+ id="polyline4774"
+ points="51.562,15.306 41.17,16.188 42.053,5.794"
+ style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round"
+ transform="matrix(-0.469241,0.469241,-0.469241,-0.469241,66.2906,1019.03)" /><path
+ d="m 39.363241,1033.1291 -0.05636,9.9115 -8.750608,0.067"
+ id="path4776"
+ style="fill:none;stroke:#ffffff;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></g><g
+ transform="matrix(0.80095119,0,0,0.80095119,-4.6564792,-5.9184549)"
+ 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></svg> \ No newline at end of file
diff --git a/plugins/turtle_blocks_extras/turtle_blocks_extras.py b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
index d2e6cfb..1593f4b 100644
--- a/plugins/turtle_blocks_extras/turtle_blocks_extras.py
+++ b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
@@ -19,21 +19,25 @@ import gtk
import gobject
from time import time
import os
+import glob
from gettext import gettext as _
from plugins.plugin import Plugin
-from TurtleArt.tapalette import make_palette, define_logo_function, \
- block_names, block_primitives, special_names, content_blocks, \
- palette_name_to_index, palette_names
-from TurtleArt.talogo import primitive_dictionary, logoerror, \
- media_blocks_dictionary
-from TurtleArt.taconstants import DEFAULT_SCALE, ICON_SIZE, CONSTANTS, \
- MEDIA_SHAPES, SKIN_PATHS, BLOCKS_WITH_SKIN, PYTHON_SKIN, \
- PREFIX_DICTIONARY, VOICES, MACROS, COLORDICT
-from TurtleArt.tautils import convert, round_int, debug_output, get_path, \
- data_to_string, find_group, image_to_base64
-from TurtleArt.tajail import myfunc, myfunc_import
+from TurtleArt.tapalette import (make_palette, define_logo_function,
+ block_names, block_primitives, special_names,
+ content_blocks, palette_name_to_index,
+ palette_names)
+from TurtleArt.talogo import (primitive_dictionary, logoerror,
+ media_blocks_dictionary)
+from TurtleArt.taconstants import (DEFAULT_SCALE, ICON_SIZE, CONSTANTS,
+ MEDIA_SHAPES, SKIN_PATHS, BLOCKS_WITH_SKIN,
+ PYTHON_SKIN, PREFIX_DICTIONARY, VOICES,
+ MACROS, COLORDICT)
+from TurtleArt.tautils import (convert, round_int, debug_output, get_path,
+ data_to_string, find_group, image_to_base64,
+ hat_on_top, listify, data_from_file)
+from TurtleArt.tajail import (myfunc, myfunc_import)
def _num_type(x):
@@ -90,6 +94,8 @@ class Turtle_blocks_extras(Plugin):
self._portfolio_palette()
+ self._macros_palette()
+
# Palette definitions
def _flow_palette(self):
@@ -1042,6 +1048,29 @@ Journal objects"))
bullets'))
self.tw.lc.def_prim('bullet', 1, self._prim_list, True)
+ def _macros_palette(self):
+ ''' User-defined macros are saved as a json-encoded file;
+ these get loaded into a palette on startup '''
+
+ if os.path.exists(self.tw.macros_path):
+ files = glob.glob(os.path.join(self.tw.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)
+
+
# Block primitives
def _prim_emptyheap(self):
diff --git a/turtleblocks.py b/turtleblocks.py
index d8b256c..7cf5afd 100755
--- a/turtleblocks.py
+++ b/turtleblocks.py
@@ -109,7 +109,6 @@ class TurtleMain():
self._init_gnome_plugins()
self._setup_gtk()
self._build_window()
- self._load_user_macros()
self._run_gnome_plugins()
self._start_gtk()
@@ -171,31 +170,8 @@ 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:
+ if self.tw.saving_macro:
self.win.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
self.tw.saving_macro = False
else:
@@ -252,7 +228,6 @@ _('Palette of user-defined operators'))
self.current_palette = 0
self.scale = 2.0
self.tw = None
- self.saving_macro = False
self.init_complete = False
def _parse_command_line(self):