Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Bender <walter@sugarlabs.org>2013-07-21 19:32:58 (GMT)
committer Walter Bender <walter@sugarlabs.org>2013-07-21 19:32:58 (GMT)
commit255832b29fc11a87438eb180cf4727501ef7a451 (patch)
tree94695da5d426e34e13d83a2172dbda8c17ae4bdb
parent6d3c7f5b0ffa076e32458b9f66cb77b03b380e8a (diff)
convert to iconview, turtle-centric
-rw-r--r--TurtleArt/tabasics.py353
-rw-r--r--TurtleArt/tablock.py26
-rw-r--r--TurtleArt/tacanvas.py607
-rw-r--r--TurtleArt/tacollaboration.py86
-rw-r--r--TurtleArt/talogo.py57
-rwxr-xr-xTurtleArt/tasprite_factory.py29
-rw-r--r--TurtleArt/taturtle.py737
-rw-r--r--TurtleArt/tautils.py9
-rw-r--r--TurtleArt/tawindow.py336
-rw-r--r--challenges/confusion-01.svg (renamed from challenges/confusion-1.svg)0
-rw-r--r--challenges/confusion-02.svg (renamed from challenges/confusion-2.svg)0
-rw-r--r--challenges/confusion-03.svg (renamed from challenges/confusion-3.svg)0
-rw-r--r--challenges/confusion-04.svg (renamed from challenges/confusion-4.svg)0
-rw-r--r--challenges/confusion-05.svg (renamed from challenges/confusion-5.svg)0
-rw-r--r--challenges/confusion-06.svg (renamed from challenges/confusion-6.svg)0
-rw-r--r--challenges/confusion-07.svg (renamed from challenges/confusion-7.svg)0
-rw-r--r--challenges/confusion-08.svg (renamed from challenges/confusion-8.svg)0
-rw-r--r--challenges/confusion-09.svg (renamed from challenges/confusion-9.svg)0
-rw-r--r--challenges/help-confusion-01.ta (renamed from challenges/help-1.ta)0
-rw-r--r--challenges/help-confusion-02.ta (renamed from challenges/help-2.ta)0
-rw-r--r--challenges/help-confusion-03.ta (renamed from challenges/help-3.ta)0
-rw-r--r--challenges/help-confusion-04.ta (renamed from challenges/help-4.ta)0
-rw-r--r--challenges/help-confusion-05.ta (renamed from challenges/help-5.ta)0
-rw-r--r--challenges/help-confusion-06.ta (renamed from challenges/help-6.ta)0
-rw-r--r--challenges/help-confusion-07.ta (renamed from challenges/help-7.ta)0
-rw-r--r--challenges/help-confusion-08.ta (renamed from challenges/help-8.ta)0
-rw-r--r--challenges/help-confusion-09.ta (renamed from challenges/help-9.ta)0
-rw-r--r--challenges/help-confusion-10.ta (renamed from challenges/help-10.ta)0
-rw-r--r--challenges/help-confusion-11.ta (renamed from challenges/help-11.ta)0
-rw-r--r--challenges/help-confusion-12.ta (renamed from challenges/help-12.ta)0
-rw-r--r--challenges/help-confusion-13.ta (renamed from challenges/help-13.ta)0
-rw-r--r--challenges/help-confusion-14.ta (renamed from challenges/help-14.ta)0
-rw-r--r--challenges/help-confusion-15.ta (renamed from challenges/help-15.ta)0
-rw-r--r--challenges/help-confusion-16.ta (renamed from challenges/help-16.ta)0
-rw-r--r--challenges/help-confusion-17.ta (renamed from challenges/help-17.ta)0
-rw-r--r--challenges/help-confusion-18.ta (renamed from challenges/help-18.ta)0
-rw-r--r--challenges/help-confusion-19.ta (renamed from challenges/help-19.ta)0
-rw-r--r--challenges/help-confusion-20.ta (renamed from challenges/help-20.ta)0
-rw-r--r--challenges/help-confusion-21.ta (renamed from challenges/help-21.ta)0
-rw-r--r--challenges/help-confusion-22.ta (renamed from challenges/help-22.ta)0
-rw-r--r--challenges/help-confusion-23.ta (renamed from challenges/help-23.ta)0
-rw-r--r--challenges/help-confusion-24.ta (renamed from challenges/help-24.ta)0
-rw-r--r--challenges/help-confusion-25.ta (renamed from challenges/help-25.ta)0
-rw-r--r--challenges/help-confusion-26.ta (renamed from challenges/help-26.ta)0
-rw-r--r--challenges/help-confusion-27.ta (renamed from challenges/help-27.ta)0
-rw-r--r--challenges/help-confusion-28.ta (renamed from challenges/help-28.ta)0
-rw-r--r--challenges/help-confusion-29.ta (renamed from challenges/help-29.ta)0
-rw-r--r--challenges/help-confusion-30.ta (renamed from challenges/help-30.ta)0
-rw-r--r--challenges/help-confusion-31.ta (renamed from challenges/help-31.ta)0
-rw-r--r--challenges/help-confusion-32.ta (renamed from challenges/help-32.ta)0
-rw-r--r--challenges/help-confusion-33.ta (renamed from challenges/help-33.ta)0
-rw-r--r--challenges/help-confusion-34.ta (renamed from challenges/help-34.ta)0
-rw-r--r--challenges/help-confusion-35.ta (renamed from challenges/help-35.ta)0
-rw-r--r--challenges/help-confusion-36.ta (renamed from challenges/help-36.ta)0
-rw-r--r--challenges/help-confusion-37.ta (renamed from challenges/help-37.ta)0
-rw-r--r--challenges/help-confusion-38.ta (renamed from challenges/help-38.ta)0
-rw-r--r--challenges/help-confusion-39.ta (renamed from challenges/help-39.ta)0
-rw-r--r--challenges/help-confusion-40.ta (renamed from challenges/help-40.ta)0
-rw-r--r--challenges/offsets73
-rw-r--r--plugins/turtle_blocks_extras/turtle_blocks_extras.py333
-rwxr-xr-xturtleconfusion.py (renamed from turtleblocks.py)185
61 files changed, 1440 insertions, 1391 deletions
diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py
index 789c5b8..05ff16a 100644
--- a/TurtleArt/tabasics.py
+++ b/TurtleArt/tabasics.py
@@ -19,7 +19,7 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
-"""
+'''
This file contains the constants that by-in-large determine the
behavior of Turtle Art. Notably, the block palettes are defined
below. If you want to add a new block to Turtle Art, you could
@@ -43,9 +43,13 @@ add_block method in the Palette class.
# Next, you need to define what your block will do:
# def_prim takes 3 arguments: the primitive name, the number of
# arguments -- 0 in this case -- and the function to call -- in this
- # case, the canvas.seth function to set the heading.
- self.tw.lc.def_prim('uturn', 0,
- lambda self: self.tw.canvas.seth(self.tw.canvas.heading + 180))
+ # case, we define the _prim_uturn function to set heading += 180.
+ self.tw.lc.def_prim('uturn', 0, lambda self: self._prim_uturn)
+ def _prim_uturn(self):
+ value = self.tw.turtles.get_active_turtle().get_heading() + 180
+ self.tw.turtles.get_active_turtle().set_heading(value)
+ if self.tw.lc.update_values:
+ self.tw.lc.update_label_value('heading', value)
That's it. When you next run Turtle Art, you will have a 'uturn' block
on the 'mypalette' palette.
@@ -56,7 +60,7 @@ mypaletteoff.svg and mypaletteon.svg, where 'mypalette' is the same
string as the entry you used in instantiating the Palette class. Note
that the icons should be the same size (55x55) as the others. (This is
the default icon size for Sugar toolbars.)
-"""
+'''
from time import time, sleep
from math import sqrt
@@ -78,22 +82,22 @@ def _color_to_num(c):
def _num_type(x):
- """ Is x a number type? """
+ ''' Is x a number type? '''
if isinstance(x, (int, float)):
return True
return False
def _millisecond():
- """ Current time in milliseconds """
+ ''' Current time in milliseconds '''
return time() * 1000
class Palettes():
- """ a class for creating the palettes of blocks """
+ ''' a class for creating the palettes of blocks '''
- def __init__(self, parent):
- self.tw = parent
+ def __init__(self, turtle_window):
+ self.tw = turtle_window
self._turtle_palette()
@@ -107,12 +111,13 @@ class Palettes():
self._blocks_palette()
+ def make_trash_palette(self):
self._trash_palette()
# Palette definitions
def _turtle_palette(self):
- """ The basic Turtle Art turtle palette """
+ ''' The basic Turtle Art turtle palette '''
palette = make_palette('turtle',
colors=["#00FF00", "#00A000"],
@@ -126,10 +131,11 @@ class Palettes():
default=100,
logo_command='forward',
help_string=_('moves turtle forward'))
- self.tw.lc.def_prim('forward', 1,
- lambda self, x:
- primitive_dictionary['move']
- (self.tw.canvas.forward, x))
+ self.tw.lc.def_prim(
+ 'forward',
+ 1,
+ lambda self, x: primitive_dictionary['move'](
+ self.tw.turtles.get_active_turtle().forward, x))
palette.add_block('back',
style='basic-style-1arg',
@@ -141,9 +147,10 @@ class Palettes():
self.tw.lc.def_prim('back', 1,
lambda self, x:
primitive_dictionary['move']
- (self.tw.canvas.forward, x, reverse=True))
+ (self.tw.turtles.get_active_turtle().forward, x,
+ reverse=True))
- primitive_dictionary['clean'] = self.tw.lc.prim_clear
+ primitive_dictionary['clean'] = self._prim_clear
palette.add_block('clean',
style='basic-style-extended-vertical',
label=_('clean'),
@@ -151,8 +158,10 @@ class Palettes():
logo_command='clean',
help_string=_('clears the screen and reset the \
turtle'))
- self.tw.lc.def_prim('clean', 0,
- lambda self: primitive_dictionary['clean']())
+ self.tw.lc.def_prim(
+ 'clean',
+ 0,
+ lambda self: primitive_dictionary['clean']())
primitive_dictionary['right'] = self._prim_right
palette.add_block('left',
@@ -175,8 +184,10 @@ in degrees)'))
logo_command='right',
help_string=_('turns turtle clockwise (angle in \
degrees)'))
- self.tw.lc.def_prim('right', 1,
- lambda self, x: primitive_dictionary['right'](x))
+ self.tw.lc.def_prim(
+ 'right',
+ 1,
+ lambda self, x: primitive_dictionary['right'](x))
primitive_dictionary['arc'] = self._prim_arc
palette.add_block('arc',
@@ -186,10 +197,11 @@ degrees)'))
default=[90, 100],
logo_command='taarc',
help_string=_('moves turtle along an arc'))
- self.tw.lc.def_prim('arc', 2,
- lambda self, x, y:
- primitive_dictionary['arc']
- (self.tw.canvas.arc, x, y))
+ self.tw.lc.def_prim(
+ 'arc',
+ 2,
+ lambda self, x, y: primitive_dictionary['arc'](
+ self.tw.turtles.get_active_turtle().arc, x, y))
define_logo_function('taarc', 'to taarc :a :r\nrepeat round :a \
[right 1 forward (0.0175 * :r)]\nend\n')
@@ -201,10 +213,11 @@ degrees)'))
default=[0, 0],
help_string=_('moves turtle to position xcor, ycor; \
(0, 0) is in the center of the screen.'))
- self.tw.lc.def_prim('setxy2', 2,
- lambda self, x, y:
- primitive_dictionary['move']
- (self.tw.canvas.setxy, x, y))
+ self.tw.lc.def_prim(
+ 'setxy2',
+ 2,
+ lambda self, x, y: primitive_dictionary['move'](
+ self.tw.turtles.get_active_turtle().set_xy, (x, y)))
define_logo_function('tasetxy', 'to tasetxy :x :y\nsetxy :x :y\nend\n')
primitive_dictionary['set'] = self._prim_set
@@ -216,10 +229,11 @@ degrees)'))
logo_command='seth',
help_string=_('sets the heading of the turtle (0 is \
towards the top of the screen.)'))
- self.tw.lc.def_prim('seth', 1,
- lambda self, x:
- primitive_dictionary['set']
- ('heading', self.tw.canvas.seth, x))
+ self.tw.lc.def_prim(
+ 'seth',
+ 1,
+ lambda self, x: primitive_dictionary['set'](
+ 'heading', self.tw.turtles.get_active_turtle().set_heading, x))
palette.add_block('xcor',
style='box-style',
@@ -230,7 +244,10 @@ the turtle (can be used in place of a number block)'),
prim_name='xcor',
logo_command='xcor')
self.tw.lc.def_prim(
- 'xcor', 0, lambda self: self.tw.canvas.xcor / self.tw.coord_scale)
+ 'xcor',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().get_xy()[0] /
+ self.tw.coord_scale)
palette.add_block('ycor',
style='box-style',
@@ -241,7 +258,10 @@ the turtle (can be used in place of a number block)'),
prim_name='ycor',
logo_command='ycor')
self.tw.lc.def_prim(
- 'ycor', 0, lambda self: self.tw.canvas.ycor / self.tw.coord_scale)
+ 'ycor',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().get_xy()[1] /
+ self.tw.coord_scale)
palette.add_block('heading',
style='box-style',
@@ -252,7 +272,9 @@ turtle (can be used in place of a number block)'),
prim_name='heading',
logo_command='heading')
self.tw.lc.def_prim(
- 'heading', 0, lambda self: self.tw.canvas.heading)
+ 'heading',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().get_heading())
palette.add_block('turtle-label',
hidden=True,
@@ -269,15 +291,17 @@ turtle (can be used in place of a number block)'),
logo_command='tasetxypenup',
help_string=_('moves turtle to position xcor, ycor; \
(0, 0) is in the center of the screen.'))
- self.tw.lc.def_prim('setxy', 2,
- lambda self, x, y:
- primitive_dictionary['move']
- (self.tw.canvas.setxy, x, y, pendown=False))
+ self.tw.lc.def_prim(
+ 'setxy',
+ 2,
+ lambda self, x, y: primitive_dictionary['move'](
+ self.tw.turtles.get_active_turtle().set_xy, (x, y),
+ pendown=False))
define_logo_function('tasetxypenup', 'to tasetxypenup :x :y\npenup\n\
setxy :x :y\npendown\nend\n')
def _pen_palette(self):
- """ The basic Turtle Art pen palette """
+ ''' The basic Turtle Art pen palette '''
palette = make_palette('pen',
colors=["#00FFFF", "#00A0A0"],
@@ -292,8 +316,10 @@ setxy :x :y\npendown\nend\n')
logo_command='tasetbackground',
help_string=_('fills the background with (color, \
shade)'))
- self.tw.lc.def_prim('fillscreen', 2,
- lambda self, x, y: self.tw.canvas.fillscreen(x, y))
+ self.tw.lc.def_prim(
+ 'fillscreen',
+ 2,
+ lambda self, x, y: self.tw.canvas.fillscreen(x, y))
palette.add_block('fillscreen2',
style='basic-style-3arg',
@@ -304,9 +330,10 @@ shade)'))
logo_command='tasetbackground',
help_string=_('fills the background with (color, \
shade)'))
- self.tw.lc.def_prim('fillscreen2', 3,
- lambda self, x, y, z:
- self.tw.canvas.fillscreen_with_gray(x, y, z))
+ self.tw.lc.def_prim(
+ 'fillscreen2',
+ 3,
+ lambda self, x, y, z: self.tw.canvas.fillscreen_with_gray(x, y, z))
define_logo_function('tasetbackground', 'to tasetbackground :color \
:shade\ntasetshade :shade\nsetbackground :color\nend\n')
@@ -319,10 +346,11 @@ shade)'))
logo_command='tasetpencolor',
help_string=_('sets color of the line drawn by the \
turtle'))
- self.tw.lc.def_prim('setcolor', 1,
- lambda self, x:
- primitive_dictionary['set']
- ('color', self.tw.canvas.setcolor, x))
+ self.tw.lc.def_prim(
+ 'setcolor',
+ 1,
+ lambda self, x: primitive_dictionary['set'](
+ 'color', self.tw.turtles.get_active_turtle().set_color, x))
palette.add_block('setshade',
style='basic-style-1arg',
@@ -332,10 +360,11 @@ turtle'))
logo_command='tasetshade',
help_string=_('sets shade of the line drawn by the \
turtle'))
- self.tw.lc.def_prim('setshade', 1,
- lambda self, x:
- primitive_dictionary['set']
- ('shade', self.tw.canvas.setshade, x))
+ self.tw.lc.def_prim(
+ 'setshade',
+ 1,
+ lambda self, x: primitive_dictionary['set'](
+ 'shade', self.tw.turtles.get_active_turtle().set_shade, x))
palette.add_block('setgray',
style='basic-style-1arg',
@@ -344,10 +373,11 @@ turtle'))
default=100,
help_string=_('sets gray level of the line drawn by \
the turtle'))
- self.tw.lc.def_prim('setgray', 1,
- lambda self, x:
- primitive_dictionary['set']
- ('gray', self.tw.canvas.setgray, x))
+ self.tw.lc.def_prim(
+ 'setgray',
+ 1,
+ lambda self, x: primitive_dictionary['set'](
+ 'gray', self.tw.turtles.get_active_turtle().set_gray, x))
palette.add_block('color',
style='box-style',
@@ -357,7 +387,10 @@ in place of a number block)'),
value_block=True,
prim_name='color',
logo_command='pencolor')
- self.tw.lc.def_prim('color', 0, lambda self: self.tw.canvas.color)
+ self.tw.lc.def_prim(
+ 'color',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().get_color())
palette.add_block('shade',
style='box-style',
@@ -366,7 +399,10 @@ in place of a number block)'),
value_block=True,
prim_name='shade',
logo_command=':shade')
- self.tw.lc.def_prim('shade', 0, lambda self: self.tw.canvas.shade)
+ self.tw.lc.def_prim(
+ 'shade',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().get_shade())
palette.add_block('gray',
style='box-style',
@@ -375,7 +411,8 @@ in place of a number block)'),
used in place of a number block)'),
value_block=True,
prim_name='gray')
- self.tw.lc.def_prim('gray', 0, lambda self: self.tw.canvas.gray)
+ self.tw.lc.def_prim('gray', 0, lambda self:
+ self.tw.turtles.get_active_turtle().get_gray())
palette.add_block('penup',
style='basic-style-extended-vertical',
@@ -383,8 +420,11 @@ used in place of a number block)'),
prim_name='penup',
logo_command='penup',
help_string=_('Turtle will not draw when moved.'))
- self.tw.lc.def_prim('penup', 0,
- lambda self: self.tw.canvas.setpen(False))
+ self.tw.lc.def_prim(
+ 'penup',
+ 0,
+ lambda self:
+ self.tw.turtles.get_active_turtle().set_pen_state(False))
palette.add_block('pendown',
style='basic-style-extended-vertical',
@@ -392,8 +432,21 @@ used in place of a number block)'),
prim_name='pendown',
logo_command='pendown',
help_string=_('Turtle will draw when moved.'))
- self.tw.lc.def_prim('pendown', 0,
- lambda self: self.tw.canvas.setpen(True))
+ self.tw.lc.def_prim(
+ 'pendown',
+ 0,
+ lambda self:
+ self.tw.turtles.get_active_turtle().set_pen_state(True))
+
+ palette.add_block('penstate',
+ style='boolean-block-style',
+ label=_('pen down?'),
+ prim_name='penstate',
+ help_string=_('returns True if pen is down'))
+ self.tw.lc.def_prim(
+ 'penstate',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().get_pen_state())
palette.add_block('setpensize',
style='basic-style-1arg',
@@ -403,12 +456,12 @@ used in place of a number block)'),
logo_command='setpensize',
help_string=_('sets size of the line drawn by the \
turtle'))
- self.tw.lc.def_prim('setpensize', 1,
- lambda self, x:
- primitive_dictionary['set']
- ('pensize', self.tw.canvas.setpensize, x))
- define_logo_function('tasetpensize', 'to tasetpensize :a\nsetpensize \
-round :a\nend\n')
+ self.tw.lc.def_prim(
+ 'setpensize', 1,
+ lambda self, x: primitive_dictionary['set']
+ ('pensize', self.tw.turtles.get_active_turtle().set_pen_size, x))
+ define_logo_function('tasetpensize',
+ 'to tasetpensize :a\nsetpensize round :a\nend\n')
palette.add_block('startfill',
style='basic-style-extended-vertical',
@@ -416,8 +469,10 @@ round :a\nend\n')
prim_name='startfill',
help_string=_('starts filled polygon (used with end \
fill block)'))
- self.tw.lc.def_prim('startfill', 0,
- lambda self: self.tw.canvas.start_fill())
+ self.tw.lc.def_prim(
+ 'startfill',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().start_fill())
palette.add_block('stopfill',
style='basic-style-extended-vertical',
@@ -425,8 +480,10 @@ fill block)'))
prim_name='stopfill',
help_string=_('completes filled polygon (used with \
start fill block)'))
- self.tw.lc.def_prim('stopfill', 0,
- lambda self: self.tw.canvas.stop_fill())
+ self.tw.lc.def_prim(
+ 'stopfill',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().stop_fill())
palette.add_block('pensize',
style='box-style',
@@ -436,12 +493,15 @@ in place of a number block)'),
value_block=True,
prim_name='pensize',
logo_command='pensize')
- self.tw.lc.def_prim('pensize', 0, lambda self: self.tw.canvas.pensize)
+ self.tw.lc.def_prim(
+ 'pensize',
+ 0,
+ lambda self: self.tw.turtles.get_active_turtle().get_pen_size())
define_logo_function('tapensize', 'to tapensize\noutput first round \
pensize\nend\n')
def _color_palette(self):
- """ The basic Turtle Art color palette """
+ ''' The basic Turtle Art color palette '''
palette = make_palette('colors',
colors=["#00FFFF", "#00A0A0"],
@@ -460,29 +520,6 @@ pensize\nend\n')
self._make_constant(palette, 'white', _('white'), CONSTANTS['white'])
self._make_constant(palette, 'black', _('black'), CONSTANTS['black'])
- # deprecated blocks
- palette.add_block('settextcolor',
- hidden=True,
- style='basic-style-1arg',
- label=_('set text color'),
- prim_name='settextcolor',
- default=0,
- help_string=_('sets color of text drawn by the \
-turtle'))
- self.tw.lc.def_prim('settextcolor', 1,
- lambda self, x: self.tw.canvas.settextcolor(x))
-
- palette.add_block('settextsize',
- hidden=True,
- style='basic-style-1arg',
- label=_('set text size'),
- prim_name='settextsize',
- default=0,
- help_string=_('sets size of text drawn by the \
-turtle'))
- self.tw.lc.def_prim('settextsize', 1,
- lambda self, x: self.tw.canvas.settextsize(x))
-
# In order to map Turtle Art colors to the standard UCB Logo palette,
# we need to define a somewhat complex set of functions.
define_logo_function('tacolor', '\
@@ -557,7 +594,7 @@ make "shade 50 \n\
tasetshade :shade \n')
def _numbers_palette(self):
- """ The basic Turtle Art numbers palette """
+ ''' The basic Turtle Art numbers palette '''
palette = make_palette('numbers',
colors=["#FF00FF", "#A000A0"],
@@ -740,7 +777,7 @@ operators'))
'or', 2, lambda self, x, y: primitive_dictionary['or'](x, y))
def _flow_palette(self):
- """ The basic Turtle Art flow palette """
+ ''' The basic Turtle Art flow palette '''
palette = make_palette('flow',
colors=["#FFC000", "#A08000"],
@@ -840,7 +877,7 @@ boolean operators from Numbers palette'))
lambda self: primitive_dictionary['stopstack']())
def _blocks_palette(self):
- """ The basic Turtle Art blocks palette """
+ ''' The basic Turtle Art blocks palette '''
palette = make_palette('blocks',
colors=["#FFFF00", "#A0A000"],
@@ -1001,7 +1038,7 @@ variable'))
self.tw.lc.def_prim('stack2', 0, primitive_dictionary['stack2'], True)
def _trash_palette(self):
- """ The basic Turtle Art turtle palette """
+ ''' The basic Turtle Art turtle palette '''
palette = make_palette('trash',
colors=["#FFFF00", "#A0A000"],
@@ -1024,22 +1061,32 @@ variable'))
# Block primitives
+ def _prim_clear(self):
+ self.tw.lc.prim_clear()
+ self.tw.turtles.reset_turtles()
+
def _prim_and(self, x, y):
- """ Logical and """
+ ''' Logical and '''
return x & y
def _prim_arc(self, cmd, value1, value2):
- """ Turtle draws an arc of degree, radius """
+ ''' Turtle draws an arc of degree, radius '''
cmd(float(value1), float(value2))
if self.tw.lc.update_values:
self.tw.lc.update_label_value(
- 'xcor', self.tw.canvas.xcor / self.tw.coord_scale)
+ 'xcor',
+ self.tw.turtles.get_active_turtle().get_xy()[0] /
+ self.tw.coord_scale)
self.tw.lc.update_label_value(
- 'ycor', self.tw.canvas.ycor / self.tw.coord_scale)
- self.tw.lc.update_label_value('heading', self.tw.canvas.heading)
+ 'ycor',
+ self.tw.turtles.get_active_turtle().get_xy()[1] /
+ self.tw.coord_scale)
+ self.tw.lc.update_label_value(
+ 'heading',
+ self.tw.turtles.get_active_turtle().get_heading)
def _prim_box(self, x):
- """ Retrieve value from named box """
+ ''' Retrieve value from named box '''
if isinstance(convert(x, float, False), float):
if int(float(x)) == x:
x = int(x)
@@ -1049,7 +1096,7 @@ variable'))
raise logoerror("#emptybox")
def _prim_forever(self, blklist):
- """ Do list forever """
+ ''' Do list forever '''
while True:
self.tw.lc.icall(self.tw.lc.evline, blklist[:])
yield True
@@ -1059,7 +1106,7 @@ variable'))
yield True
def _prim_if(self, boolean, blklist):
- """ If bool, do list """
+ ''' If bool, do list '''
if boolean:
self.tw.lc.icall(self.tw.lc.evline, blklist[:])
yield True
@@ -1067,7 +1114,7 @@ variable'))
yield True
def _prim_ifelse(self, boolean, list1, list2):
- """ If bool, do list1, else do list2 """
+ ''' If bool, do list1, else do list2 '''
if boolean:
self.tw.lc.ijmp(self.tw.lc.evline, list1[:])
yield True
@@ -1077,7 +1124,12 @@ variable'))
def _prim_move(self, cmd, value1, value2=None, pendown=True,
reverse=False):
- """ Turtle moves by method specified in value1 """
+ ''' Turtle moves by method specified in value1 '''
+ pos = None
+ if isinstance(value1, (tuple, list)):
+ pos = value1
+ value1 = pos[0]
+ value2 = pos[1]
if not _num_type(value1):
raise logoerror("#notanumber")
if value2 is None:
@@ -1088,19 +1140,26 @@ variable'))
else:
if not _num_type(value2):
raise logoerror("#notanumber")
- cmd(float(value1), float(value2), pendown=pendown)
+ if pos is not None:
+ cmd((float(value1), float(value2)), pendown=pendown)
+ else:
+ cmd(float(value1), float(value2), pendown=pendown)
if self.tw.lc.update_values:
self.tw.lc.update_label_value(
- 'xcor', self.tw.canvas.xcor / self.tw.coord_scale)
+ 'xcor',
+ self.tw.turtles.get_active_turtle().get_xy()[0] /
+ self.tw.coord_scale)
self.tw.lc.update_label_value(
- 'ycor', self.tw.canvas.ycor / self.tw.coord_scale)
+ 'ycor',
+ self.tw.turtles.get_active_turtle().get_xy()[1] /
+ self.tw.coord_scale)
def _prim_or(self, x, y):
- """ Logical or """
+ ''' Logical or '''
return x | y
def _prim_repeat(self, num, blklist):
- """ Repeat list num times. """
+ ''' Repeat list num times. '''
if not _num_type(num):
raise logoerror("#notanumber")
num = self.tw.lc.int(num)
@@ -1113,25 +1172,27 @@ variable'))
yield True
def _prim_right(self, value, reverse=False):
- """ Turtle rotates clockwise """
+ ''' Turtle rotates clockwise '''
if not _num_type(value):
raise logoerror("#notanumber")
if reverse:
- self.tw.canvas.right(float(-value))
+ self.tw.turtles.get_active_turtle().right(float(-value))
else:
- self.tw.canvas.right(float(value))
+ self.tw.turtles.get_active_turtle().right(float(value))
if self.tw.lc.update_values:
- self.tw.lc.update_label_value('heading', self.tw.canvas.heading)
+ self.tw.lc.update_label_value(
+ 'heading',
+ self.tw.turtles.get_active_turtle().get_heading)
def _prim_set(self, name, cmd, value=None):
- """ Set a value and update the associated value blocks """
+ ''' Set a value and update the associated value blocks '''
if value is not None:
cmd(value)
if self.tw.lc.update_values:
self.tw.lc.update_label_value(name, value)
def _prim_setbox(self, name, x, val):
- """ Define value of named box """
+ ''' Define value of named box '''
if x is not None:
if isinstance(convert(x, float, False), float):
if int(float(x)) == x:
@@ -1145,7 +1206,7 @@ variable'))
self.tw.lc.update_label_value(name, val)
def _prim_stack(self, x):
- """ Process a named stack """
+ ''' Process a named stack '''
if isinstance(convert(x, float, False), float):
if int(float(x)) == x:
x = int(x)
@@ -1160,7 +1221,7 @@ variable'))
yield True
def _prim_stack1(self):
- """ Process Stack 1 """
+ ''' Process Stack 1 '''
if self.tw.lc.stacks['stack1'] is None:
raise logoerror("#nostack")
self.tw.lc.icall(self.tw.lc.evline,
@@ -1171,7 +1232,7 @@ variable'))
yield True
def _prim_stack2(self):
- """ Process Stack 2 """
+ ''' Process Stack 2 '''
if self.tw.lc.stacks['stack2'] is None:
raise logoerror("#nostack")
self.tw.lc.icall(self.tw.lc.evline, self.tw.lc.stacks['stack2'][:])
@@ -1181,29 +1242,29 @@ variable'))
yield True
def _prim_start(self):
- """ Start block: recenter """
+ ''' Start block: recenter '''
if self.tw.running_sugar:
self.tw.activity.recenter()
def _prim_stopstack(self):
- """ Stop execution of a stack """
+ ''' Stop execution of a stack '''
self.tw.lc.procstop = True
def _prim_wait(self, wait_time):
- """ Show the turtle while we wait """
- self.tw.active_turtle.show()
+ ''' Show the turtle while we wait '''
+ self.tw.turtles.get_active_turtle().show()
endtime = _millisecond() + wait_time * 1000.
while _millisecond() < endtime:
sleep(wait_time / 10.)
yield True
- self.tw.active_turtle.hide()
+ self.tw.turtles.get_active_turtle().hide()
self.tw.lc.ireturn()
yield True
# Math primitivies
def _prim_careful_divide(self, x, y):
- """ Raise error on divide by zero """
+ ''' Raise error on divide by zero '''
if isinstance(x, list) and _num_type(y):
z = []
for i in range(len(x)):
@@ -1227,7 +1288,7 @@ variable'))
raise logoerror("#notanumber")
def _prim_equal(self, x, y):
- """ Numeric and logical equal """
+ ''' Numeric and logical equal '''
if isinstance(x, list) and isinstance(y, list):
for i in range(len(x)):
if x[i] != y[i]:
@@ -1249,7 +1310,7 @@ variable'))
raise logoerror("#syntaxerror")
def _prim_less(self, x, y):
- """ Compare numbers and strings """
+ ''' Compare numbers and strings '''
if isinstance(x, list) or isinstance(y, list):
raise logoerror("#syntaxerror")
try:
@@ -1268,11 +1329,11 @@ variable'))
raise logoerror("#notanumber")
def _prim_more(self, x, y):
- """ Compare numbers and strings """
+ ''' Compare numbers and strings '''
return self._prim_less(y, x)
def _prim_plus(self, x, y):
- """ Add numbers, concat strings """
+ ''' Add numbers, concat strings '''
if x in COLORDICT:
x = _color_to_num(x)
if y in COLORDICT:
@@ -1296,7 +1357,7 @@ variable'))
return(xx + yy)
def _prim_minus(self, x, y):
- """ Numerical subtraction """
+ ''' Numerical subtraction '''
if _num_type(x) and _num_type(y):
return(x - y)
elif isinstance(x, list) and isinstance(y, list):
@@ -1310,7 +1371,7 @@ variable'))
raise logoerror("#notanumber")
def _prim_product(self, x, y):
- """ Numerical multiplication """
+ ''' Numerical multiplication '''
if _num_type(x) and _num_type(y):
return(x * y)
elif isinstance(x, list) and _num_type(y):
@@ -1329,7 +1390,7 @@ variable'))
raise logoerror("#notanumber")
def _prim_mod(self, x, y):
- """ Numerical mod """
+ ''' Numerical mod '''
if _num_type(x) and _num_type(y):
return(x % y)
try:
@@ -1340,7 +1401,7 @@ variable'))
raise logoerror("#syntaxerror")
def _prim_sqrt(self, x):
- """ Square root """
+ ''' Square root '''
if _num_type(x):
if x < 0:
raise logoerror("#negroot")
@@ -1353,7 +1414,7 @@ variable'))
raise logoerror("#notanumber")
def _prim_random(self, x, y):
- """ Random integer """
+ ''' Random integer '''
if _num_type(x) and _num_type(y):
return(int(round(uniform(x, y), 0)))
xx, xflag = chr_to_ord(x)
@@ -1370,13 +1431,13 @@ variable'))
raise logoerror("#notanumber")
def _prim_identity(self, x):
- """ Identity function """
+ ''' Identity function '''
return(x)
# Utilities
def _string_to_num(self, x):
- """ Try to comvert a string to a number """
+ ''' Try to comvert a string to a number '''
if isinstance(x, (int, float)):
return(x)
try:
@@ -1398,7 +1459,7 @@ variable'))
raise logoerror("#syntaxerror")
def _make_constant(self, palette, block_name, label, constant):
- """ Factory for constant blocks """
+ ''' Factory for constant blocks '''
if constant in COLORDICT:
if COLORDICT[constant][0] is not None:
value = str(COLORDICT[constant][0])
diff --git a/TurtleArt/tablock.py b/TurtleArt/tablock.py
index 2658624..8d8ed4a 100644
--- a/TurtleArt/tablock.py
+++ b/TurtleArt/tablock.py
@@ -125,7 +125,31 @@ class Blocks:
class Block:
- """ A class for the individual blocks """
+ """ A class for the individual blocks
+
+ Attributes:
+ docks -- a list of docks, i.e. connection points where other blocks
+ could be attached. Each dock is a list of the form
+ [type_of_dock, flow_is_in, x, y, parenthesis]
+ with the last element being optional.
+ type_of_dock may be one of the following strings:
+ flow -- connect to the previous or next block ('slot' or 'tab')
+ bool, media, number, string -- argument slot ('innie') or
+ return value ('outie') of the given kind
+ unavailable -- nothing can be attached here ('cap' or 'tail')
+ flow_is_in is True if the flow is into the block, or False for out.
+ x and y are coodinates for positioning the block on the dock.
+ parenthesis is only used with arguments and ensures a known order
+ of arguments for arithmetic and logical operations.
+ connections -- a list of blocks that are attached to this one (or that
+ this one is attached to). This list corresponds to the docks list
+ as it uses the same indices. Slots where nothing is attached are
+ None on this list.
+ primitive -- a callable that is called when the block is executed
+ type -- type of the block:
+ block -- block that is part of the user's program
+ proto -- block on a palette, used to generate other blocks
+ trash -- block in the trash """
def __init__(self, block_list, sprite_list, name, x, y, type='block',
values=[], scale=BLOCK_SCALE[0],
diff --git a/TurtleArt/tacanvas.py b/TurtleArt/tacanvas.py
index 5eaa4a8..2af41cd 100644
--- a/TurtleArt/tacanvas.py
+++ b/TurtleArt/tacanvas.py
@@ -21,15 +21,13 @@
#THE SOFTWARE.
import gtk
-import gobject
-from math import sin, cos, pi
+from math import pi
import os
import pango
import cairo
import pangocairo
-from tautils import (image_to_base64, get_path, data_to_string, round_int,
- debug_output)
+from tautils import get_path
from taconstants import COLORDICT
@@ -101,38 +99,31 @@ COLOR_TABLE = (
class TurtleGraphics:
''' A class for the Turtle graphics canvas '''
- def __init__(self, tw, width, height):
+ def __init__(self, turtle_window, width, height):
''' Create a sprite to hold the canvas. '''
- self.tw = tw
+ self.turtle_window = turtle_window
self.width = width
self.height = height
+ self.textsize = 48
+ self._fgrgb = [255, 0, 0]
+ self._bgrgb = [255, 248, 222]
+ self._shade = 0
+ self._color = 0
+ self._gray = 100
+ self.cr_svg = None # Surface used for saving to SVG
# Build a cairo.Context from a cairo.XlibSurface
- self.canvas = cairo.Context(self.tw.turtle_canvas)
+ self.canvas = cairo.Context(self.turtle_window.turtle_canvas)
cr = gtk.gdk.CairoContext(self.canvas)
cr.set_line_cap(1) # Set the line cap to be round
- self.cr_svg = None # Surface used for saving to SVG
- self.cx = 0
- self.cy = 0
- self.fgrgb = [255, 0, 0]
- self.bgrgb = [255, 248, 222]
- self.textsize = 48 # deprecated
- self.shade = 0
- self.pendown = False
- self.xcor = 0
- self.ycor = 0
- self.heading = 0
- self.pensize = 5
- self.color = 0
- self.gray = 100
- self.fill = False
- self.poly_points = []
+
+ self.set_pen_size(5)
def setup_svg_surface(self):
''' Set up a surface for saving to SVG '''
- if self.tw.running_sugar:
+ if self.turtle_window.running_sugar:
svg_surface = cairo.SVGSurface(
- os.path.join(get_path(self.tw.activity, 'instance'),
+ os.path.join(get_path(self.turtle_window.activity, 'instance'),
'output.svg'), self.width, self.height)
else:
svg_surface = cairo.SVGSurface(
@@ -141,27 +132,6 @@ class TurtleGraphics:
self.cr_svg = cairo.Context(svg_surface)
self.cr_svg.set_line_cap(1) # Set the line cap to be round
- def start_fill(self):
- ''' Start accumulating points of a polygon to fill. '''
- self.fill = True
- self.poly_points = []
-
- def stop_fill(self):
- ''' Fill the polygon. '''
- self.fill = False
- if len(self.poly_points) == 0:
- return
- self.fill_polygon(self.poly_points)
- if self.tw.sharing():
- shared_poly_points = []
- for p in self.poly_points:
- shared_poly_points.append((self.screen_to_turtle_coordinates
- (p[0], p[1])))
- event = 'F|%s' % (data_to_string([self._get_my_nick(),
- shared_poly_points]))
- self.tw.send_event(event)
- self.poly_points = []
-
def fill_polygon(self, poly_points):
''' Draw the polygon... '''
def _fill_polygon(cr, poly_points):
@@ -188,10 +158,10 @@ class TurtleGraphics:
def _clearscreen(cr):
cr.move_to(0, 0)
- self.bgrgb = [255, 248, 222]
- cr.set_source_rgb(self.bgrgb[0] / 255.,
- self.bgrgb[1] / 255.,
- self.bgrgb[2] / 255.)
+ self._bgrgb = [255, 248, 222]
+ cr.set_source_rgb(self._bgrgb[0] / 255.,
+ self._bgrgb[1] / 255.,
+ self._bgrgb[2] / 255.)
cr.rectangle(0, 0, self.width * 2, self.height * 2)
cr.fill()
@@ -200,359 +170,101 @@ class TurtleGraphics:
if self.cr_svg is not None:
_clearscreen(self.cr_svg)
- self.setpensize(5, share)
- self.setgray(100, share)
- self.setcolor(0, share)
- self.setshade(50, share)
- self.fill = False
- self.poly_points = []
- for turtle_key in iter(self.tw.turtles.dict):
- # Don't reset remote turtles
- if not self.tw.remote_turtle(turtle_key):
- self.set_turtle(turtle_key)
- self.tw.active_turtle.set_color(0)
- self.tw.active_turtle.set_shade(50)
- self.tw.active_turtle.set_gray(100)
- self.tw.active_turtle.set_pen_size(5)
- self.tw.active_turtle.reset_shapes()
- self.seth(0.0, share)
- self.setpen(False, share)
- self.setxy(0.0, 0.0, share)
- self.setpen(True, share)
- self.tw.active_turtle.hide()
- self.set_turtle(self.tw.default_turtle_name)
-
- def forward(self, n, share=True):
- ''' Move the turtle forward.'''
- nn = n * self.tw.coord_scale
- self.canvas.set_source_rgb(self.fgrgb[0] / 255., self.fgrgb[1] / 255.,
- self.fgrgb[2] / 255.)
- if self.cr_svg is not None:
- debug_output('in forward', True)
- self.cr_svg.set_source_rgb(self.fgrgb[0] / 255.,
- self.fgrgb[1] / 255.,
- self.fgrgb[2] / 255.)
- oldx, oldy = self.xcor, self.ycor
- try:
- self.xcor += nn * sin(self.heading * DEGTOR)
- self.ycor += nn * cos(self.heading * DEGTOR)
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- if self.pendown:
- self.draw_line(oldx, oldy, self.xcor, self.ycor)
-
- self.move_turtle()
-
- if self.tw.sharing() and share:
- event = 'f|%s' % (data_to_string([self._get_my_nick(), int(n)]))
- self.tw.send_event(event)
+ def rarc(self, x, y, r, a, heading):
+ ''' draw a clockwise arc '''
+ def _rarc(cr, x, y, r, a, h):
+ cr.arc(x, y, r, (h - 180) * DEGTOR, (h - 180 + a) * DEGTOR)
+ cr.stroke()
+
+ _rarc(self.canvas, x, y, r, a, heading)
self.inval()
- def seth(self, n, share=True):
- ''' Set the turtle heading. '''
- try:
- self.heading = n
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- self.heading %= 360
- self.turn_turtle()
- if self.tw.sharing() and share:
- event = 'r|%s' % (data_to_string([self._get_my_nick(),
- round_int(self.heading)]))
- self.tw.send_event(event)
-
- def right(self, n, share=True):
- ''' Rotate turtle clockwise '''
- try:
- self.heading += n
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- self.heading %= 360
- self.turn_turtle()
- if self.tw.sharing() and share:
- event = 'r|%s' % (data_to_string([self._get_my_nick(),
- round_int(self.heading)]))
- self.tw.send_event(event)
-
- def arc(self, a, r, share=True):
- ''' Draw an arc '''
- self.canvas.set_source_rgb(self.fgrgb[0] / 255., self.fgrgb[1] / 255.,
- self.fgrgb[2] / 255.)
if self.cr_svg is not None:
- self.cr_svg.set_source_rgb(self.fgrgb[0] / 255.,
- self.fgrgb[1] / 255.,
- self.fgrgb[2] / 255.)
- try:
- if a < 0:
- self.larc(-a, r)
- else:
- self.rarc(a, r)
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- self.move_turtle()
- if self.tw.sharing() and share:
- event = 'a|%s' % (data_to_string([self._get_my_nick(),
- [round_int(a), round_int(r)]]))
- self.tw.send_event(event)
-
- def rarc(self, a, r):
- ''' draw a clockwise arc '''
- r *= self.tw.coord_scale
- if r < 0:
- r = -r
- a = -a
- oldx, oldy = self.xcor, self.ycor
- cx = self.xcor + r * cos(self.heading * DEGTOR)
- cy = self.ycor - r * sin(self.heading * DEGTOR)
- if self.pendown:
- x, y = self.turtle_to_screen_coordinates(cx, cy)
-
- def _rarc(cr, x, y, r, a, h):
- cr.arc(x, y, r, (h - 180) * DEGTOR, (h - 180 + a) * DEGTOR)
- cr.stroke()
-
- _rarc(self.canvas, x, y, r, a, self.heading)
- self.inval()
- if self.cr_svg is not None:
- _rarc(self.cr_svg, x, y, r, a, self.heading)
-
- if self.fill:
- if self.poly_points == []:
- self.poly_points.append(('move', x, y))
- self.poly_points.append(('rarc', x, y, r,
- (self.heading - 180) * DEGTOR,
- (self.heading - 180 + a) * DEGTOR))
-
- self.right(a, False)
- self.xcor = cx - r * cos(self.heading * DEGTOR)
- self.ycor = cy + r * sin(self.heading * DEGTOR)
-
- def larc(self, a, r):
+ _rarc(self.cr_svg, x, y, r, a, heading)
+
+ def larc(self, x, y, r, a, heading):
''' draw a counter-clockwise arc '''
- r *= self.tw.coord_scale
- if r < 0:
- r = -r
- a = -a
- oldx, oldy = self.xcor, self.ycor
- cx = self.xcor - r * cos(self.heading * DEGTOR)
- cy = self.ycor + r * sin(self.heading * DEGTOR)
- if self.pendown:
- x, y = self.turtle_to_screen_coordinates(cx, cy)
-
- def _larc(cr, x, y, r, a, h):
- cr.arc_negative(x, y, r, h * DEGTOR, (h - a) * DEGTOR)
- cr.stroke()
-
- _larc(self.canvas, x, y, r, a, self.heading)
- self.inval()
- if self.cr_svg is not None:
- _larc(self.cr_svg, x, y, r, a, self.heading)
-
- if self.fill:
- if self.poly_points == []:
- self.poly_points.append(('move', x, y))
- self.poly_points.append(('larc', x, y, r,
- (self.heading) * DEGTOR,
- (self.heading - a) * DEGTOR))
-
- self.right(-a, False)
- self.xcor = cx + r * cos(self.heading * DEGTOR)
- self.ycor = cy - r * sin(self.heading * DEGTOR)
-
- def setxy(self, x, y, share=True, pendown=True):
- ''' Move turtle to position x,y '''
- oldx, oldy = self.xcor, self.ycor
- x *= self.tw.coord_scale
- y *= self.tw.coord_scale
- try:
- self.xcor, self.ycor = x, y
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
-
- if self.pendown and pendown:
- self.canvas.set_source_rgb(self.fgrgb[0] / 255.,
- self.fgrgb[1] / 255.,
- self.fgrgb[2] / 255.)
- if self.cr_svg is not None:
- self.cr_svg.set_source_rgb(self.fgrgb[0] / 255.,
- self.fgrgb[1] / 255.,
- self.fgrgb[2] / 255.)
- self.draw_line(oldx, oldy, self.xcor, self.ycor)
- self.inval()
- self.move_turtle()
-
- if self.tw.sharing() and share:
- event = 'x|%s' % (data_to_string([self._get_my_nick(),
- [round_int(x), round_int(y)]]))
- self.tw.send_event(event)
-
- def setpensize(self, ps, share=True):
- ''' Set the pen size '''
- try:
- if ps < 0:
- ps = 0
- self.pensize = ps
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- self.tw.active_turtle.set_pen_size(ps)
- self.canvas.set_line_width(ps)
- if self.cr_svg is not None:
- self.cr_svg.set_line_width(ps)
- if self.tw.sharing() and share:
- event = 'w|%s' % (data_to_string([self._get_my_nick(),
- round_int(ps)]))
- self.tw.send_event(event)
+ def _larc(cr, x, y, r, a, h):
+ cr.arc_negative(x, y, r, h * DEGTOR, (h - a) * DEGTOR)
+ cr.stroke()
- def setcolor(self, c, share=True):
- ''' Set the pen color '''
+ _larc(self.canvas, x, y, r, a, heading)
+ self.inval()
+ if self.cr_svg is not None:
+ _larc(self.cr_svg, x, y, r, a, heading)
- # Special case for color blocks
- if c in COLORDICT:
- self.setshade(COLORDICT[c][1], share)
- self.setgray(COLORDICT[c][2], share)
- if COLORDICT[c][0] is not None:
- self.setcolor(COLORDICT[c][0], share)
- c = COLORDICT[c][0]
- else:
- c = self.color
-
- try:
- self.color = c
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- self.tw.active_turtle.set_color(c)
- self.set_fgcolor()
- if self.tw.sharing() and share:
- event = 'c|%s' % (data_to_string([self._get_my_nick(),
- round_int(c)]))
- self.tw.send_event(event)
-
- def setgray(self, g, share=True):
- ''' Set the gray level '''
- try:
- self.gray = g
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- if self.gray < 0:
- self.gray = 0
- if self.gray > 100:
- self.gray = 100
- self.set_fgcolor()
- self.tw.active_turtle.set_gray(self.gray)
- if self.tw.sharing() and share:
- event = 'g|%s' % (data_to_string([self._get_my_nick(),
- round_int(self.gray)]))
- self.tw.send_event(event)
-
- def set_textcolor(self):
- ''' Deprecated: Set the text color to foreground color. '''
- return
-
- def settextcolor(self, c): # deprecated
- ''' Set the text color '''
- return
-
- def settextsize(self, c): # deprecated
- ''' Set the text size '''
- try:
- self.tw.textsize = c
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
-
- def setshade(self, s, share=True):
- ''' Set the color shade '''
- try:
- self.shade = s
- except (TypeError, ValueError):
- debug_output('bad value sent to %s' % (__name__),
- self.tw.running_sugar)
- return
- self.tw.active_turtle.set_shade(s)
- self.set_fgcolor()
- if self.tw.sharing() and share:
- event = 's|%s' % (data_to_string([self._get_my_nick(),
- round_int(s)]))
- self.tw.send_event(event)
+ def set_pen_size(self, pen_size):
+ ''' Set the pen size '''
+ self.canvas.set_line_width(pen_size)
+ if self.cr_svg is not None:
+ self.cr_svg.set_line_width(pen_size)
def fillscreen(self, c, s):
''' Deprecated method: Fill screen with color/shade '''
- self.fillscreen_with_gray(c, s, self.gray)
+ self.fillscreen_with_gray(c, s, self._gray)
- def fillscreen_with_gray(self, c, s, g):
+ def fillscreen_with_gray(self, color, shade, gray):
''' Fill screen with color/shade/gray and reset to defaults '''
- oldc, olds, oldg = self.color, self.shade, self.gray
+
+ save_rgb = self._fgrgb[:]
# Special case for color blocks
- if c in COLORDICT:
- if COLORDICT[c][0] is None:
- s = COLORDICT[c][1]
- c = self.color
+ if color in COLORDICT:
+ if COLORDICT[color][0] is None:
+ self._shade = COLORDICT[color][1]
else:
- c = COLORDICT[c][0]
- if s in COLORDICT:
- s = COLORDICT[s][1]
- if g in COLORDICT:
- g = COLORDICT[g][2]
+ self._color = COLORDICT[color][0]
+ else:
+ self._color = color
+ if shade in COLORDICT:
+ self._shade = COLORDICT[shade][1]
+ else:
+ self._shade = shade
+ if gray in COLORDICT:
+ self._gray = COLORDICT[gray][2]
+ else:
+ self._gray = gray
+
+ if self._gray < 0:
+ self._gray = 0
+ if self._gray > 100:
+ self._gray = 100
- self.setcolor(c, False)
- self.setshade(s, False)
- self.setgray(g, False)
- self.bgrgb = self.fgrgb[:]
+ self.set_fgcolor(shade=self._shade, gray=self._gray, color=self._color)
+ self._bgrgb = self._fgrgb[:]
def _fillscreen(cr, rgb, w, h):
cr.set_source_rgb(rgb[0] / 255., rgb[1] / 255., rgb[2] / 255.)
cr.rectangle(0, 0, w * 2, h * 2)
cr.fill()
- _fillscreen(self.canvas, self.fgrgb, self.width, self.height)
+ _fillscreen(self.canvas, self._fgrgb, self.width, self.height)
self.inval()
if self.cr_svg is not None:
- _fillscreen(self.cr_svg, self.fgrgb, self.width, self.height)
- self.setcolor(oldc, False)
- self.setshade(olds, False)
- self.setgray(oldg, False)
- self.fill = False
- self.poly_points = []
-
- def set_fgcolor(self):
+ _fillscreen(self.cr_svg, self._fgrgb, self.width, self.height)
+
+ self._fgrgb = save_rgb[:]
+
+ def set_fgcolor(self, shade=None, gray=None, color=None):
''' Set the foreground color '''
- sh = (wrap100(self.shade) - 50) / 50.0
- rgb = COLOR_TABLE[wrap100(self.color)]
+ if shade is not None:
+ self._shade = shade
+ if gray is not None:
+ self._gray = gray
+ if color is not None:
+ self._color = color
+ sh = (wrap100(self._shade) - 50) / 50.0
+ rgb = COLOR_TABLE[wrap100(self._color)]
r = (rgb >> 8) & 0xff00
- r = calc_gray(r, self.gray)
+ r = calc_gray(r, self._gray)
r = calc_shade(r, sh)
g = rgb & 0xff00
- g = calc_gray(g, self.gray)
+ g = calc_gray(g, self._gray)
g = calc_shade(g, sh)
b = (rgb << 8) & 0xff00
- b = calc_gray(b, self.gray)
+ b = calc_gray(b, self._gray)
b = calc_shade(b, sh)
- self.fgrgb = [r >> 8, g >> 8, b >> 8]
-
- def setpen(self, bool, share=True):
- ''' Lower or raise the pen '''
- self.pendown = bool
- self.tw.active_turtle.set_pen_state(bool)
- if self.tw.sharing() and share:
- event = 'p|%s' % (data_to_string([self._get_my_nick(), bool]))
- self.tw.send_event(event)
+ self._fgrgb = [r >> 8, g >> 8, b >> 8]
def draw_surface(self, surface, x, y, w, h):
''' Draw a surface '''
@@ -568,7 +280,7 @@ class TurtleGraphics:
if self.cr_svg is not None:
_draw_surface(self.cr_svg, surface, x, y, w, h)
- def draw_pixbuf(self, pixbuf, a, b, x, y, w, h, path, share=True):
+ def draw_pixbuf(self, pixbuf, a, b, x, y, w, h, heading):
''' Draw a pixbuf '''
def _draw_pixbuf(cr, pixbuf, a, b, x, y, w, h, heading):
@@ -585,37 +297,15 @@ class TurtleGraphics:
cc.fill()
cc.restore()
- _draw_pixbuf(self.canvas, pixbuf, a, b, x, y, w, h, self.heading)
+ _draw_pixbuf(self.canvas, pixbuf, a, b, x, y, w, h, heading)
self.inval()
if self.cr_svg is not None:
- _draw_pixbuf(self.cr_svg, pixbuf, a, b, x, y, w, h, self.heading)
- if self.tw.sharing() and share:
- if self.tw.running_sugar:
- tmp_path = get_path(self.tw.activity, 'instance')
- else:
- tmp_path = '/tmp'
- tmp_file = os.path.join(get_path(self.tw.activity, 'instance'),
- 'tmpfile.png')
- pixbuf.save(tmp_file, 'png', {'quality': '100'})
- data = image_to_base64(tmp_file, tmp_path)
- height = pixbuf.get_height()
- width = pixbuf.get_width()
- x, y = self.screen_to_turtle_coordinates(x, y)
- event = 'P|%s' % (data_to_string([self._get_my_nick(),
- [round_int(a), round_int(b),
- round_int(x), round_int(y),
- round_int(w), round_int(h),
- round_int(width),
- round_int(height),
- data]]))
- gobject.idle_add(self.tw.send_event, event)
- os.remove(tmp_file)
-
- def draw_text(self, label, x, y, size, w, share=True):
+ _draw_pixbuf(self.cr_svg, pixbuf, a, b, x, y, w, h, heading)
+
+ def draw_text(self, label, x, y, size, width, heading, scale):
''' Draw text '''
- w *= self.tw.coord_scale
- def _draw_text(cr, label, x, y, size, w, scale, heading, rgb):
+ def _draw_text(cr, label, x, y, size, width, scale, heading, rgb):
cc = pangocairo.CairoContext(cr)
pl = cc.create_layout()
fd = pango.FontDescription('Sans')
@@ -627,7 +317,7 @@ class TurtleGraphics:
pl.set_text(str(label))
else:
pl.set_text(str(label))
- pl.set_width(int(w) * pango.SCALE)
+ pl.set_width(int(width) * pango.SCALE)
cc.save()
cc.translate(x, y)
cc.rotate(heading * DEGTOR)
@@ -636,36 +326,24 @@ class TurtleGraphics:
cc.show_layout(pl)
cc.restore()
- _draw_text(self.canvas, label, x, y, size, w, self.tw.coord_scale,
- self.heading, self.fgrgb)
+ width *= scale
+ _draw_text(self.canvas, label, x, y, size, width, scale, heading,
+ self._fgrgb)
self.inval()
if self.cr_svg is not None: # and self.pendown:
- _draw_text(self.cr_svg, label, x, y, size, w, self.tw.coord_scale,
- self.heading, self.fgrgb)
- if self.tw.sharing() and share:
- event = 'W|%s' % (data_to_string([self._get_my_nick(),
- [label, round_int(x),
- round_int(y), round_int(size),
- round_int(w)]]))
- self.tw.send_event(event)
-
- def turtle_to_screen_coordinates(self, x, y):
- ''' The origin of turtle coordinates is the center of the screen '''
- return self.width / 2. + x, self.invert_y_coordinate(y)
-
- def screen_to_turtle_coordinates(self, x, y):
- ''' The origin of the screen coordinates is the upper left corner '''
- return x - self.width / 2., self.invert_y_coordinate(y)
-
- def invert_y_coordinate(self, y):
- ''' Positive y goes up in turtle coordinates, down in sceeen
- coordinates '''
- return self.height / 2. - y
+ _draw_text(self.cr_svg, label, x, y, size, width, scale, heading,
+ self._fgrgb)
+
+ def set_source_rgb(self):
+ r = self._fgrgb[0] / 255.
+ g = self._fgrgb[1] / 255.
+ b = self._fgrgb[2] / 255.
+ self.canvas.set_source_rgb(r, g, b)
+ if self.cr_svg is not None:
+ self.cr_svg.set_source_rgb(r, g, b)
def draw_line(self, x1, y1, x2, y2):
''' Draw a line '''
- x1, y1 = self.turtle_to_screen_coordinates(x1, y1)
- x2, y2 = self.turtle_to_screen_coordinates(x2, y2)
def _draw_line(cr, x1, y1, x2, y2):
cr.move_to(x1, y1)
@@ -675,40 +353,23 @@ class TurtleGraphics:
_draw_line(self.canvas, x1, y1, x2, y2)
if self.cr_svg is not None:
_draw_line(self.cr_svg, x1, y1, x2, y2)
- if self.fill:
- if self.poly_points == []:
- self.poly_points.append(('move', x1, y1))
- self.poly_points.append(('line', x2, y2))
-
- def turn_turtle(self):
- ''' Change the orientation of the turtle '''
- self.tw.active_turtle.set_heading(self.heading)
-
- def move_turtle(self):
- ''' Move the turtle '''
- x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor)
- if self.tw.interactive_mode:
- self.tw.active_turtle.move(
- (self.cx + x - self.tw.active_turtle.spr.rect.width / 2.,
- self.cy + y - self.tw.active_turtle.spr.rect.height / 2.))
- else:
- self.tw.active_turtle.move((self.cx + x, self.cy + y))
+ self.inval()
def get_color_index(self, r, g, b, a=0):
''' Find the closest palette entry to the rgb triplet '''
- if self.shade != 50 or self.gray != 100:
+ if self._shade != 50 or self._gray != 100:
r <<= 8
g <<= 8
b <<= 8
- if self.shade != 50:
- sh = (wrap100(self.shade) - 50) / 50.
+ if self._shade != 50:
+ sh = (wrap100(self._shade) - 50) / 50.
r = calc_shade(r, sh, True)
g = calc_shade(g, sh, True)
b = calc_shade(b, sh, True)
- if self.gray != 100:
- r = calc_gray(r, self.gray, True)
- g = calc_gray(g, self.gray, True)
- b = calc_gray(b, self.gray, True)
+ if self._gray != 100:
+ r = calc_gray(r, self._gray, True)
+ g = calc_gray(g, self._gray, True)
+ b = calc_gray(b, self._gray, True)
r >>= 8
g >>= 8
b >>= 8
@@ -727,20 +388,19 @@ class TurtleGraphics:
closest_color = i
return closest_color
- def get_pixel(self):
+ def get_pixel(self, x, y):
''' Read the pixel at x, y '''
- if self.tw.interactive_mode:
- x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor)
+ if self.turtle_window.interactive_mode:
x = int(x)
y = int(y)
- w = self.tw.turtle_canvas.get_width()
- h = self.tw.turtle_canvas.get_height()
+ w = self.turtle_window.turtle_canvas.get_width()
+ h = self.turtle_window.turtle_canvas.get_height()
if x < 0 or x > (w - 1) or y < 0 or y > (h - 1):
return(-1, -1, -1, -1)
# create a new 1x1 cairo surface
cs = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1)
cr = cairo.Context(cs)
- cr.set_source_surface(self.tw.turtle_canvas, -x, -y)
+ cr.set_source_surface(self.turtle_window.turtle_canvas, -x, -y)
cr.rectangle(0, 0, 1, 1)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.fill()
@@ -750,32 +410,6 @@ class TurtleGraphics:
else:
return(-1, -1, -1, -1)
- def set_turtle(self, k, colors=None):
- ''' Select the current turtle and associated pen status '''
- if k not in self.tw.turtles.dict:
- # if it is a new turtle, start it in the center of the screen
- self.tw.active_turtle = self.tw.turtles.get_turtle(k, True, colors)
- self.seth(0.0, False)
- self.setxy(0.0, 0.0, False, pendown=False)
- self.tw.active_turtle.set_pen_state(True)
- elif colors is not None:
- self.tw.active_turtle = self.tw.turtles.get_turtle(k, False)
- self.tw.active_turtle.set_turtle_colors(colors)
- else:
- self.tw.active_turtle = self.tw.turtles.get_turtle(k, False)
- self.tw.active_turtle.show()
- tx, ty = self.tw.active_turtle.get_xy()
- self.xcor, self.ycor = self.screen_to_turtle_coordinates(tx, ty)
- if self.tw.interactive_mode:
- self.xcor += self.tw.active_turtle.spr.rect.width / 2.
- self.ycor -= self.tw.active_turtle.spr.rect.height / 2.
- self.heading = self.tw.active_turtle.get_heading()
- self.setcolor(self.tw.active_turtle.get_color(), False)
- self.setgray(self.tw.active_turtle.get_gray(), False)
- self.setshade(self.tw.active_turtle.get_shade(), False)
- self.setpensize(self.tw.active_turtle.get_pen_size(), False)
- self.setpen(self.tw.active_turtle.get_pen_state(), False)
-
def svg_close(self):
''' Close current SVG graphic '''
self.cr_svg.show_page()
@@ -784,9 +418,6 @@ class TurtleGraphics:
''' Reset svg flags '''
self.cr_svg = None
- def _get_my_nick(self):
- return self.tw.nick
-
def inval(self):
''' Invalidate a region for gtk '''
- self.tw.inval_all()
+ self.turtle_window.inval_all()
diff --git a/TurtleArt/tacollaboration.py b/TurtleArt/tacollaboration.py
index 32df65b..26a21d7 100644
--- a/TurtleArt/tacollaboration.py
+++ b/TurtleArt/tacollaboration.py
@@ -200,7 +200,7 @@ class Collaboration():
return
# Save active Turtle
- save_active_turtle = self._tw.active_turtle
+ save_active_turtle = self._tw.turtles.get_active_turtle()
try:
command, payload = event_message.split('|', 2)
@@ -211,7 +211,7 @@ class Collaboration():
self._processing_methods[command](payload)
# Restore active Turtle
- self._tw.canvas.set_turtle(
+ self._tw.turtles.set_turtle(
self._tw.turtles.get_turtle_key(save_active_turtle))
def send_event(self, entry):
@@ -229,13 +229,13 @@ class Collaboration():
# Make sure it is not a "rejoin".
if not nick in self._tw.remote_turtle_dictionary:
# Add new turtle for the joiner.
- self._tw.canvas.set_turtle(nick, colors)
+ self._tw.turtles.set_turtle(nick, colors)
self._tw.label_remote_turtle(nick, colors)
self._tw.remote_turtle_dictionary[nick] = colors
else:
self._tw.remote_turtle_dictionary = self._get_dictionary()
# Add new turtle for the joiner.
- self._tw.canvas.set_turtle(nick, colors)
+ self._tw.turtles.set_turtle(nick, colors)
self._tw.label_remote_turtle(nick, colors)
# Sharer should send the updated remote turtle dictionary to everyone.
@@ -264,7 +264,7 @@ class Collaboration():
# Add new the turtle.
colors = remote_turtle_dictionary[nick]
self._tw.remote_turtle_dictionary[nick] = colors
- self._tw.canvas.set_turtle(nick, colors)
+ self._tw.turtles.set_turtle(nick, colors)
# Label the remote turtle.
self._tw.label_remote_turtle(nick, colors)
debug_output('adding %s to remote turtle dictionary' %
@@ -278,23 +278,23 @@ class Collaboration():
def send_my_xy(self):
''' Set xy location so joiner can sync turtle positions. Should be
used to sync positions after turtle drag. '''
- self._tw.canvas.set_turtle(self._get_nick())
- if self._tw.canvas.pendown:
+ self._tw.turtles.set_turtle(self._get_nick())
+ if self._tw.turtles.get_active_turtle().get_pen_state():
self.send_event('p|%s' % (data_to_string([self._get_nick(),
False])))
put_pen_back_down = True
else:
put_pen_back_down = False
- self.send_event('x|%s' %
- (data_to_string([self._get_nick(),
- [int(self._tw.canvas.xcor),
- int(self._tw.canvas.ycor)]])))
+ self.send_event('x|%s' % (data_to_string(
+ [self._get_nick(),
+ [int(self._tw.turtles.get_active_turtle().get_xy()[0]),
+ int(self._tw.turtles.get_active_turtle().get_xy()[1])]])))
if put_pen_back_down:
self.send_event('p|%s' % (data_to_string([self._get_nick(),
True])))
- self.send_event('r|%s' %
- (data_to_string([self._get_nick(),
- int(self._tw.canvas.heading)])))
+ self.send_event('r|%s' % (data_to_string(
+ [self._get_nick(),
+ int(self._tw.turtles.get_active_turtle().get_heading())])))
def _reskin_turtle(self, payload):
if len(payload) > 0:
@@ -307,8 +307,8 @@ class Collaboration():
file_name = base64_to_image(data, tmp_path)
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(file_name,
width, height)
- self._tw.canvas.set_turtle(nick)
- self._tw.active_turtle.set_shapes([pixbuf])
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_shapes([pixbuf])
def _draw_pixbuf(self, payload):
if len(payload) > 0:
@@ -322,89 +322,93 @@ class Collaboration():
file_name = base64_to_image(data, tmp_path)
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(file_name,
width, height)
- x, y = self._tw.canvas.turtle_to_screen_coordinates(x, y)
- self._tw.canvas.draw_pixbuf(pixbuf, a, b, x, y, w, h,
- file_name, False)
+ pos = self._tw.turtles.turtle_to_screen_coordinates((x, y))
+ self._tw.turtles.get_active_turtle().draw_pixbuf(
+ pixbuf, a, b, pos[0], pos[1], w, h, file_name, False)
def _move_forward(self, payload):
if len(payload) > 0:
[nick, x] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.forward(x, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().forward(x, False)
def _move_in_arc(self, payload):
if len(payload) > 0:
[nick, [a, r]] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.arc(a, r, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().arc(a, r, False)
def _rotate_turtle(self, payload):
if len(payload) > 0:
[nick, h] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.seth(h, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_heading(h, False)
def _setxy(self, payload):
if len(payload) > 0:
[nick, [x, y]] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setxy(x, y, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_xy(x, y, False)
def _draw_text(self, payload):
if len(payload) > 0:
[nick, [label, x, y, size, w]] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.draw_text(label, x, y, size, w, False)
+ self._tw.turtles.get_active_turtle().draw_text(
+ label, x, y, size, w, False)
def _set_pen_color(self, payload):
if len(payload) > 0:
[nick, x] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setcolor(x, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_color(x, False)
def _set_pen_gray_level(self, payload):
if len(payload) > 0:
[nick, x] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setgray(x, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_gray(x, False)
def _set_pen_shade(self, payload):
if len(payload) > 0:
[nick, x] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setshade(x, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_shade(x, False)
def _set_pen_width(self, payload):
if len(payload) > 0:
[nick, x] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setpensize(x, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_pen_size(x, False)
def _set_pen_state(self, payload):
if len(payload) > 0:
[nick, x] = data_from_string(payload)
if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setpen(x, False)
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_pen_state(x, False)
def _fill_polygon(self, payload):
- # Check to make sure that the poly_point array is passed properly
if len(payload) > 0:
[nick, poly_points] = data_from_string(payload)
shared_poly_points = []
for i in range(len(poly_points)):
shared_poly_points.append(
- (self._tw.canvas.turtle_to_screen_coordinates
+ (self._tw.turtles.turtle_to_screen_coordinates
(poly_points[i][0], poly_points[i][1])))
- self._tw.canvas.fill_polygon(shared_poly_points)
+ if nick != self._tw.nick:
+ self._tw.turtles.set_turtle(nick)
+ self._tw.turtles.get_active_turtle().set_poly_points(
+ shared_poly_points)
+ self._tw.turtles.get_active_turtle().stop_fill(False)
def _speak(self, payload):
if len(payload) > 0:
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py
index 29d05d9..7e72439 100644
--- a/TurtleArt/talogo.py
+++ b/TurtleArt/talogo.py
@@ -166,7 +166,7 @@ class LogoCode:
if self.tw.gst_available:
from tagplay import stop_media
stop_media(self)
- self.tw.active_turtle.show()
+ self.tw.turtles.get_active_turtle().show()
self.tw.running_blocks = False
# If we disabled hover help, reenable it
if self._disable_help:
@@ -188,10 +188,14 @@ class LogoCode:
return sym
def run_blocks(self, code):
+ """Run code generated by generate_code().
+ """
self.start_time = time()
self._setup_cmd(code)
def generate_code(self, blk, blocks):
+ """ Generate code to be passed to run_blocks() from a stack of blocks.
+ """
for k in self.stacks.keys():
self.stacks[k] = None
self.stacks['stack1'] = None
@@ -323,7 +327,7 @@ class LogoCode:
def _setup_cmd(self, string):
""" Execute the psuedocode. """
- self.hidden_turtle = self.tw.active_turtle
+ self.hidden_turtle = self.tw.turtles.get_active_turtle()
self.hidden_turtle.hide() # Hide the turtle while we are running.
self.procstop = False
blklist = self._readline(string)
@@ -413,12 +417,12 @@ class LogoCode:
# In debugging modes, we pause between steps and show the turtle.
if self.tw.step_time > 0:
- self.tw.active_turtle.show()
+ self.tw.turtles.get_active_turtle().show()
endtime = _millisecond() + self.tw.step_time * 100.
while _millisecond() < endtime:
sleep(0.1)
yield True
- self.tw.active_turtle.hide()
+ self.tw.turtles.get_active_turtle().hide()
# 'Stand-alone' booleans are handled here.
if token == self.symopar:
@@ -537,7 +541,7 @@ class LogoCode:
self.hidden_turtle.show()
self.hidden_turtle = None
else:
- self.tw.active_turtle.show()
+ self.tw.turtles.get_active_turtle().show()
self.tw.running_blocks = False
return False
except logoerror, e:
@@ -599,10 +603,12 @@ class LogoCode:
from tagplay import stop_media
stop_media(self)
self.tw.canvas.clearscreen()
+ self.tw.turtles.reset_turtles()
self.scale = DEFAULT_SCALE
self.hidden_turtle = None
self.start_time = time()
self.clear_value_blocks()
+ self.tw.activity.restore_challenge()
def clear_value_blocks(self):
if not hasattr(self, 'value_blocks_to_update'):
@@ -689,11 +695,13 @@ class LogoCode:
def x2tx(self):
""" Convert screen coordinates to turtle coordinates """
- return int(self.tw.canvas.width / 2) + int(self.tw.canvas.xcor)
+ return int(self.tw.canvas.width / 2) + \
+ int(self.tw.turtles.get_active_turtle().get_xy()[0])
def y2ty(self):
""" Convert screen coordinates to turtle coordinates """
- return int(self.tw.canvas.height / 2) - int(self.tw.canvas.ycor)
+ return int(self.tw.canvas.height / 2) - \
+ int(self.tw.turtles.get_active_turtle().get_xy()[1])
def wpercent(self):
""" width as a percentage of screen coordinates """
@@ -742,20 +750,23 @@ class LogoCode:
w *= self.tw.coord_scale
h *= self.tw.coord_scale
if center:
- self.tw.canvas.draw_pixbuf(self.pixbuf, 0, 0,
- self.x2tx() - int(w / 2),
- self.y2ty() - int(h / 2), w, h,
- self.filepath)
+ self.tw.turtles.get_active_turtle().draw_pixbuf(
+ self.pixbuf, 0, 0,
+ self.x2tx() - int(w / 2),
+ self.y2ty() - int(h / 2), w, h,
+ self.filepath)
elif offset:
- self.tw.canvas.draw_pixbuf(self.pixbuf, 0, 0,
- self.x2tx(),
- self.y2ty() - h,
- w, h, self.filepath)
+ self.tw.turtles.get_active_turtle().draw_pixbuf(
+ self.pixbuf, 0, 0,
+ self.x2tx(),
+ self.y2ty() - h,
+ w, h, self.filepath)
else:
- self.tw.canvas.draw_pixbuf(self.pixbuf, 0, 0,
- self.x2tx(),
- self.y2ty(),
- w, h, self.filepath)
+ self.tw.turtles.get_active_turtle().draw_pixbuf(
+ self.pixbuf, 0, 0,
+ self.x2tx(),
+ self.y2ty(),
+ w, h, self.filepath)
def insert_desc(self, mimetype=None, description=None):
""" Description text only (at current x, y) """
@@ -786,8 +797,8 @@ class LogoCode:
else:
text = self.filepath
if text is not None:
- self.tw.canvas.draw_text(text, self.x2tx(), self.y2ty(),
- self.body_height, w)
+ self.tw.turtles.get_active_turtle().draw_text(
+ text, self.x2tx(), self.y2ty(), self.body_height, w)
def media_wait(self):
""" Wait for media to stop playing """
@@ -849,7 +860,9 @@ class LogoCode:
def _expand_forever(self, b, blk, blocks):
""" Expand a while or until block into: forever, ifelse, stopstack
- Expand a forever block to run in a separate stack """
+ Expand a forever block to run in a separate stack
+ Parameters: the loop block, the top block, all blocks.
+ Return the start block of the expanded loop, and all blocks."""
# TODO: create a less brittle way of doing this; having to
# manage the connections and flows locally means we may run
diff --git a/TurtleArt/tasprite_factory.py b/TurtleArt/tasprite_factory.py
index 200fb78..2bd8993 100755
--- a/TurtleArt/tasprite_factory.py
+++ b/TurtleArt/tasprite_factory.py
@@ -30,6 +30,20 @@ from taconstants import HIT_RED, HIT_GREEN, HIDE_WHITE, SHOW_WHITE, \
class SVG:
+ """ Interface to the graphical representation of blocks, turtles,
+ palettes, etc. on screen
+
+ terms used here:
+ docks -- list of connection points of a block to other blocks
+ innies -- right hand side docks of a block, argument slots
+ outie -- left hand side dock of a block
+ slot -- top dock of a block that can be attached to other blocks
+ cap -- top dock of a block that cannot be attached to other blocks
+ tab -- bottom dock of a block if other blocks can be attached
+ tail -- bottom dock of a block if no other blocks can be attached
+ arm -- connection point of a branching block (if-then, loops) where
+ inner blocks are attached
+ else -- optional second `arm' for if-then-else blocks """
def __init__(self):
self._x = 0
@@ -496,13 +510,13 @@ C 36.1 12.6 43.1 20.6 43.1 30.4 Z" stroke-width="3.5" \
fill="%s" stroke="%s" />\n' % (self._fill, self._stroke)
svg += ' <path d="M 25.9 33.8 L 24.3 29.1 \
L 27.5 26.5 L 31.1 29.2 L 29.6 33.8 Z" stroke-width="3.5" \
-fill="%s" stroke="%s" />\n' % (self._fill, self._stroke)
+fill="%s" stroke="none" />\n' % (self._stroke)
svg += ' <path d="M 27.5 41.6 C 23.5 41.4 22.0 39.5 22.0 39.5 \
L 25.5 35.4 L 30.0 35.5 L 33.1 39.7 C 33.1 39.7 30.2 41.7 27.5 41.6 Z" \
-stroke-width="3.5" fill="%s" stroke="%s" />\n' % (self._fill, self._stroke)
+stroke-width="3.5" fill="%s" stroke="none" />\n' % (self._stroke)
svg += ' <path d="M 18.5 33.8 C 17.6 30.9 18.6 27.0 18.6 27.0 \
L 22.6 29.1 L 24.1 33.8 L 20.5 38.0 C 20.5 38.0 19.1 36.0 18.4 33.8 Z" \
-stroke-width="3.5" fill="%s" stroke="%s" />\n' % (self._fill, self._stroke)
+stroke-width="3.5" fill="%s" stroke="none" />\n' % (self._stroke)
svg += ' <path d="M 19.5 25.1 C 19.5 25.1 20.0 23.2 22.5 21.3 \
C 24.7 19.7 27.0 19.6 27.0 19.6 L 26.9 24.6 L 23.4 27.3 L 19.5 25.1 Z" \
stroke-width="3.5" fill="%s" stroke="none" />\n' % (self._stroke)
@@ -1224,6 +1238,13 @@ def close_file(f):
def generator(datapath):
svg = SVG()
+ f = open_file(datapath, "turtle.svg")
+ svg.set_scale(2)
+ svg_str = svg.turtle(['#00FF00','#00AA00'])
+ f.write(svg_str)
+ close_file(f)
+
+ svg = SVG()
f = open_file(datapath, "boolean_notnot.svg")
svg.set_scale(2)
svg.expand(30, 0, 0, 0)
@@ -1248,7 +1269,6 @@ def generator(datapath):
f.write(svg_str)
close_file(f)
- '''
svg = SVG()
f = open_file(datapath, "basic.svg")
svg.set_scale(2)
@@ -1473,7 +1493,6 @@ def generator(datapath):
svg_str = svg.clamp()
f.write(svg_str)
close_file(f)
- '''
def main():
diff --git a/TurtleArt/taturtle.py b/TurtleArt/taturtle.py
index 7db72e6..0ca6df6 100644
--- a/TurtleArt/taturtle.py
+++ b/TurtleArt/taturtle.py
@@ -19,22 +19,29 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
-from random import uniform
-from math import sin, cos, pi, sqrt
+import os
+
import gtk
+import gobject
import cairo
-from taconstants import (TURTLE_LAYER, DEFAULT_TURTLE_COLORS)
-from tasprite_factory import (SVG, svg_str_to_pixbuf)
-from tacanvas import (wrap100, COLOR_TABLE)
+from random import uniform
+from math import sin, cos, pi, sqrt
+from taconstants import (TURTLE_LAYER, DEFAULT_TURTLE_COLORS, DEFAULT_TURTLE,
+ COLORDICT)
+from tasprite_factory import SVG, svg_str_to_pixbuf
+from tacanvas import wrap100, COLOR_TABLE
from sprites import Sprite
-from tautils import debug_output
+from tautils import (debug_output, data_to_string, round_int, get_path,
+ image_to_base64)
SHAPES = 36
+DEGTOR = pi / 180.
+RTODEG = 180. / pi
def generate_turtle_pixbufs(colors):
- """ Generate pixbufs for generic turtles """
+ ''' Generate pixbufs for generic turtles '''
shapes = []
svg = SVG()
svg.set_scale(1.0)
@@ -46,106 +53,196 @@ def generate_turtle_pixbufs(colors):
class Turtles:
- def __init__(self, sprite_list):
- """ Class to hold turtles """
- self.dict = dict()
- self.sprite_list = sprite_list
- self.default_pixbufs = []
-
- def get_turtle(self, k, append=False, colors=None):
- """ Find a turtle """
- if k in self.dict:
- return self.dict[k]
+ def __init__(self, turtle_window):
+ ''' Class to hold turtles '''
+ self.turtle_window = turtle_window
+ self.sprite_list = turtle_window.sprite_list
+ self.width = turtle_window.width
+ self.height = turtle_window.height
+ self.dict = {}
+ self._default_pixbufs = []
+ self._active_turtle = None
+ self._default_turtle_name = DEFAULT_TURTLE
+
+ def get_turtle(self, turtle_name, append=False, colors=None):
+ ''' Find a turtle '''
+ if turtle_name in self.dict:
+ return self.dict[turtle_name]
elif not append:
return None
else:
if colors is None:
- Turtle(self, k)
+ Turtle(self, turtle_name)
elif isinstance(colors, (list, tuple)):
- Turtle(self, k, colors)
+ Turtle(self, turtle_name, colors)
else:
- Turtle(self, k, colors.split(','))
- return self.dict[k]
+ Turtle(self, turtle_name, colors.split(','))
+ return self.dict[turtle_name]
def get_turtle_key(self, turtle):
- """ Find a turtle's name """
- for k in iter(self.dict):
- if self.dict[k] == turtle:
- return k
+ ''' Find a turtle's name '''
+ for turtle_name in iter(self.dict):
+ if self.dict[turtle_name] == turtle:
+ return turtle_name
return None
def turtle_count(self):
- """ How many turtles are there? """
+ ''' How many turtles are there? '''
return(len(self.dict))
- def add_to_dict(self, k, turtle):
- """ Add a new turtle """
- self.dict[k] = turtle
+ def add_to_dict(self, turtle_name, turtle):
+ ''' Add a new turtle '''
+ self.dict[turtle_name] = turtle
- def remove_from_dict(self, k):
- """ Delete a turtle """
- if k in self.dict:
- del(self.dict[k])
+ def remove_from_dict(self, turtle_name):
+ ''' Delete a turtle '''
+ if turtle_name in self.dict:
+ del(self.dict[turtle_name])
def show_all(self):
- """ Make all turtles visible """
- for k in iter(self.dict):
- self.dict[k].show()
+ ''' Make all turtles visible '''
+ for turtle_name in iter(self.dict):
+ self.dict[turtle_name].show()
def spr_to_turtle(self, spr):
- """ Find the turtle that corresponds to sprite spr. """
- for k in iter(self.dict):
- if spr == self.dict[k].spr:
- return self.dict[k]
+ ''' Find the turtle that corresponds to sprite spr. '''
+ for turtle_name in iter(self.dict):
+ if spr == self.dict[turtle_name].spr:
+ return self.dict[turtle_name]
return None
def get_pixbufs(self):
- """ Get the pixbufs for the default turtle shapes. """
- if self.default_pixbufs == []:
- self.default_pixbufs = generate_turtle_pixbufs(
+ ''' Get the pixbufs for the default turtle shapes. '''
+ if self._default_pixbufs == []:
+ self._default_pixbufs = generate_turtle_pixbufs(
["#008000", "#00A000"])
- return(self.default_pixbufs)
+ return(self._default_pixbufs)
+
+ def turtle_to_screen_coordinates(self, pos):
+ ''' The origin of turtle coordinates is the center of the screen '''
+ return [self.width / 2.0 + pos[0], self._invert_y_coordinate(pos[1])]
+
+ def screen_to_turtle_coordinates(self, pos):
+ ''' The origin of the screen coordinates is the upper-left corner '''
+ return [pos[0] - self.width / 2.0, self._invert_y_coordinate(pos[1])]
+
+ def _invert_y_coordinate(self, y):
+ ''' Positive y goes up in turtle coordinates, down in sceeen
+ coordinates '''
+ return self.height / 2.0 - y
+
+ def reset_turtles(self):
+ for turtle_name in iter(self.dict):
+ self.set_turtle(turtle_name)
+ if not self._active_turtle.get_remote():
+ self._active_turtle.set_color(0)
+ self._active_turtle.set_shade(50)
+ self._active_turtle.set_gray(100)
+ self._active_turtle.set_pen_size(5)
+ self._active_turtle.reset_shapes()
+ self._active_turtle.set_heading(0.0)
+ self._active_turtle.set_pen_state(False)
+ self._active_turtle.move_turtle((0.0, 0.0))
+ self._active_turtle.set_pen_state(True)
+ self._active_turtle.set_fill(False)
+ self._active_turtle.hide()
+ self.set_turtle(self._default_turtle_name)
+
+ def set_turtle(self, turtle_name, colors=None):
+ ''' Select the current turtle and associated pen status '''
+ if turtle_name not in self.dict:
+ # if it is a new turtle, start it in the center of the screen
+ self._active_turtle = self.get_turtle(turtle_name, True, colors)
+ self._active_turtle.set_heading(0.0, False)
+ self._active_turtle.set_xy((0.0, 0.0), False, pendown=False)
+ self._active_turtle.set_pen_state(True)
+ elif colors is not None:
+ self._active_turtle = self.get_turtle(turtle_name, False)
+ self._active_turtle.set_turtle_colors(colors)
+ else:
+ self._active_turtle = self.get_turtle(turtle_name, False)
+ self._active_turtle.show()
+ self._active_turtle.set_color(share=False)
+ self._active_turtle.set_gray(share=False)
+ self._active_turtle.set_shade(share=False)
+ self._active_turtle.set_pen_size(share=False)
+ self._active_turtle.set_pen_state(share=False)
+
+ def set_default_turtle_name(self, name):
+ self._default_turtle_name = name
+
+ def get_default_turtle_name(self):
+ return self._default_turtle_name
+
+ def set_active_turtle(self, active_turtle):
+ self._active_turtle = active_turtle
+
+ def get_active_turtle(self):
+ return self._active_turtle
class Turtle:
- def __init__(self, turtles, key, turtle_colors=None):
- """ The turtle is not a block, just a sprite with an orientation """
- self.x = 0.0
- self.y = 0.0
- self.hidden = False
- self.shapes = []
- self.custom_shapes = False
- self.type = 'turtle'
- self.name = key
- self.heading = 0.0
- self.pen_shade = 50
- self.pen_color = 0
- self.pen_gray = 100
- self.pen_size = 5
- self.pen_state = True
+ def __init__(self, turtles, turtle_name, turtle_colors=None):
+ ''' The turtle is not a block, just a sprite with an orientation '''
+ self.spr = None
self.label_block = None
+ self._turtles = turtles
+ self._shapes = []
+ self._custom_shapes = False
+ self._name = turtle_name
+ self._hidden = False
+ self._remote = False
+ self._x = 0.0
+ self._y = 0.0
+ self._heading = 0.0
+ self._half_width = 0
+ self._half_height = 0
+ self._drag_radius = None
+ self._pen_shade = 50
+ self._pen_color = 0
+ self._pen_gray = 100
+ self._pen_size = 5
+ self._pen_state = True
+ self._pen_fill = False
+ self._poly_points = []
+
+ self._prep_shapes(turtle_name, self._turtles, turtle_colors)
+
+ # Create a sprite for the turtle in interactive mode.
+ if turtles.sprite_list is not None:
+ self.spr = Sprite(self._turtles.sprite_list, 0, 0, self._shapes[0])
- self._prep_shapes(key, turtles, turtle_colors)
+ self._calculate_sizes()
- # Choose a random angle from which to attach the turtle label.
- if turtles.sprite_list is not None:
- self.spr = Sprite(turtles.sprite_list, 0, 0, self.shapes[0])
+ # Choose a random angle from which to attach the turtle
+ # label to be used when sharing.
angle = uniform(0, pi * 4 / 3.0) # 240 degrees
- w = self.shapes[0].get_width()
- r = w * 0.67
- # Restrict angle the the sides 30-150; 210-330
+ width = self._shapes[0].get_width()
+ radius = width * 0.67
+ # Restrict the angle to the sides: 30-150; 210-330
if angle > pi * 2 / 3.0:
angle += pi / 2.0 # + 90
- self.label_xy = [int(r * sin(angle)),
- int(r * cos(angle) + w / 2.0)]
+ self.label_xy = [int(radius * sin(angle)),
+ int(radius * cos(angle) + width / 2.0)]
else:
angle += pi / 6.0 # + 30
- self.label_xy = [int(r * sin(angle) + w / 2.0),
- int(r * cos(angle) + w / 2.0)]
- else:
- self.spr = None
- turtles.add_to_dict(key, self)
+ self.label_xy = [int(radius * sin(angle) + width / 2.0),
+ int(radius * cos(angle) + width / 2.0)]
+
+ self._turtles.add_to_dict(turtle_name, self)
+
+ def _calculate_sizes(self):
+ self._half_width = int(self.spr.rect.width / 2.0)
+ self._half_height = int(self.spr.rect.height / 2.0)
+ self._drag_radius = ((self._half_width * self._half_width) +
+ (self._half_height * self._half_height)) / 6
+
+ def set_remote(self):
+ self._remote = True
+
+ def get_remote(self):
+ return self._remote
def _prep_shapes(self, name, turtles=None, turtle_colors=None):
# If the turtle name is an int, we'll use a palette color as the
@@ -158,38 +255,38 @@ class Turtle:
if turtle_colors is not None:
self.colors = turtle_colors[:]
- self.shapes = generate_turtle_pixbufs(self.colors)
+ self._shapes = generate_turtle_pixbufs(self.colors)
elif use_color_table:
fill = wrap100(int_key)
stroke = wrap100(fill + 10)
self.colors = ['#%06x' % (COLOR_TABLE[fill]),
'#%06x' % (COLOR_TABLE[stroke])]
- self.shapes = generate_turtle_pixbufs(self.colors)
+ self._shapes = generate_turtle_pixbufs(self.colors)
else:
if turtles is not None:
self.colors = DEFAULT_TURTLE_COLORS
- self.shapes = turtles.get_pixbufs()
+ self._shapes = turtles.get_pixbufs()
def set_turtle_colors(self, turtle_colors):
''' reset the colors of a preloaded turtle '''
if turtle_colors is not None:
self.colors = turtle_colors[:]
- self.shapes = generate_turtle_pixbufs(self.colors)
- self.set_heading(self.heading)
+ self._shapes = generate_turtle_pixbufs(self.colors)
+ self.set_heading(self._heading, share=False)
def set_shapes(self, shapes, i=0):
- """ Reskin the turtle """
+ ''' Reskin the turtle '''
n = len(shapes)
if n == 1 and i > 0: # set shape[i]
- if i < len(self.shapes):
- self.shapes[i] = shapes[0]
+ if i < len(self._shapes):
+ self._shapes[i] = shapes[0]
elif n == SHAPES: # all shapes have been precomputed
- self.shapes = shapes[:]
+ self._shapes = shapes[:]
else: # rotate shapes
if n != 1:
debug_output("%d images passed to set_shapes: ignoring" % (n),
- self.tw.running_sugar)
- if self.heading == 0.0: # rotate the shapes
+ self._turtles.turtle_window.running_sugar)
+ if self._heading == 0.0: # rotate the shapes
images = []
w, h = shapes[0].get_width(), shapes[0].get_height()
nw = nh = int(sqrt(w * w + h * h))
@@ -197,113 +294,447 @@ class Turtle:
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, nw, nh)
context = cairo.Context(surface)
context = gtk.gdk.CairoContext(context)
- context.translate(nw / 2., nh / 2.)
+ context.translate(nw / 2.0, nh / 2.0)
context.rotate(i * 10 * pi / 180.)
- context.translate(-nw / 2., -nh / 2.)
- context.set_source_pixbuf(shapes[0], (nw - w) / 2.,
- (nh - h) / 2.)
+ context.translate(-nw / 2.0, -nh / 2.0)
+ context.set_source_pixbuf(shapes[0], (nw - w) / 2.0,
+ (nh - h) / 2.0)
context.rectangle(0, 0, nw, nh)
context.fill()
images.append(surface)
- self.shapes = images[:]
+ self._shapes = images[:]
else: # associate shape with image at current heading
- j = int(self.heading + 5) % 360 / (360 / SHAPES)
- self.shapes[j] = shapes[0]
- self.custom_shapes = True
+ j = int(self._heading + 5) % 360 / (360 / SHAPES)
+ self._shapes[j] = shapes[0]
+ self._custom_shapes = True
self.show()
+ self._calculate_sizes()
def reset_shapes(self):
- """ Reset the shapes to the standard turtle """
- if self.custom_shapes:
- self.shapes = generate_turtle_pixbufs(self.colors)
- self.custom_shapes = False
-
- def set_heading(self, heading):
- """ Set the turtle heading (one shape per 360/SHAPES degrees) """
- self.heading = heading
- i = (int(self.heading + 5) % 360) / (360 / SHAPES)
- if not self.hidden and self.spr is not None:
+ ''' Reset the shapes to the standard turtle '''
+ if self._custom_shapes:
+ self._shapes = generate_turtle_pixbufs(self.colors)
+ self._custom_shapes = False
+ self._calculate_sizes()
+
+ def set_heading(self, heading, share=True):
+ ''' Set the turtle heading (one shape per 360/SHAPES degrees) '''
+ try:
+ self._heading = heading
+ except (TypeError, ValueError):
+ debug_output('set_heading: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+ self._heading %= 360
+
+ i = (int(self._heading + 5) % 360) / (360 / SHAPES)
+ if not self._hidden and self.spr is not None:
try:
- self.spr.set_shape(self.shapes[i])
+ self.spr.set_shape(self._shapes[i])
except IndexError:
- self.spr.set_shape(self.shapes[0])
-
- def set_color(self, color):
- """ Set the pen color for this turtle. """
- self.pen_color = color
-
- def set_gray(self, gray):
- """ Set the pen gray level for this turtle. """
- self.pen_gray = gray
-
- def set_shade(self, shade):
- """ Set the pen shade for this turtle. """
- self.pen_shade = shade
-
- def set_pen_size(self, pen_size):
- """ Set the pen size for this turtle. """
- self.pen_size = pen_size
+ self.spr.set_shape(self._shapes[0])
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'r|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ round_int(self._heading)]))
+ self._turtles.turtle_window.send_event(event)
+
+ def set_color(self, color=None, share=True):
+ ''' Set the pen color for this turtle. '''
+ # Special case for color blocks
+ if color is not None and color in COLORDICT:
+ self.set_shade(COLORDICT[color][1], share)
+ self.set_gray(COLORDICT[color][2], share)
+ if COLORDICT[color][0] is not None:
+ self.set_color(COLORDICT[color][0], share)
+ color = COLORDICT[color][0]
+ else:
+ color = self._pen_color
+ elif color is None:
+ color = self._pen_color
- def set_pen_state(self, pen_state):
- """ Set the pen state (down==True) for this turtle. """
- self.pen_state = pen_state
+ try:
+ self._pen_color = color
+ except (TypeError, ValueError):
+ debug_output('set_color: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+
+ self._turtles.turtle_window.canvas.set_fgcolor(shade=self._pen_shade,
+ gray=self._pen_gray,
+ color=self._pen_color)
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'c|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ round_int(self._pen_color)]))
+ self._turtles.turtle_window.send_event(event)
+
+ def set_gray(self, gray=None, share=True):
+ ''' Set the pen gray level for this turtle. '''
+ if gray is not None:
+ try:
+ self._pen_gray = gray
+ except (TypeError, ValueError):
+ debug_output('set_gray: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+
+ if self._pen_gray < 0:
+ self._pen_gray = 0
+ if self._pen_gray > 100:
+ self._pen_gray = 100
+
+ self._turtles.turtle_window.canvas.set_fgcolor(shade=self._pen_shade,
+ gray=self._pen_gray,
+ color=self._pen_color)
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'g|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ round_int(self._pen_gray)]))
+ self._turtles.turtle_window.send_event(event)
+
+ def set_shade(self, shade=None, share=True):
+ ''' Set the pen shade for this turtle. '''
+ if shade is not None:
+ try:
+ self._pen_shade = shade
+ except (TypeError, ValueError):
+ debug_output('set_shade: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+
+ self._turtles.turtle_window.canvas.set_fgcolor(shade=self._pen_shade,
+ gray=self._pen_gray,
+ color=self._pen_color)
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 's|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ round_int(self._pen_shade)]))
+ self._turtles.turtle_window.send_event(event)
+
+ def set_pen_size(self, pen_size=None, share=True):
+ ''' Set the pen size for this turtle. '''
+ if pen_size is not None:
+ try:
+ self._pen_size = max(0, pen_size)
+ except (TypeError, ValueError):
+ debug_output('set_pen_size: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+
+ self._turtles.turtle_window.canvas.set_pen_size(self._pen_size)
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'w|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ round_int(self._pen_size)]))
+ self._turtles.turtle_window.send_event(event)
+
+ def set_pen_state(self, pen_state=None, share=True):
+ ''' Set the pen state (down==True) for this turtle. '''
+ if pen_state is not None:
+ self._pen_state = pen_state
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'p|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ self._pen_state]))
+ self._turtles.turtle_window.send_event(event)
+
+ def set_fill(self, state=False):
+ self._pen_fill = state
+ if not self._pen_fill:
+ self._poly_points = []
+
+ def set_poly_points(self, poly_points=None):
+ if poly_points is not None:
+ self._poly_points = poly_points[:]
+
+ def start_fill(self):
+ self._pen_fill = True
+ self._poly_points = []
+
+ def stop_fill(self, share=True):
+ self._pen_fill = False
+ if len(self._poly_points) == 0:
+ return
+
+ self._turtles.turtle_window.canvas.fill_polygon(self._poly_points)
+
+ if self._turtles.turtle_window.sharing() and share:
+ shared_poly_points = []
+ for p in self._poly_points:
+ shared_poly_points.append(
+ (self._turtles.screen_to_turtle_coordinates(p)))
+ event = 'F|%s' % (data_to_string(
+ [self._turtles.turtle_window.nick,
+ shared_poly_points]))
+ self._turtles.turtle_window.send_event(event)
+ self._poly_points = []
def hide(self):
- """ Hide the turtle. """
if self.spr is not None:
self.spr.hide()
if self.label_block is not None:
self.label_block.spr.hide()
- self.hidden = True
+ self._hidden = True
def show(self):
- """ Show the turtle. """
if self.spr is not None:
self.spr.set_layer(TURTLE_LAYER)
- self.hidden = False
- self.move((self.x, self.y))
- self.set_heading(self.heading)
+ self._hidden = False
+ self.move_turtle_spr((self._x, self._y))
+ self.set_heading(self._heading)
if self.label_block is not None:
self.label_block.spr.set_layer(TURTLE_LAYER + 1)
- def move(self, pos):
- """ Move the turtle. """
- self.x, self.y = pos[0], pos[1]
- if not self.hidden and self.spr is not None:
- self.spr.move((int(pos[0]), int(pos[1])))
+ def move_turtle(self, pos=None):
+ ''' Move the turtle's position '''
+ if pos is None:
+ pos = self.get_xy()
+
+ self._x, self._y = pos[0], pos[1]
+ if self.spr is not None:
+ self.move_turtle_spr(pos)
+
+ def move_turtle_spr(self, pos):
+ ''' Move the turtle's sprite '''
+ pos = self._turtles.turtle_to_screen_coordinates(pos)
+
+ pos[0] -= self._half_width
+ pos[1] -= self._half_height
+
+ if not self._hidden and self.spr is not None:
+ self.spr.move(pos)
if self.label_block is not None:
- self.label_block.spr.move((int(pos[0] + self.label_xy[0]),
- int(pos[1] + self.label_xy[1])))
- return(self.x, self.y)
+ self.label_block.spr.move((pos[0] + self.label_xy[0],
+ pos[1] + self.label_xy[1]))
+
+ def right(self, degrees, share=True):
+ ''' Rotate turtle clockwise '''
+ try:
+ self._heading += degrees
+ except (TypeError, ValueError):
+ debug_output('right: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+ self._heading %= 360
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'r|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ round_int(self._heading)]))
+ self._turtles.turtle_window.send_event(event)
+
+ def _draw_line(self, old, new, pendown):
+ if self._pen_state and pendown:
+ self._turtles.turtle_window.canvas.set_source_rgb()
+ pos1 = self._turtles.turtle_to_screen_coordinates(old)
+ pos2 = self._turtles.turtle_to_screen_coordinates(new)
+ self._turtles.turtle_window.canvas.draw_line(pos1[0], pos1[1],
+ pos2[0], pos2[1])
+ if self._pen_fill:
+ if self._poly_points == []:
+ self._poly_points.append(('move', pos1[0], pos1[1]))
+ self._poly_points.append(('line', pos2[0], pos2[1]))
+
+ def forward(self, distance, share=True):
+ scaled_distance = distance * self._turtles.turtle_window.coord_scale
+
+ old = self.get_xy()
+ try:
+ xcor = old[0] + scaled_distance * sin(self._heading * DEGTOR)
+ ycor = old[1] + scaled_distance * cos(self._heading * DEGTOR)
+ except (TypeError, ValueError):
+ debug_output('forward: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+
+ self._draw_line(old, (xcor, ycor), True)
+ self.move_turtle((xcor, ycor))
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'f|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ int(distance)]))
+ self._turtles.turtle_window.send_event(event)
+
+ def set_xy(self, pos, share=True, pendown=True):
+ old = self.get_xy()
+
+ try:
+ xcor = pos[0] * self._turtles.turtle_window.coord_scale
+ ycor = pos[1] * self._turtles.turtle_window.coord_scale
+ except (TypeError, ValueError):
+ debug_output('set_xy: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+
+ self._draw_line(old, (xcor, ycor), pendown)
+ self.move_turtle((xcor, ycor))
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'x|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ [round_int(xcor),
+ round_int(ycor)]]))
+ self._turtles.turtle_window.send_event(event)
+
+ def arc(self, a, r, share=True):
+ ''' Draw an arc '''
+ if self._pen_state:
+ self._turtles.turtle_window.canvas.set_source_rgb()
+ try:
+ if a < 0:
+ pos = self.larc(-a, r)
+ else:
+ pos = self.rarc(a, r)
+ except (TypeError, ValueError):
+ debug_output('arc: bad value sent to %s' % (__name__),
+ self._turtles.turtle_window.running_sugar)
+ return
+
+ self.move_turtle(pos)
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'a|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ [round_int(a), round_int(r)]]))
+ self._turtles.turtle_window.send_event(event)
+
+ def rarc(self, a, r):
+ ''' draw a clockwise arc '''
+ r *= self._turtles.turtle_window.coord_scale
+ if r < 0:
+ r = -r
+ a = -a
+ pos = self.get_xy()
+ cx = pos[0] + r * cos(self._heading * DEGTOR)
+ cy = pos[1] - r * sin(self._heading * DEGTOR)
+ if self._pen_state:
+ npos = self._turtles.turtle_to_screen_coordinates((cx, cy))
+ self._turtles.turtle_window.canvas.rarc(npos[0], npos[1], r, a,
+ self._heading)
+
+ if self._pen_fill:
+ if self._poly_points == []:
+ self._poly_points.append(('move', npos[0], npos[1]))
+ self._poly_points.append(('rarc', npos[0], npos[1], r,
+ (self._heading - 180) * DEGTOR,
+ (self._heading - 180 + a)
+ * DEGTOR))
+
+ self.right(a, False)
+ return [cx - r * cos(self._heading * DEGTOR),
+ cy + r * sin(self._heading * DEGTOR)]
+
+ def larc(self, a, r):
+ ''' draw a counter-clockwise arc '''
+ r *= self._turtles.turtle_window.coord_scale
+ if r < 0:
+ r = -r
+ a = -a
+ pos = self.get_xy()
+ cx = pos[0] - r * cos(self._heading * DEGTOR)
+ cy = pos[1] + r * sin(self._heading * DEGTOR)
+ if self._pen_state:
+ npos = self._turtles.turtle_to_screen_coordinates((cx, cy))
+ self._turtles.turtle_window.canvas.larc(npos[0], npos[1], r, a,
+ self._heading)
+
+ if self._pen_fill:
+ if self._poly_points == []:
+ self._poly_points.append(('move', npos[0], npos[1]))
+ self._poly_points.append(('larc', npos[0], npos[1], r,
+ (self._heading) * DEGTOR,
+ (self._heading - a) * DEGTOR))
+
+ self.right(-a, False)
+ return [cx + r * cos(self._heading * DEGTOR),
+ cy - r * sin(self._heading * DEGTOR)]
+
+ def draw_pixbuf(self, pixbuf, a, b, x, y, w, h, path, share=True):
+ ''' Draw a pixbuf '''
+
+ self._turtles.turtle_window.canvas.draw_pixbuf(
+ pixbuf, a, b, x, y, w, h, self._heading)
+
+ if self._turtles.turtle_window.sharing() and share:
+ if self._turtles.turtle_window.running_sugar:
+ tmp_path = get_path(self._turtles.turtle_window.activity,
+ 'instance')
+ else:
+ tmp_path = '/tmp'
+ tmp_file = os.path.join(
+ get_path(self._turtles.turtle_window.activity, 'instance'),
+ 'tmpfile.png')
+ pixbuf.save(tmp_file, 'png', {'quality': '100'})
+ data = image_to_base64(tmp_file, tmp_path)
+ height = pixbuf.get_height()
+ width = pixbuf.get_width()
+
+ pos = self._turtles.screen_to_turtle_coordinates((x, y))
+
+ event = 'P|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ [round_int(a), round_int(b),
+ round_int(pos[0]),
+ round_int(pos[1]),
+ round_int(w), round_int(h),
+ round_int(width),
+ round_int(height),
+ data]]))
+ gobject.idle_add(self._turtles.turtle_window.send_event, event)
+
+ os.remove(tmp_file)
+
+ def draw_text(self, label, x, y, size, w, share=True):
+ ''' Draw text '''
+ self._turtles.turtle_window.canvas.draw_text(
+ label, x, y, size, w, self._heading,
+ self._turtles.turtle_window.coord_scale)
+
+ if self._turtles.turtle_window.sharing() and share:
+ event = 'W|%s' % (data_to_string([self._turtles.turtle_window.nick,
+ [label, round_int(x),
+ round_int(y), round_int(size),
+ round_int(w)]]))
+ self._turtles.turtle_window.send_event(event)
def get_name(self):
- ''' return turtle name (key) '''
- return self.name
+ return self._name
def get_xy(self):
- """ Return the turtle's x, y coordinates. """
- return(self.x, self.y)
+ return [self._x, self._y]
+
+ def get_x(self):
+ return self._x
+
+ def get_y(self):
+ return self._y
def get_heading(self):
- """ Return the turtle's heading. """
- return(self.heading)
+ return self._heading
def get_color(self):
- """ Return the turtle's color. """
- return(self.pen_color)
+ return self._pen_color
def get_gray(self):
- """ Return the turtle's gray level. """
- return(self.pen_gray)
+ return self._pen_gray
def get_shade(self):
- """ Return the turtle's shade. """
- return(self.pen_shade)
+ return self._pen_shade
def get_pen_size(self):
- """ Return the turtle's pen size. """
- return(self.pen_size)
+ return self._pen_size
def get_pen_state(self):
- """ Return the turtle's pen state. """
- return(self.pen_state)
+ return self._pen_state
+
+ def get_fill(self):
+ return self._pen_fill
+
+ def get_poly_points(self):
+ return self._poly_points
+
+ def get_pixel(self):
+ pos = self._turtles.turtle_to_screen_coordinates(self.get_xy())
+ return self._turtles.turtle_window.canvas.get_pixel(pos[0], pos[1])
+
+ def get_drag_radius(self):
+ if self._drag_radius is None:
+ self._calculate_sizes()
+ return self._drag_radius
diff --git a/TurtleArt/tautils.py b/TurtleArt/tautils.py
index 345fb22..07b72d9 100644
--- a/TurtleArt/tautils.py
+++ b/TurtleArt/tautils.py
@@ -22,7 +22,11 @@
import gtk
import gobject
-import gconf
+try:
+ import gconf
+ HAS_GCONF = True
+except ImportError:
+ HAS_GCONF = False
import dbus
import cairo
import pickle
@@ -877,6 +881,9 @@ def power_manager_off(status):
power_manager_off(True) --> Disable power manager
power_manager_off(False) --> Use custom power manager
'''
+ if not HAS_GCONF:
+ return
+
global FIRST_TIME
OHM_SERVICE_NAME = 'org.freedesktop.ohm'
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py
index 5b0c3e0..6b14abf 100644
--- a/TurtleArt/tawindow.py
+++ b/TurtleArt/tawindow.py
@@ -99,9 +99,14 @@ _MACROS_SUBPATH = 'macros'
class TurtleArtWindow():
''' TurtleArt Window class abstraction '''
- def __init__(self, canvas_window, path, parent=None,
+ def __init__(self, canvas_window, path, parent=None, activity=None,
mycolors=None, mynick=None, turtle_canvas=None,
- running_sugar=True):
+ running_sugar=True, running_turtleart=True):
+ '''parent -- the GTK Window that TA runs in
+ activity -- the object that instantiated this TurtleArtWindow (in
+ GNOME, a TurtleMain instance)
+ running_turtleart -- are we running TA or exported python code?
+ '''
self.parent = parent
self.turtle_canvas = turtle_canvas
self._loaded_project = ''
@@ -111,6 +116,7 @@ class TurtleArtWindow():
self.gst_available = _GST_AVAILABLE
self.running_sugar = False
self.nick = None
+ self.running_turtleart = running_turtleart
if isinstance(canvas_window, gtk.DrawingArea):
self.interactive_mode = True
self.window = canvas_window
@@ -135,8 +141,13 @@ class TurtleArtWindow():
self.interactive_mode = False
self.window = canvas_window
self.running_sugar = False
- self.activity = parent
+ if activity is not None:
+ self.activity = activity
+ else:
+ self.activity = parent
+
+ # loading and saving
self.path = path
self.load_save_folder = os.path.join(path, 'samples')
self.py_load_save_folder = os.path.join(path, 'pysamples')
@@ -144,6 +155,8 @@ class TurtleArtWindow():
self.used_block_list = [] # Which blocks has the user used?
self.save_folder = None
self.save_file_name = None
+
+ # dimensions
self.width = gtk.gdk.screen_width()
self.height = gtk.gdk.screen_height()
self.rect = gtk.gdk.Rectangle(0, 0, 0, 0)
@@ -166,6 +179,7 @@ class TurtleArtWindow():
self.sharing_blocks = False
self.deleting_blocks = False
+ # find out which character to use as decimal point
try:
locale.setlocale(locale.LC_NUMERIC, '')
except locale.Error:
@@ -174,8 +188,8 @@ class TurtleArtWindow():
if self.decimal_point == '' or self.decimal_point is None:
self.decimal_point = '.'
+ # settings that depend on the hardware
self.orientation = HORIZONTAL_PALETTE
-
self.hw = get_hardware()
self.lead = 1.0
if self.hw in (XO1, XO15, XO175, XO4):
@@ -200,8 +214,9 @@ class TurtleArtWindow():
self.nop = 'nop'
self.loaded = 0
self.step_time = 0
- self.hide = False
- self.palette = True
+ # show/ hide palettes depending on whether we're running in TA or not
+ self.hide = not self.running_turtleart
+ self.palette = self.running_turtleart
self.coord_scale = 1
self.buddies = []
self._saved_string = ''
@@ -239,6 +254,7 @@ class TurtleArtWindow():
self.turtle_movement_to_share = None
self.paste_offset = 20 # Don't paste on top of where you copied.
+ # common properties of all blocks (font size, decimal point, ...)
self.block_list = Blocks(font_scale_factor=self.scale,
decimal_point=self.decimal_point)
if self.interactive_mode:
@@ -246,49 +262,69 @@ class TurtleArtWindow():
else:
self.sprite_list = None
+ # canvas object that supports the basic drawing functionality
self.canvas = TurtleGraphics(self, self.width, self.height)
if self.hw == XO175 and self.canvas.width == 1024:
self.hw = XO30
if self.interactive_mode:
self.sprite_list.set_cairo_context(self.canvas.canvas)
- self.turtles = Turtles(self.sprite_list)
- if self.nick is None:
- self.default_turtle_name = DEFAULT_TURTLE
- else:
- self.default_turtle_name = self.nick
+ self.turtles = Turtles(self)
+ if self.nick is not None:
+ self.turtles.set_default_turtle_name(self.nick)
if mycolors is None:
- Turtle(self.turtles, self.default_turtle_name)
+ Turtle(self.turtles, self.turtles.get_default_turtle_name())
else:
- Turtle(self.turtles, self.default_turtle_name, mycolors.split(','))
- self.active_turtle = self.turtles.get_turtle(self.default_turtle_name)
- self.active_turtle.show()
+ Turtle(self.turtles, self.turtles.get_default_turtle_name(),
+ mycolors.split(','))
+ self.turtles.set_active_turtle(
+ self.turtles.get_turtle(self.turtles.get_default_turtle_name()))
+ self.turtles.get_active_turtle().show()
self.canvas.clearscreen(False)
self._configure_cb(None)
self._icon_paths = [os.path.join(self.path, 'icons')]
- self.turtleart_plugins = []
- self._init_plugins()
self.lc = LogoCode(self)
- from tabasics import Palettes
- Palettes(self)
- self._setup_plugins()
+ self.turtleart_plugins = []
+ self.saved_pictures = []
+ self.block_operation = ''
+
+ # only in TA: setup basic palettes
+ if self.running_turtleart:
+ from tabasics import Palettes
+ self._basic_palettes = Palettes(self)
if self.interactive_mode:
- self._setup_misc()
+ gobject.idle_add(self._lazy_init)
+ else:
+ self._init_plugins()
+ self._setup_plugins()
+
+ def _lazy_init(self):
+ self._init_plugins()
+ self._setup_plugins()
+ self._setup_misc()
+
+ if self.running_turtleart:
+ self._basic_palettes.make_trash_palette()
for name in palette_init_on_start:
debug_output('initing palette %s' % (name), self.running_sugar)
self.show_toolbar_palette(palette_names.index(name),
- init_only=False, regenerate=True,
+ init_only=False,
+ regenerate=True,
show=False)
- self.show_toolbar_palette(0, init_only=False, regenerate=True,
+
+ self.show_toolbar_palette(0,
+ init_only=False,
+ regenerate=True,
show=True)
- self.saved_pictures = []
- self.block_operation = ''
+
+ if self.running_sugar:
+ self.activity.check_buttons_for_fit()
def _set_screen_dpi(self):
dpi = get_screen_dpi()
@@ -318,7 +354,7 @@ class TurtleArtWindow():
pname = os.path.join(path, dirname, dirname + '.py')
if os.path.exists(pname):
plugin_files.append(dirname)
- return plugin_files
+ return plugin_files
def _init_plugins(self):
''' Try importing plugin files from the plugin dir. '''
@@ -502,7 +538,7 @@ class TurtleArtWindow():
self.overlay_shapes[name].hide()
self.overlay_shapes[name].type = 'overlay'
- if not self.running_sugar:
+ if self.running_turtleart and not self.running_sugar:
# offset = 2 * self.width - 55 * len(TOOLBAR_SHAPES)
offset = 55 * (1 + len(palette_blocks))
for i, name in enumerate(TOOLBAR_SHAPES):
@@ -673,21 +709,26 @@ class TurtleArtWindow():
def draw_overlay(self, overlay):
''' Draw a coordinate grid onto the canvas. '''
- save_heading = self.canvas.heading
- self.canvas.heading = 0
- w = self.overlay_shapes[overlay].rect[2]
- h = self.overlay_shapes[overlay].rect[3]
+ width = self.overlay_shapes[overlay].rect[2]
+ height = self.overlay_shapes[overlay].rect[3]
+ if self.running_sugar:
+ y_offset = 0
+ else:
+ y_offset = ICON_SIZE
self.canvas.draw_surface(
self.overlay_shapes[overlay].cached_surfaces[0],
- (self.canvas.width - w) / 2.,
- (self.canvas.height - h) / 2., w, h)
- self.canvas.heading = save_heading
+ (self.canvas.width - width) / 2.0,
+ (self.canvas.height - height + y_offset) / 2.0,
+ width,
+ height)
def update_overlay_position(self, widget, event):
''' Reposition the overlays when window size changes '''
self.width = event.width
self.height = event.height
for name in OVERLAY_SHAPES:
+ if not name in self.overlay_shapes:
+ continue
shape = self.overlay_shapes[name]
showing = False
if shape in shape._sprites.list:
@@ -709,7 +750,7 @@ class TurtleArtWindow():
self.metric = False
self.canvas.width = self.width
self.canvas.height = self.height
- self.canvas.move_turtle()
+ self.turtles.get_active_turtle().move_turtle()
def hideshow_button(self):
''' Hide/show button '''
@@ -922,7 +963,7 @@ class TurtleArtWindow():
self.running_sugar)
else:
blk.spr.hide()
- if n == palette_names.index('trash'):
+ if 'trash' in palette_names and n == palette_names.index('trash'):
for blk in self.trash_stack:
# Deprecated
for gblk in find_group(blk):
@@ -1198,7 +1239,8 @@ class TurtleArtWindow():
and not self.activity.has_toolbarbox:
self.activity.palette_buttons[palette].set_icon(
palette_names[palette] + 'off')
- if palette == palette_names.index('trash'):
+ if 'trash' in palette_names and \
+ palette == palette_names.index('trash'):
for blk in self.trash_stack:
for gblk in find_group(blk):
gblk.spr.hide()
@@ -1278,7 +1320,8 @@ class TurtleArtWindow():
if self.orientation == HORIZONTAL_PALETTE:
x, y = _BUTTON_SIZE, self.toolbar_offset + _MARGIN
x, y, max_w = self._horizontal_layout(x, y, self.palettes[n])
- if n == palette_names.index('trash'):
+ if 'trash' in palette_names and \
+ n == palette_names.index('trash'):
x, y, max_w = self._horizontal_layout(x + max_w, y,
self.trash_stack)
w = x + max_w + _BUTTON_SIZE + _MARGIN
@@ -1294,7 +1337,8 @@ class TurtleArtWindow():
else:
x, y = _MARGIN, self.toolbar_offset + _BUTTON_SIZE + _MARGIN
x, y, max_h = self._vertical_layout(x, y, self.palettes[n])
- if n == palette_names.index('trash'):
+ if 'trash' in palette_names and \
+ n == palette_names.index('trash'):
x, y, max_h = self._vertical_layout(x, y + max_h,
self.trash_stack)
h = y + max_h + _BUTTON_SIZE + _MARGIN - self.toolbar_offset
@@ -1339,7 +1383,8 @@ class TurtleArtWindow():
'category-shift-vertical'
else:
self.palette_sprs[n][self.orientation].type = 'category'
- if n == palette_names.index('trash'):
+ if 'trash' in palette_names and \
+ n == palette_names.index('trash'):
svg = SVG()
self.palette_sprs[n][self.orientation].set_shape(
svg_str_to_pixbuf(svg.palette(w, h)))
@@ -1672,13 +1717,13 @@ before making changes to your Turtle Blocks program'))
def _look_for_a_turtle(self, spr, x, y):
# Next, look for a turtle
- t = self.turtles.spr_to_turtle(spr)
- if t is not None:
+ turtle = self.turtles.spr_to_turtle(spr)
+ if turtle is not None:
# If turtle is shared, ignore click
- if self.remote_turtle(t.get_name()):
+ if self.remote_turtle(turtle.get_name()):
return True
- self.selected_turtle = t
- self.canvas.set_turtle(self.turtles.get_turtle_key(t))
+ self.selected_turtle = turtle
+ self.turtles.set_turtle(self.turtles.get_turtle_key(turtle))
self._turtle_pressed(x, y)
self.update_counter = 0
return True
@@ -1919,7 +1964,8 @@ before making changes to your Turtle Blocks program'))
if gblk.name in BLOCKS_WITH_SKIN:
self._resize_skin(gblk)
- if self.selected_palette != palette_names.index('trash'):
+ if not 'trash' in palette_names or \
+ self.selected_palette != palette_names.index('trash'):
for gblk in group:
gblk.spr.hide()
@@ -2390,20 +2436,22 @@ before making changes to your Turtle Blocks program'))
self._adjust_dock_positions(c)
def _turtle_pressed(self, x, y):
- (tx, ty) = self.selected_turtle.get_xy()
- w = self.selected_turtle.spr.rect.width / 2
- h = self.selected_turtle.spr.rect.height / 2
- dx = x - tx - w
- dy = y - ty - h
- # if x, y is near the edge, rotate
+ pos = self.selected_turtle.get_xy()
+ tpos = self.turtles.turtle_to_screen_coordinates(pos)
+ dx = x - tpos[0]
+ dy = y - tpos[1]
if not hasattr(self.lc, 'value_blocks'):
self.lc.find_value_blocks()
self.lc.update_values = True
- if (dx * dx) + (dy * dy) > ((w * w) + (h * h)) / 6:
- self.drag_turtle = \
- ('turn', self.canvas.heading - atan2(dy, dx) / DEGTOR, 0)
+ # Compare distance squared of drag position to sprite radius.
+ # If x, y is near the edge, rotate.
+ if (dx * dx) + (dy * dy) > self.selected_turtle.get_drag_radius():
+ self.drag_turtle = (
+ 'turn',
+ self.selected_turtle.get_heading() - atan2(dy, dx) / DEGTOR,
+ 0)
else:
- self.drag_turtle = ('move', x - tx, y - ty)
+ self.drag_turtle = ('move', x - tpos[0], y - tpos[1])
def _move_cb(self, win, event):
x, y = xy(event)
@@ -2416,18 +2464,18 @@ before making changes to your Turtle Blocks program'))
''' Share turtle movement and rotation after button up '''
if self.sharing():
nick = self.turtle_movement_to_share.get_name()
- self.send_event("r|%s" %
- (data_to_string([nick,
- round_int(self.canvas.heading)])))
- if self.canvas.pendown:
+ self.send_event("r|%s" % (data_to_string(
+ [nick,
+ round_int(self.turtles.get_active_turtle().get_heading())])))
+ if self.turtles.get_active_turtle().get_pen_state():
self.send_event('p|%s' % (data_to_string([nick, False])))
put_pen_back_down = True
else:
put_pen_back_down = False
- self.send_event("x|%s" %
- (data_to_string([nick,
- [round_int(self.canvas.xcor),
- round_int(self.canvas.ycor)]])))
+ self.send_event("x|%s" % (data_to_string(
+ [nick,
+ [round_int(self.turtles.get_active_turtle().get_xy()[0]),
+ round_int(self.turtles.get_active_turtle().get_xy()[1])]])))
if put_pen_back_down:
self.send_event('p|%s' % (data_to_string([nick, True])))
self.turtle_movement_to_share = None
@@ -2454,34 +2502,37 @@ before making changes to your Turtle Blocks program'))
# First, check to see if we are dragging or rotating a turtle.
if self.selected_turtle is not None:
- dtype, dragx, dragy = self.drag_turtle
- (sx, sy) = self.selected_turtle.get_xy()
- # self.canvas.set_turtle(self.selected_turtle.get_name())
+ drag_type, dragx, dragy = self.drag_turtle
self.update_counter += 1
- if dtype == 'move':
- dx = x - dragx - sx + self.selected_turtle.spr.rect.width / 2
- dy = y - dragy - sy + self.selected_turtle.spr.rect.height / 2
+ if drag_type == 'move':
+ dx = x - dragx
+ dy = y - dragy
self.selected_turtle.spr.set_layer(TOP_LAYER)
- tx, ty = self.canvas.screen_to_turtle_coordinates(sx + dx,
- sy + dy)
- if self.canvas.pendown:
- self.canvas.setpen(False)
- self.canvas.setxy(tx, ty, share=False)
- self.canvas.setpen(True)
+ pos = self.turtles.screen_to_turtle_coordinates((dx, dy))
+ if self.selected_turtle.get_pen_state():
+ self.selected_turtle.set_pen_state(False)
+ self.selected_turtle.set_xy(pos, share=False)
+ self.selected_turtle.set_pen_state(True)
else:
- self.canvas.setxy(tx, ty, share=False)
+ self.selected_turtle.set_xy(pos, share=False)
if self.update_counter % 5:
self.lc.update_label_value(
- 'xcor', self.canvas.xcor / self.coord_scale)
+ 'xcor', self.selected_turtle.get_xy()[0] /
+ self.coord_scale)
self.lc.update_label_value(
- 'ycor', self.canvas.ycor / self.coord_scale)
+ 'ycor', self.selected_turtle.get_xy()[1] /
+ self.coord_scale)
else:
- dx = x - sx - self.selected_turtle.spr.rect.width / 2
- dy = y - sy - self.selected_turtle.spr.rect.height / 2
- self.canvas.seth(int(dragx + atan2(dy, dx) / DEGTOR + 5) /
- 10 * 10, share=False)
+ spos = self.turtles.turtle_to_screen_coordinates(
+ self.selected_turtle.get_xy())
+ dx = x - spos[0]
+ dy = y - spos[1]
+ self.turtles.get_active_turtle().set_heading(
+ int(dragx + atan2(dy, dx) / DEGTOR + 5) / 10 * 10,
+ share=False)
if self.update_counter % 5:
- self.lc.update_label_value('heading', self.canvas.heading)
+ self.lc.update_label_value(
+ 'heading', self.selected_turtle.get_heading())
if self.update_counter % 20:
self.display_coordinates()
self.turtle_movement_to_share = self.selected_turtle
@@ -2638,30 +2689,26 @@ before making changes to your Turtle Blocks program'))
# We may have been moving the turtle
if self.selected_turtle is not None:
- (tx, ty) = self.selected_turtle.get_xy()
- k = self.turtles.get_turtle_key(self.selected_turtle)
-
+ pos = self.selected_turtle.get_xy()
+ spos = self.turtles.turtle_to_screen_coordinates(pos)
+ turtle_name = self.turtles.get_turtle_key(self.selected_turtle)
# Remove turtles by dragging them onto the trash palette.
- if self._in_the_trash(tx, ty):
+ if self._in_the_trash(spos[0], spos[1]):
# If it is the default turtle, just recenter it.
- if k == self.default_turtle_name:
+ if turtle_name == self.turtles.get_default_turtle_name():
self._move_turtle(0, 0)
- self.canvas.heading = 0
- self.canvas.turn_turtle()
- self.lc.update_label_value('heading', self.canvas.heading)
+ self.selected_turtle.set_heading(0)
+ self.lc.update_label_value('heading', 0)
else:
self.selected_turtle.hide()
- self.turtles.remove_from_dict(k)
- self.active_turtle = None
+ self.turtles.remove_from_dict(turtle_name)
+ self.turtles.set_active_turtle(None)
else:
- self._move_turtle(
- tx - self.canvas.width / 2. +
- self.active_turtle.spr.rect.width / 2.,
- self.canvas.height / 2. - ty -
- self.active_turtle.spr.rect.height / 2.)
+ self._move_turtle(pos[0], pos[1])
+
self.selected_turtle = None
- if self.active_turtle is None:
- self.canvas.set_turtle(self.default_turtle_name)
+ if self.turtles.get_active_turtle() is None:
+ self.turtles.set_turtle(self.turtles.get_default_turtle_name())
self.display_coordinates()
return
@@ -2737,21 +2784,23 @@ before making changes to your Turtle Blocks program'))
turtle.label_block.spr.set_label(name[0:4] + '…')
else:
turtle.label_block.spr.set_label(name)
+ turtle.set_remote()
turtle.show()
def _move_turtle(self, x, y):
''' Move the selected turtle to (x, y). '''
- self.canvas.xcor = x
- self.canvas.ycor = y
- self.canvas.move_turtle()
+ if self.drag_turtle[0] == 'move':
+ self.turtles.get_active_turtle().move_turtle((x, y))
if self.interactive_mode:
self.display_coordinates()
if self.running_sugar:
self.selected_turtle.spr.set_layer(TURTLE_LAYER)
- self.lc.update_label_value('xcor',
- self.canvas.xcor / self.coord_scale)
- self.lc.update_label_value('ycor',
- self.canvas.ycor / self.coord_scale)
+ self.lc.update_label_value(
+ 'xcor', self.turtles.get_active_turtle().get_xy()[0] /
+ self.coord_scale)
+ self.lc.update_label_value(
+ 'ycor', self.turtles.get_active_turtle().get_xy()[1] /
+ self.coord_scale)
def _click_block(self, x, y):
''' Click block: lots of special cases to handle... '''
@@ -3023,10 +3072,8 @@ before making changes to your Turtle Blocks program'))
if blk is None:
return
self.lc.find_value_blocks() # Are there blocks to update?
- # Is there a savesvg block?
- if len(self.block_list.get_similar_blocks('block', 'savesvg')) > 0:
- if self.canvas.cr_svg is None:
- self.canvas.setup_svg_surface()
+ if self.canvas.cr_svg is None:
+ self.canvas.setup_svg_surface()
self.running_blocks = True
self._start_plugins() # Let the plugins know we are running.
top = find_top_block(blk)
@@ -3506,13 +3553,15 @@ before making changes to your Turtle Blocks program'))
def _jog_turtle(self, dx, dy):
''' Jog turtle '''
if dx == -1 and dy == -1:
- self.canvas.xcor = 0
- self.canvas.ycor = 0
+ x = 0
+ y = 0
else:
- self.canvas.xcor += dx
- self.canvas.ycor += dy
- self.active_turtle = self.turtles.spr_to_turtle(self.selected_spr)
- self.canvas.move_turtle()
+ pos = self.turtles.get_active_turtle().get_xy()
+ x = pos[0] + dx
+ y = pos[1] + dy
+ self.turtles.set_active_turtle(
+ self.turtles.spr_to_turtle(self.selected_spr))
+ self.turtles.get_active_turtle().move_turtle((x, y))
self.display_coordinates()
self.selected_turtle = None
@@ -3678,8 +3727,8 @@ before making changes to your Turtle Blocks program'))
if add_new_block:
# add a new block for this code at turtle position
- (tx, ty) = self.active_turtle.get_xy()
- self._new_block('userdefined', tx, ty)
+ pos = self.turtles.get_active_turtle().get_xy()
+ self._new_block('userdefined', pos[0], pos[1])
self.myblock[self.block_list.list.index(self.drag_group[0])] =\
self.python_code
self.set_userdefined(self.drag_group[0])
@@ -3725,7 +3774,6 @@ before making changes to your Turtle Blocks program'))
if self.running_sugar:
chooser_dialog(self.parent, 'org.laptop.Pippy',
self.load_python_code_from_journal)
- dsobject.destroy()
else:
self.load_python_code_from_file(fname=None, add_new_block=False)
@@ -3805,12 +3853,13 @@ before making changes to your Turtle Blocks program'))
def load_turtle(self, blk, key=1):
''' Restore a turtle from its saved state '''
tid, name, xcor, ycor, heading, color, shade, pensize = blk
- self.canvas.set_turtle(key)
- self.canvas.setxy(xcor, ycor, pendown=False)
- self.canvas.seth(heading)
- self.canvas.setcolor(color)
- self.canvas.setshade(shade)
- self.canvas.setpensize(pensize)
+ self.turtles.set_turtle(key)
+ self.turtles.get_active_turtle().set_xy(xcor, ycor, pendown=False)
+ self.turtles.get_active_turtle().set_heading(heading)
+ self.turtles.get_active_turtle().set_color(color)
+ self.turtles.get_active_turtle().set_shade(shade)
+ self.turtles.get_active_turtle().set_gray(100)
+ self.turtles.get_active_turtle().set_pen_size(pensize)
def load_block(self, b, offset=0):
''' Restore individual blocks from saved state '''
@@ -3913,8 +3962,8 @@ before making changes to your Turtle Blocks program'))
btype = OLD_NAMES[btype]
blk = Block(self.block_list, self.sprite_list, btype,
- b[2] + self.canvas.cx + offset,
- b[3] + self.canvas.cy + offset,
+ b[2] + offset,
+ b[3] + offset,
'block', values, self.block_scale)
# If it was an unknown block type, we need to match the number
@@ -4078,9 +4127,10 @@ before making changes to your Turtle Blocks program'))
def load_start(self, ta_file=None):
''' Start a new project with a 'start' brick '''
if ta_file is None:
- self.process_data([[0, "start", PALETTE_WIDTH + 20,
- self.toolbar_offset + PALETTE_HEIGHT + 20,
- [None, None]]])
+ self.process_data(
+ [[0, "start", PALETTE_WIDTH + 20,
+ self.toolbar_offset + PALETTE_HEIGHT + 20 + ICON_SIZE,
+ [None, None]]])
else:
self.process_data(data_from_file(ta_file))
@@ -4147,8 +4197,7 @@ before making changes to your Turtle Blocks program'))
if not save_project:
sx += 20
sy += 20
- data.append((blk.id, name, sx - self.canvas.cx,
- sy - self.canvas.cy, connections))
+ data.append((blk.id, name, sx, sy, connections))
if save_turtle:
for turtle in iter(self.turtles.dict):
# Don't save remote turtles
@@ -4156,12 +4205,15 @@ before making changes to your Turtle Blocks program'))
# Save default turtle as 'Yertle'
if turtle == self.nick:
turtle = DEFAULT_TURTLE
+ pos = self.turtles.get_active_turtle().get_xy()
data.append(
(-1,
['turtle', turtle],
- self.canvas.xcor, self.canvas.ycor,
- self.canvas.heading, self.canvas.color,
- self.canvas.shade, self.canvas.pensize))
+ pos[0], pos[1],
+ self.turtles.get_active_turtle().get_heading(),
+ self.turtles.get_active_turtle().get_color(),
+ self.turtles.get_active_turtle().get_shade(),
+ self.turtles.get_active_turtle().get_pen_size()))
return data
def display_coordinates(self, clear=False):
@@ -4173,9 +4225,11 @@ before making changes to your Turtle Blocks program'))
elif self.interactive_mode:
self.parent.set_title('')
else:
- x = round_int(float(self.canvas.xcor) / self.coord_scale)
- y = round_int(float(self.canvas.ycor) / self.coord_scale)
- h = round_int(self.canvas.heading)
+ x = round_int(float(self.turtles.get_active_turtle().get_xy()[0]) /
+ self.coord_scale)
+ y = round_int(float(self.turtles.get_active_turtle().get_xy()[1]) /
+ self.coord_scale)
+ h = round_int(self.turtles.get_active_turtle().get_heading())
if self.running_sugar:
if int(x) == x and int(y) == y and int(h) == h:
formatting = '(%d, %d) %d'
@@ -4556,7 +4610,7 @@ variable'))
raise logoerror("#emptybox")
def _prim_setbox(self, name, x, val):
- """ Define value of named box """
+ ''' Define value of named box '''
if x is not None:
if isinstance(convert(x, float, False), float):
if int(float(x)) == x:
diff --git a/challenges/confusion-1.svg b/challenges/confusion-01.svg
index d46a36b..d46a36b 100644
--- a/challenges/confusion-1.svg
+++ b/challenges/confusion-01.svg
diff --git a/challenges/confusion-2.svg b/challenges/confusion-02.svg
index 61b3bdd..61b3bdd 100644
--- a/challenges/confusion-2.svg
+++ b/challenges/confusion-02.svg
diff --git a/challenges/confusion-3.svg b/challenges/confusion-03.svg
index eddd464..eddd464 100644
--- a/challenges/confusion-3.svg
+++ b/challenges/confusion-03.svg
diff --git a/challenges/confusion-4.svg b/challenges/confusion-04.svg
index 97cdcc3..97cdcc3 100644
--- a/challenges/confusion-4.svg
+++ b/challenges/confusion-04.svg
diff --git a/challenges/confusion-5.svg b/challenges/confusion-05.svg
index f5c766d..f5c766d 100644
--- a/challenges/confusion-5.svg
+++ b/challenges/confusion-05.svg
diff --git a/challenges/confusion-6.svg b/challenges/confusion-06.svg
index bf84aba..bf84aba 100644
--- a/challenges/confusion-6.svg
+++ b/challenges/confusion-06.svg
diff --git a/challenges/confusion-7.svg b/challenges/confusion-07.svg
index f8d90c2..f8d90c2 100644
--- a/challenges/confusion-7.svg
+++ b/challenges/confusion-07.svg
diff --git a/challenges/confusion-8.svg b/challenges/confusion-08.svg
index 6cb6454..6cb6454 100644
--- a/challenges/confusion-8.svg
+++ b/challenges/confusion-08.svg
diff --git a/challenges/confusion-9.svg b/challenges/confusion-09.svg
index d6d3d08..d6d3d08 100644
--- a/challenges/confusion-9.svg
+++ b/challenges/confusion-09.svg
diff --git a/challenges/help-1.ta b/challenges/help-confusion-01.ta
index cfc47bf..cfc47bf 100644
--- a/challenges/help-1.ta
+++ b/challenges/help-confusion-01.ta
diff --git a/challenges/help-2.ta b/challenges/help-confusion-02.ta
index 869b88c..869b88c 100644
--- a/challenges/help-2.ta
+++ b/challenges/help-confusion-02.ta
diff --git a/challenges/help-3.ta b/challenges/help-confusion-03.ta
index 4c58755..4c58755 100644
--- a/challenges/help-3.ta
+++ b/challenges/help-confusion-03.ta
diff --git a/challenges/help-4.ta b/challenges/help-confusion-04.ta
index cfc47bf..cfc47bf 100644
--- a/challenges/help-4.ta
+++ b/challenges/help-confusion-04.ta
diff --git a/challenges/help-5.ta b/challenges/help-confusion-05.ta
index 0c2514a..0c2514a 100644
--- a/challenges/help-5.ta
+++ b/challenges/help-confusion-05.ta
diff --git a/challenges/help-6.ta b/challenges/help-confusion-06.ta
index 1e16e88..1e16e88 100644
--- a/challenges/help-6.ta
+++ b/challenges/help-confusion-06.ta
diff --git a/challenges/help-7.ta b/challenges/help-confusion-07.ta
index e2ac8d1..e2ac8d1 100644
--- a/challenges/help-7.ta
+++ b/challenges/help-confusion-07.ta
diff --git a/challenges/help-8.ta b/challenges/help-confusion-08.ta
index 10bb958..10bb958 100644
--- a/challenges/help-8.ta
+++ b/challenges/help-confusion-08.ta
diff --git a/challenges/help-9.ta b/challenges/help-confusion-09.ta
index 010e379..010e379 100644
--- a/challenges/help-9.ta
+++ b/challenges/help-confusion-09.ta
diff --git a/challenges/help-10.ta b/challenges/help-confusion-10.ta
index 9572d85..9572d85 100644
--- a/challenges/help-10.ta
+++ b/challenges/help-confusion-10.ta
diff --git a/challenges/help-11.ta b/challenges/help-confusion-11.ta
index b10aa82..b10aa82 100644
--- a/challenges/help-11.ta
+++ b/challenges/help-confusion-11.ta
diff --git a/challenges/help-12.ta b/challenges/help-confusion-12.ta
index a7b5280..a7b5280 100644
--- a/challenges/help-12.ta
+++ b/challenges/help-confusion-12.ta
diff --git a/challenges/help-13.ta b/challenges/help-confusion-13.ta
index bb063d9..bb063d9 100644
--- a/challenges/help-13.ta
+++ b/challenges/help-confusion-13.ta
diff --git a/challenges/help-14.ta b/challenges/help-confusion-14.ta
index 31f378f..31f378f 100644
--- a/challenges/help-14.ta
+++ b/challenges/help-confusion-14.ta
diff --git a/challenges/help-15.ta b/challenges/help-confusion-15.ta
index 5272264..5272264 100644
--- a/challenges/help-15.ta
+++ b/challenges/help-confusion-15.ta
diff --git a/challenges/help-16.ta b/challenges/help-confusion-16.ta
index 18932fb..18932fb 100644
--- a/challenges/help-16.ta
+++ b/challenges/help-confusion-16.ta
diff --git a/challenges/help-17.ta b/challenges/help-confusion-17.ta
index ebbf81e..ebbf81e 100644
--- a/challenges/help-17.ta
+++ b/challenges/help-confusion-17.ta
diff --git a/challenges/help-18.ta b/challenges/help-confusion-18.ta
index 86223a4..86223a4 100644
--- a/challenges/help-18.ta
+++ b/challenges/help-confusion-18.ta
diff --git a/challenges/help-19.ta b/challenges/help-confusion-19.ta
index 23ed84b..23ed84b 100644
--- a/challenges/help-19.ta
+++ b/challenges/help-confusion-19.ta
diff --git a/challenges/help-20.ta b/challenges/help-confusion-20.ta
index 65e070b..65e070b 100644
--- a/challenges/help-20.ta
+++ b/challenges/help-confusion-20.ta
diff --git a/challenges/help-21.ta b/challenges/help-confusion-21.ta
index 37a7235..37a7235 100644
--- a/challenges/help-21.ta
+++ b/challenges/help-confusion-21.ta
diff --git a/challenges/help-22.ta b/challenges/help-confusion-22.ta
index c76c535..c76c535 100644
--- a/challenges/help-22.ta
+++ b/challenges/help-confusion-22.ta
diff --git a/challenges/help-23.ta b/challenges/help-confusion-23.ta
index afaf421..afaf421 100644
--- a/challenges/help-23.ta
+++ b/challenges/help-confusion-23.ta
diff --git a/challenges/help-24.ta b/challenges/help-confusion-24.ta
index 97e457f..97e457f 100644
--- a/challenges/help-24.ta
+++ b/challenges/help-confusion-24.ta
diff --git a/challenges/help-25.ta b/challenges/help-confusion-25.ta
index 06ec5b0..06ec5b0 100644
--- a/challenges/help-25.ta
+++ b/challenges/help-confusion-25.ta
diff --git a/challenges/help-26.ta b/challenges/help-confusion-26.ta
index c86e8f5..c86e8f5 100644
--- a/challenges/help-26.ta
+++ b/challenges/help-confusion-26.ta
diff --git a/challenges/help-27.ta b/challenges/help-confusion-27.ta
index 6cd8eca..6cd8eca 100644
--- a/challenges/help-27.ta
+++ b/challenges/help-confusion-27.ta
diff --git a/challenges/help-28.ta b/challenges/help-confusion-28.ta
index 2d250d1..2d250d1 100644
--- a/challenges/help-28.ta
+++ b/challenges/help-confusion-28.ta
diff --git a/challenges/help-29.ta b/challenges/help-confusion-29.ta
index c456109..c456109 100644
--- a/challenges/help-29.ta
+++ b/challenges/help-confusion-29.ta
diff --git a/challenges/help-30.ta b/challenges/help-confusion-30.ta
index aea3b89..aea3b89 100644
--- a/challenges/help-30.ta
+++ b/challenges/help-confusion-30.ta
diff --git a/challenges/help-31.ta b/challenges/help-confusion-31.ta
index 6d518e2..6d518e2 100644
--- a/challenges/help-31.ta
+++ b/challenges/help-confusion-31.ta
diff --git a/challenges/help-32.ta b/challenges/help-confusion-32.ta
index 79607bb..79607bb 100644
--- a/challenges/help-32.ta
+++ b/challenges/help-confusion-32.ta
diff --git a/challenges/help-33.ta b/challenges/help-confusion-33.ta
index 7e1ecdc..7e1ecdc 100644
--- a/challenges/help-33.ta
+++ b/challenges/help-confusion-33.ta
diff --git a/challenges/help-34.ta b/challenges/help-confusion-34.ta
index 7e1ecdc..7e1ecdc 100644
--- a/challenges/help-34.ta
+++ b/challenges/help-confusion-34.ta
diff --git a/challenges/help-35.ta b/challenges/help-confusion-35.ta
index a8faf26..a8faf26 100644
--- a/challenges/help-35.ta
+++ b/challenges/help-confusion-35.ta
diff --git a/challenges/help-36.ta b/challenges/help-confusion-36.ta
index b63a1c8..b63a1c8 100644
--- a/challenges/help-36.ta
+++ b/challenges/help-confusion-36.ta
diff --git a/challenges/help-37.ta b/challenges/help-confusion-37.ta
index 42513fd..42513fd 100644
--- a/challenges/help-37.ta
+++ b/challenges/help-confusion-37.ta
diff --git a/challenges/help-38.ta b/challenges/help-confusion-38.ta
index bb5a0d4..bb5a0d4 100644
--- a/challenges/help-38.ta
+++ b/challenges/help-confusion-38.ta
diff --git a/challenges/help-39.ta b/challenges/help-confusion-39.ta
index eaf5f55..eaf5f55 100644
--- a/challenges/help-39.ta
+++ b/challenges/help-confusion-39.ta
diff --git a/challenges/help-40.ta b/challenges/help-confusion-40.ta
index c79cc97..c79cc97 100644
--- a/challenges/help-40.ta
+++ b/challenges/help-confusion-40.ta
diff --git a/challenges/offsets b/challenges/offsets
index 995e3af..a3ad73e 100644
--- a/challenges/offsets
+++ b/challenges/offsets
@@ -1,35 +1,42 @@
-5:-100,0
-7:-141,-141
-10:0,-48
-11:0,-51
-12:0,-72
-13:0,-112
-14:0,-122
-15:-117,0
-16:-150,-150
-17:-100,-85
-18:-100,-100
-19:-150,-150
-20:-100,-111
-21:-100,-100
-22:-100,-100
-23:-150,-150
-24:-175,-150
-25:-75,-94
-26:-105,-125
-27:-150,-150
-28:-107,-107
-29:-155,-161
-30:-130,-152
-31:0,-50
-32:-121,-121
-33:-106,-106
-34:-100,-100
-35:-150,-150
-36:-121,-121
-37:-150,-150
-38:-106,-106
-39:-100,-100
-40:-104,-104
+01:0,0,29
+02:0,0,15
+03:0,0,29
+04:0,0,29
+05:-100,0,43
+06:0,0,29
+07:-141,-141,41
+08:0,0,22
+09:0,0,29
+10:0,-48,36
+11:0,-45,29
+12:0,-61,33
+13:0,-97,29
+14:0,-112,33
+15:-117,0,29
+16:-150,-150,43
+17:-97,-84,25
+18:-100,-100,29
+19:-150,-150,43
+20:-100,-111,33
+21:-100,-100,29
+22:-100,-100,29
+23:-150,-150,43
+24:-173,-147,43
+25:-85,-97,33
+26:-122,-142,41
+27:-150,-148,43
+28:-107,-105,31
+29:-150,-157,46
+30:-130,-147,43
+31:0,-50,33
+32:-111,-111,33
+33:-111,-111,33
+34:-110,-110,33
+35:-150,-148,43
+36:-111,-111,33
+37:-147,-147,36
+38:-114,-114,33
+39:-110,-110,33
+40:-114,-114,33
diff --git a/plugins/turtle_blocks_extras/turtle_blocks_extras.py b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
index 132848a..d78ba94 100644
--- a/plugins/turtle_blocks_extras/turtle_blocks_extras.py
+++ b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
@@ -60,8 +60,8 @@ class Turtle_blocks_extras(Plugin):
""" a class for defining the extra palettes that distinguish Turtle Blocks
from Turtle Art """
- def __init__(self, parent):
- self.tw = parent
+ def __init__(self, turtle_window):
+ self.tw = turtle_window
def setup(self):
SKIN_PATHS.append('plugins/turtle_blocks_extras/images')
@@ -123,13 +123,11 @@ boolean operators from Numbers palette'))
self.tw.lc.def_prim('clamp', 1, primitive_dictionary['clamp'], True)
def _media_palette(self):
-
palette = make_palette('flow',
colors=["#FFC000", "#A08000"],
help_string=_('Palette of flow operators'))
palette.add_block('journal',
- hidden=True,
style='box-style-media',
label=' ',
default='None',
@@ -216,22 +214,6 @@ Journal'))
lambda self, x:
primitive_dictionary['show'](x, False))
- # deprecated
- primitive_dictionary['write'] = self._prim_write
- palette.add_block('write',
- hidden=True,
- colors=["#A0FF00", "#80A000"],
- style='basic-style-1arg',
- label=_('show'),
- default=[_('text'), 32],
- prim_name='write',
- logo_command='label',
- help_string=_('draws text or show media from the \
-Journal'))
- self.tw.lc.def_prim('write', 2,
- lambda self, x, y:
- primitive_dictionary['write'](x, y))
-
primitive_dictionary['setscale'] = self._prim_setscale
palette.add_block('setscale',
hidden=True,
@@ -339,7 +321,6 @@ amplitude, and duration (in seconds)'))
primitive_dictionary['sinewave'](x, y, z))
def _sensor_palette(self):
-
palette = make_palette('flow',
colors=["#FFC000", "#A08000"],
help_string=_('Palette of flow operators'))
@@ -473,7 +454,6 @@ program started'))
lambda self: primitive_dictionary['time']())
def _extras_palette(self):
-
palette = make_palette('extras',
colors=["#FF0000", "#A00000"],
help_string=_('Palette of extra options'))
@@ -727,7 +707,7 @@ module found in the Journal'))
help_string=_('chooses which turtle to command'))
self.tw.lc.def_prim('turtle', 1,
lambda self, x:
- self.tw.canvas.set_turtle(x))
+ self.tw.turtles.set_turtle(x))
primitive_dictionary['activeturtle'] = self._prim_active_turtle
palette.add_block('activeturtle',
@@ -819,9 +799,8 @@ module found in the Journal'))
primitive_dictionary['loadpalette'](x))
def _portfolio_palette(self):
-
palette = make_palette('extras',
- colors=["#FF0000", "#A00000"],
+ colors=["#FF0000", "#FF0000"],
help_string=_('Palette of extra options'))
primitive_dictionary['hideblocks'] = self._prim_hideblocks
@@ -1024,108 +1003,13 @@ Journal objects'))
logo_command='bottomy')
self.tw.lc.def_prim('bottomy', 0, lambda self: CONSTANTS['bottomy'])
- # deprecated blocks
-
- primitive_dictionary['t1x1'] = self._prim_t1x1
- palette.add_block('template1x1',
- hidden=True,
- colors=["#0606FF", "#0606A0"],
- style='portfolio-style-1x1',
- label=' ',
- prim_name='t1x1',
- default=[_('Title'), 'None'],
- special_name=_('presentation 1x1'),
- string_or_number=True,
- help_string=_('presentation template: select \
-Journal object (with description)'))
- self.tw.lc.def_prim('t1x1', 2,
- lambda self, a, b:
- primitive_dictionary['t1x1'](a, b))
-
- primitive_dictionary['t1x1a'] = self._prim_t1x1a
- palette.add_block('template1x1a',
- hidden=True,
- colors=["#0606FF", "#0606A0"],
- style='portfolio-style-1x1',
- label=' ',
- prim_name='t1x1a',
- default=[_('Title'), 'None'],
- special_name=_('presentation 1x1'),
- string_or_number=True,
- help_string=_('presentation template: select \
-Journal object (no description)'))
- self.tw.lc.def_prim('t1x1a', 2,
- lambda self, a, b:
- primitive_dictionary['t1x1a'](a, b))
-
- primitive_dictionary['2x1'] = self._prim_t2x1
- palette.add_block('template2x1',
- hidden=True,
- colors=["#0606FF", "#0606A0"],
- style='portfolio-style-2x1',
- label=' ',
- prim_name='t2x1',
- default=[_('Title'), 'None', 'None'],
- special_name=_('presentation 2x1'),
- string_or_number=True,
- help_string=_("presentation template: select two \
-Journal objects"))
- self.tw.lc.def_prim('t2x1', 3,
- lambda self, a, b, c:
- primitive_dictionary['t2x1'](a, b, c))
-
- primitive_dictionary['1x2'] = self._prim_t1x2
- palette.add_block('template1x2',
- hidden=True,
- colors=["#0606FF", "#0606A0"],
- style='portfolio-style-1x2',
- label=' ',
- prim_name='t1x2',
- default=[_('Title'), 'None', 'None'],
- special_name=_('presentation 1x2'),
- string_or_number=True,
- help_string=_("presentation template: select two \
-Journal objects"))
- self.tw.lc.def_prim('t1x2', 3,
- lambda self, a, b, c:
- primitive_dictionary['t1x2'](a, b, c))
-
- primitive_dictionary['t2x2'] = self._prim_t2x2
- palette.add_block('template2x2',
- hidden=True,
- colors=["#0606FF", "#0606A0"],
- style='portfolio-style-2x2',
- label=' ',
- prim_name='t2x2',
- default=[_('Title'), 'None', 'None', 'None', 'None'],
- special_name=_('presentation 2x2'),
- string_or_number=True,
- help_string=_("presentation template: select four \
-Journal objects"))
- self.tw.lc.def_prim('t2x2', 5,
- lambda self, a, b, c, d, e:
- primitive_dictionary['t2x2'](a, b, c, d, e))
-
- palette.add_block('templatelist',
- hidden=True,
- colors=["#0606FF", "#0606A0"],
- style='bullet-style',
- label=' ',
- prim_name='bullet',
- default=[_('Title'), '∙ '],
- special_name=_('presentation bulleted list'),
- string_or_number=True,
- help_string=_('presentation template: list of \
-bullets'))
- self.tw.lc.def_prim('bullet', 1, self._prim_list, True)
-
def _myblocks_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'
+ debug_output('making myblocks palette', self.tw.running_sugar)
if len(files) > 0:
palette = make_palette(
'myblocks',
@@ -1299,13 +1183,13 @@ bullets'))
def _prim_readpixel(self):
""" Read r, g, b, a from the canvas and push b, g, r to the stack """
- r, g, b, a = self.tw.canvas.get_pixel()
+ r, g, b, a = self.tw.turtles.get_active_turtle().get_pixel()
self.tw.lc.heap.append(b)
self.tw.lc.heap.append(g)
self.tw.lc.heap.append(r)
def _prim_active_turtle(self):
- return(self.tw.active_turtle.name)
+ return(self.tw.turtles.get_active_turtle().get_name())
def _prim_reskin(self, media):
""" Reskin the turtle with an image from a file """
@@ -1337,13 +1221,13 @@ bullets'))
debug_output("Couldn't open skin %s" % (self.tw.lc.filepath),
self.tw.running_sugar)
if pixbuf is not None:
- self.tw.active_turtle.set_shapes([pixbuf])
- pen_state = self.tw.active_turtle.get_pen_state()
+ self.tw.turtles.get_active_turtle().set_shapes([pixbuf])
+ pen_state = self.tw.turtles.get_active_turtle().get_pen_state()
if pen_state:
- self.tw.canvas.setpen(False)
- self.tw.canvas.forward(0)
+ self.tw.turtles.get_active_turtle().set_pen_state(False)
+ self.tw.turtles.get_active_turtle().forward(0)
if pen_state:
- self.tw.canvas.setpen(True)
+ self.tw.turtles.get_active_turtle().set_pen_state(True)
if self.tw.sharing():
if self.tw.running_sugar:
@@ -1483,7 +1367,7 @@ bullets'))
def _prim_see(self):
""" Read r, g, b from the canvas and return a corresponding palette
color """
- r, g, b, a = self.tw.canvas.get_pixel()
+ r, g, b, a = self.tw.turtles.get_active_turtle().get_pixel()
color_index = self.tw.canvas.get_color_index(r, g, b)
if self.tw.lc.update_values:
self.tw.lc.update_label_value('see', color_index)
@@ -1553,7 +1437,7 @@ bullets'))
x, y = self.tw.lc.x2tx(), self.tw.lc.y2ty()
if center:
y -= self.tw.canvas.textsize
- self.tw.canvas.draw_text(string, x, y,
+ self.tw.turtles.get_active_turtle().draw_text(string, x, y,
int(self.tw.canvas.textsize *
self.tw.lc.scale / 100.),
self.tw.canvas.width - x)
@@ -1562,17 +1446,17 @@ bullets'))
x, y = self.tw.lc.x2tx(), self.tw.lc.y2ty()
if center:
y -= self.tw.canvas.textsize
- self.tw.canvas.draw_text(string, x, y,
+ self.tw.turtles.get_active_turtle().draw_text(string, x, y,
int(self.tw.canvas.textsize *
self.tw.lc.scale / 100.),
self.tw.canvas.width - x)
def _prim_showlist(self, sarray):
""" Display list of media objects """
- x = self.tw.canvas.xcor / self.tw.coord_scale
- y = self.tw.canvas.ycor / self.tw.coord_scale
+ x = self.tw.turtles.get_active_turtle.get_xy()[0] / self.tw.coord_scale
+ y = self.tw.turtles.get_active_turtle.get_xy()[1] / self.tw.coord_scale
for s in sarray:
- self.tw.canvas.setxy(x, y, pendown=False)
+ self.tw.turtles.get_active_turtle().set_xy(x, y, pendown=False)
self._prim_show(s)
y -= int(self.tw.canvas.textsize * self.tw.lead)
@@ -1631,14 +1515,14 @@ bullets'))
# Place the block at the active turtle (x, y) and move the turtle
# into position to place the next block in the stack.
# TODO: Add expandable argument
- x, y = self.tw.active_turtle.get_xy()
+ pos = self.tw.turtles.get_active_turtle().get_xy()
if isinstance(blkname, list):
name = blkname[0]
if len(blkname) > 1:
value = blkname[1:]
- dy = int(self._find_block(name, x, y, value))
+ dy = int(self._find_block(name, pos[0], pos[1], value))
else:
- dy = int(self._find_block(name, x, y))
+ dy = int(self._find_block(name, pos[0], pos[1]))
else:
name = blkname
if name == 'delete':
@@ -1648,11 +1532,12 @@ bullets'))
blk.spr.hide()
dy = 0
else:
- dy = int(self._find_block(name, x, y))
+ dy = int(self._find_block(name, pos[0], pos[1]))
# Reposition turtle to end of flow
- self.tw.canvas.ycor -= dy
- self.tw.canvas.move_turtle()
+ pos = self.tw.turtles.get_active_turtle().get_xy()
+ pos[1] -= dy
+ self.tw.turtles.get_active_turtle().move_turtle(pos)
def _make_block(self, name, x, y, defaults):
if defaults is None:
@@ -1684,6 +1569,7 @@ bullets'))
(1) translate the label name into the internal block name;
(2) 'dock' the block onto a stack where appropriate; and
(3) disassociate the new block from the mouse. """
+ x, y = self.tw.turtles.turtle_to_screen_coordinates((x, y))
for name in block_names:
# Translate label name into block/prim name.
if blkname in block_names[name]:
@@ -1719,170 +1605,3 @@ bullets'))
self.tw.show_toolbar_palette(palette_name_to_index(arg))
else:
raise logoerror("#syntaxerror")
-
- # Deprecated blocks
-
- def _prim_t1x1(self, title, media):
- """ title, one image, and description """
- xo = self.tw.calc_position('t1x1')[2]
- x = -(self.tw.canvas.width / 2) + xo
- y = self.tw.canvas.height / 2
- self.tw.canvas.setxy(x, y, pendown=False)
- # save the text size so we can restore it later
- save_text_size = self.tw.canvas.textsize
- # set title text
- self.tw.canvas.settextsize(self.title_height)
- self._prim_show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) \
- / self.tw.canvas.height
- self._prim_setscale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.tw.lc.body_height)
- # render media object
- # leave some space below the title
- y -= int(self.title_height * 2 * self.tw.lead)
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media)
- if self.tw.running_sugar:
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media.replace('media_', 'descr_'))
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _prim_t2x1(self, title, media1, media2):
- """ title, two images (horizontal), two descriptions """
- xo = self.tw.calc_position('t2x1')[2]
- x = -(self.tw.canvas.width / 2) + xo
- y = self.tw.canvas.height / 2
- self.tw.canvas.setxy(x, y, pendown=False)
- # save the text size so we can restore it later
- save_text_size = self.tw.canvas.textsize
- # set title text
- self.tw.canvas.settextsize(self.title_height)
- self._prim_show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._prim_setscale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.tw.lc.body_height)
- # render four quadrents
- # leave some space below the title
- y -= int(self.title_height * 2 * self.tw.lead)
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media1)
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media2)
- y = -self.title_height
- if self.tw.running_sugar:
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media2.replace('media_', 'descr_'))
- x = -(self.tw.canvas.width / 2) + xo
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media1.replace('media_', 'descr_'))
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _prim_t1x2(self, title, media1, media2):
- """ title, two images (vertical), two desciptions """
- xo = self.tw.calc_position('t1x2')[2]
- x = -(self.tw.canvas.width / 2) + xo
- y = self.tw.canvas.height / 2
- self.tw.canvas.setxy(x, y, pendown=False)
- # save the text size so we can restore it later
- save_text_size = self.tw.canvas.textsize
- # set title text
- self.tw.canvas.settextsize(self.title_height)
- self._prim_show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._prim_setscale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.tw.lc.body_height)
- # render four quadrents
- # leave some space below the title
- y -= int(self.title_height * 2 * self.tw.lead)
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media1)
- if self.tw.running_sugar:
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media1.replace('media_', 'descr_'))
- y = -self.title_height
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media2.replace('media_', 'descr_'))
- x = -(self.tw.canvas.width / 2) + xo
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media2)
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _prim_t2x2(self, title, media1, media2, media3, media4):
- """ title and four images """
- xo = self.tw.calc_position('t2x2')[2]
- x = -(self.tw.canvas.width / 2) + xo
- y = self.tw.canvas.height / 2
- self.tw.canvas.setxy(x, y, pendown=False)
- # save the text size so we can restore it later
- save_text_size = self.tw.canvas.textsize
- # set title text
- self.tw.canvas.settextsize(self.title_height)
- self._prim_show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._prim_setscale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.tw.lc.body_height)
- # render four quadrents
- # leave some space below the title
- y -= int(self.title_height * 2 * self.tw.lead)
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media1)
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media2)
- y = -self.title_height
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media4)
- x = -(self.tw.canvas.width / 2) + xo
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media3)
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _prim_t1x1a(self, title, media1):
- """ title, one media object """
- xo = self.tw.calc_position('t1x1a')[2]
- x = -(self.tw.canvas.width / 2) + xo
- y = self.tw.canvas.height / 2
- self.tw.canvas.setxy(x, y, pendown=False)
- # save the text size so we can restore it later
- save_text_size = self.tw.canvas.textsize
- # set title text
- self.tw.canvas.settextsize(self.title_height)
- self._prim_show(title)
- # calculate and set scale for media blocks
- myscale = 90 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._prim_setscale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.tw.lc.body_height)
- # render media object
- # leave some space below the title
- y -= int(self.title_height * 2 * self.tw.lead)
- self.tw.canvas.setxy(x, y, pendown=False)
- self._prim_show(media1)
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _prim_write(self, string, fsize):
- """ Write string at size """
- x = self.tw.canvas.width / 2 + int(self.tw.canvas.xcor)
- y = self.tw.canvas.height / 2 - int(self.tw.canvas.ycor)
- self.tw.canvas.draw_text(string, x, y - 15, int(fsize),
- self.tw.canvas.width)
diff --git a/turtleblocks.py b/turtleconfusion.py
index 00ca569..f28dea2 100755
--- a/turtleblocks.py
+++ b/turtleconfusion.py
@@ -99,6 +99,8 @@ class TurtleMain():
self._parse_command_line()
self._ensure_sugar_paths()
self._gnome_plugins = []
+ self._selected_challenge = None
+ self._challenge_window = None
if self._output_png:
# Outputing to file, so no need for a canvas
@@ -218,7 +220,7 @@ return %s(self)" % (p, P, P)
max(768, gtk.gdk.screen_height() * 2))
self.tw = TurtleArtWindow(self.canvas, self._execdirname,
turtle_canvas=self.turtle_canvas,
- parent=self, running_sugar=False)
+ activity=self, running_sugar=False)
self.tw.save_folder = self._abspath # os.path.expanduser('~')
if self.client.get_int(self._HOVER_HELP) == 1:
self.hover.set_active(False)
@@ -371,6 +373,7 @@ return %s(self)" % (p, P, P)
menu = gtk.Menu()
MenuBuilder.make_menu_item(menu, _('New'), self._do_new_cb)
MenuBuilder.make_menu_item(menu, _('Open'), self._do_open_cb)
+ MenuBuilder.make_menu_item(menu, _('Load project'), self._do_load_cb)
MenuBuilder.make_menu_item(menu, _('Save'), self._do_save_cb)
MenuBuilder.make_menu_item(menu, _('Save as'), self._do_save_as_cb)
MenuBuilder.make_menu_item(menu, _('Save as image'),
@@ -425,13 +428,12 @@ return %s(self)" % (p, P, P)
turtle_menu = MenuBuilder.make_sub_menu(menu, _('Turtle'))
menu = gtk.Menu()
- self._level = 0
- self._levels = self._get_levels()
self._custom_filepath = None
- for i in range(len(self._levels)):
- MenuBuilder.make_menu_item(menu, _('Challenge') + ' ' + str(i + 1),
- self._do_level_cb, i)
- turtle_menu = MenuBuilder.make_sub_menu(menu, _('Challenges'))
+ MenuBuilder.make_menu_item(menu, _('Show challenges'),
+ self._create_store)
+ MenuBuilder.make_menu_item(menu, _('Hide challenges'),
+ self._hide_store)
+ challenges_menu = MenuBuilder.make_sub_menu(menu, _('Challenges'))
menu = gtk.Menu()
MenuBuilder.make_menu_item(menu, _('About...'), self._do_about_cb)
@@ -443,6 +445,7 @@ return %s(self)" % (p, P, P)
menu_bar.append(view_menu)
menu_bar.append(tool_menu)
menu_bar.append(turtle_menu)
+ menu_bar.append(challenges_menu)
# Add menus for plugins
for p in self._gnome_plugins:
@@ -495,6 +498,10 @@ Would you like to save before quitting?'))
''' Callback for open project. '''
self.tw.load_file_from_chooser(True)
+ def _do_load_cb(self, widget):
+ ''' Callback for load project (add to current project). '''
+ self.tw.load_file_from_chooser(False)
+
def _do_save_cb(self, widget):
''' Callback for save project. '''
self.tw.save_file(self._ta_file)
@@ -582,7 +589,8 @@ Would you like to save before quitting?'))
''' Turn hover help off '''
self.tw.no_help = True
self.tw.last_label = None
- self.tw.status_spr.hide()
+ if self.tw.status_spr is not None:
+ self.tw.status_spr.hide()
self.hover.set_active(False)
self.client.set_int(self._HOVER_HELP, 1)
@@ -669,58 +677,36 @@ Would you like to save before quitting?'))
def _load_level(self, custom=False):
self.tw.canvas.clearscreen()
if custom:
- self.tw.canvas.setxy(0, 0, pendown=False)
+ self.tw.turtles.get_active_turtle().set_xy((0, 0), pendown=False)
self.tw.lc.insert_image(center=True,
filepath=self._custom_filepath,
resize=True, offset=False)
else:
- self.tw.canvas.setxy(int(-gtk.gdk.screen_width() / 2), 0,
- pendown=False)
- self.tw.lc.insert_image(center=False, resize=False,
- filepath=os.path.join(
- self._get_execution_dir(), 'images',
- 'turtle-a.png'))
- # Slight offset to account for stroke width
- if self._level + 1 in self.offsets:
- xoffset = self.offsets[self._level + 1][0]
- yoffset = self.offsets[self._level + 1][1]
+ basename = os.path.basename(self._selected_challenge)[:-4]
+ if basename in self.offsets:
+ offset = [self.offsets[basename][0] - 3,
+ self.offsets[basename][1] - 33]
+ scale = self.offsets[basename][2]
else:
- xoffset = 0
- yoffset = 0
- self.tw.canvas.setxy(-2.5 + xoffset, -2.5 + yoffset, pendown=False)
+ offset = [-3, -33]
+ scale = 33
+ save_scale = self.tw.lc.scale
+ self.tw.turtles.get_active_turtle().set_xy((offset), pendown=False)
+
+ self.tw.lc.scale = scale
self.tw.lc.insert_image(center=False,
- filepath=os.path.join(
- self._get_execution_dir(), 'challenges',
- self._levels[self._level] + '.svg'), resize=False,
+ filepath=self._selected_challenge,
+ resize=True,
offset=True)
- self.tw.canvas.setxy(0, 0, pendown=False)
-
- def _do_level_cb(self, widget, level):
- ''' Callback to resize blocks. '''
- self._level = level
- self._load_level()
-
- def _get_levels(self):
- ''' Look for level files in lessons directory. '''
- levels = glob.glob(os.path.join(self._get_execution_dir(),
- 'challenges', '*.svg'))
-
- level_files = []
- for i in range(len(levels)):
- level_files.append('confusion-%d' % (i+1))
-
- self.offsets = {}
- offset_fd = open(os.path.join(self._get_execution_dir(), 'challenges',
- 'offsets'))
- for line in offset_fd:
- try:
- idx, offsets = line.strip('\n').split(':')
- xoffset, yoffset = offsets.split(',')
- self.offsets[int(idx)] = (int(xoffset), int(yoffset))
- except ValueError:
- pass
- offset_fd.close()
- return level_files
+ '''
+ pos = self.tw.turtles.turtle_to_screen_coordinates((0, -50))
+ self.tw.turtles.get_active_turtle().draw_text(
+ os.path.basename(self._selected_challenge)[:-4].replace(
+ '_', ' '),
+ pos[0], pos[1], 24, gtk.gdk.screen_width() / 2)
+ '''
+ self.tw.lc.scale = save_scale
+ self.tw.turtles.get_active_turtle().set_xy((0, 0), pendown=False)
def _do_copy_cb(self, button):
''' Callback for copy button. '''
@@ -804,6 +790,99 @@ Would you like to save before quitting?'))
else:
return os.path.abspath(dirname)
+ def _hide_store(self, widget=None):
+ if self._challenge_window is not None:
+ self._challenge_box.hide()
+
+ def _create_store(self, widget=None):
+ if self._challenge_window is None:
+ self._challenge_box = gtk.EventBox()
+ self._challenge_window = gtk.ScrolledWindow()
+ self._challenge_window.set_policy(gtk.POLICY_NEVER,
+ gtk.POLICY_AUTOMATIC)
+ width = gtk.gdk.screen_width() / 2
+ height = gtk.gdk.screen_height() / 2
+ self._challenge_window.set_size_request(width, height)
+ self._challenge_window.show()
+
+ store = gtk.ListStore(gtk.gdk.Pixbuf, str)
+
+ icon_view = gtk.IconView()
+ icon_view.set_model(store)
+ icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
+ icon_view.connect('selection-changed', self._challenge_selected,
+ store)
+ icon_view.set_pixbuf_column(0)
+ icon_view.grab_focus()
+ self._challenge_window.add_with_viewport(icon_view)
+ icon_view.show()
+ self._fill_challenges_list(store)
+
+ width = gtk.gdk.screen_width() / 4
+ height = gtk.gdk.screen_height() / 4
+
+ self._challenge_box.add(self._challenge_window)
+ self.fixed.put(self._challenge_box, width, height)
+
+ self.offsets = {}
+ offset_fd = open(os.path.join(self._get_execution_dir(),
+ 'challenges',
+ 'offsets'))
+ for line in offset_fd:
+ try:
+ idx, offsets = line.strip('\n').split(':')
+ xoffset, yoffset, scale = offsets.split(',')
+ self.offsets['confusion-' + idx] = (int(xoffset),
+ int(yoffset),
+ int(scale))
+ except ValueError:
+ pass
+ offset_fd.close()
+
+ self._challenge_window.show()
+ self._challenge_box.show()
+
+ def _get_selected_path(self, widget, store):
+ try:
+ iter_ = store.get_iter(widget.get_selected_items()[0])
+ image_path = store.get(iter_, 1)[0]
+
+ return image_path, iter_
+ except:
+ return None
+
+ def _challenge_selected(self, widget, store):
+ selected = self._get_selected_path(widget, store)
+
+ if selected is None:
+ self._selected_challenge = None
+ self._challenge_window.hide()
+ return
+
+ image_path, _iter = selected
+ iter_ = store.get_iter(widget.get_selected_items()[0])
+ image_path = store.get(iter_, 1)[0]
+
+ self._selected_challenge = image_path
+ self._challenge_window.hide()
+ self._load_level()
+
+ def _fill_challenges_list(self, store):
+ '''
+ Append images from the artwork_paths to the store.
+ '''
+ for filepath in self._scan_for_challenges():
+ pixbuf = None
+ pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
+ filepath, 100, 100)
+ store.append([pixbuf, filepath])
+
+ def _scan_for_challenges(self):
+ file_list = list(glob.glob(os.path.join(self._get_execution_dir(),
+ 'challenges', '*.svg')))
+ file_list.sort()
+ return file_list
+
if __name__ == '__main__':
TurtleMain()