Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TurtleArt
diff options
context:
space:
mode:
Diffstat (limited to 'TurtleArt')
-rw-r--r--TurtleArt/RtfParser.py150
-rw-r--r--TurtleArt/audiograb.py622
-rw-r--r--TurtleArt/rfidutils.py123
-rw-r--r--TurtleArt/ringbuffer.py108
-rw-r--r--TurtleArt/sprites.py5
-rw-r--r--TurtleArt/tabasics.py1270
-rw-r--r--TurtleArt/tablock.py255
-rw-r--r--TurtleArt/tacamera.py42
-rw-r--r--TurtleArt/tacanvas.py362
-rw-r--r--TurtleArt/tacollaboration.py379
-rw-r--r--TurtleArt/taconstants.py830
-rw-r--r--TurtleArt/taexporthtml.py160
-rw-r--r--TurtleArt/taexportlogo.py560
-rw-r--r--TurtleArt/tagettext.py24
-rw-r--r--TurtleArt/tajail.py13
-rw-r--r--TurtleArt/talogo.py1414
-rw-r--r--TurtleArt/tapalette.py299
-rwxr-xr-xTurtleArt/tasprite_factory.py20
-rw-r--r--TurtleArt/taturtle.py54
-rw-r--r--TurtleArt/tautils.py154
-rw-r--r--TurtleArt/tawindow.py1140
-rw-r--r--TurtleArt/v4l2.py1914
22 files changed, 3464 insertions, 6434 deletions
diff --git a/TurtleArt/RtfParser.py b/TurtleArt/RtfParser.py
deleted file mode 100644
index 9a141a4..0000000
--- a/TurtleArt/RtfParser.py
+++ /dev/null
@@ -1,150 +0,0 @@
-#Copyright (c) 2010, Loic Fejoz
-#Copyright (c) 2010, Walter Bender
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-
-import sys
-
-
-class RtfException(Exception):
- pass
-
-plaintext = 1
-control = 2
-argument = 3
-backslash = 4
-escapedChar = 5
-
-
-class RtfParser(object):
-
- def __init__(self, unicode=False):
- self.state = plaintext
- self.arg = ''
- self.token = ''
- self.unicode = unicode
- self.par = False
- self.output = ''
-
- def getChar(self, code):
- """ called when an escaped char is found """
- return chr(code)
-
- def getNonBreakingSpace(self):
- return ' '
-
- def pushState(self):
- pass
-
- def popState(self):
- pass
-
- def putChar(self):
- pass
-
- def doControl(self, token, arg):
- pass
-
- def feed(self, txt):
- for c in txt:
- self.feedChar(c)
-
- def feedChar(self, char):
- if self.state == plaintext: # this is just normal user content
- if char == '\\':
- self.state = backslash
- elif char == '{':
- self.pushState()
- elif char == '}':
- self.popState()
- else:
- self.putChar(char)
- elif self.state == backslash: # a command or escape
- if char == '\\' or char == '{' or char == '}':
- self.putChar(char)
- self.state = plaintext
- else:
- if char.isalpha() or char in ('*', '-', '|'):
- self.state = control
- self.token = char
- elif char == "'":
- self.state = escapedChar
- self.escapedChar = ''
- elif char in ['\\', '{', '}']:
- self.putChar(char)
- self.state = plaintext
- elif char == "~": # non breaking space
- self.putChar(self.getNonBreakingSpace())
- self.state = plaintext
- else:
- raise RtfException(('unexpected %s after \\' % char))
- elif self.state == escapedChar:
- self.escapedChar = self.escapedChar + char
- if len(self.escapedChar) == 2:
- char = self.getChar(int(self.escapedChar, 16))
- self.putChar(char)
- self.state = plaintext
- elif self.state == control: # collecting the command token
- if char.isalpha():
- self.token = self.token + char
- elif char.isdigit() or char == '-':
- self.state = argument
- self.arg = char
- else:
- self.doControl(self.token, self.arg)
- self.state = plaintext
- if char == '\\':
- self.state = backslash
- elif char == '{':
- self.pushState()
- elif char == '}':
- self.popState()
- else:
- if not char.isspace():
- self.putChar(char)
- elif self.state == argument: # collecting the optional argument
- if char.isdigit():
- self.arg = self.arg + char
- else:
- self.state = plaintext
- self.doControl(self.token, self.arg)
- if char == '\\':
- self.state = backslash
- elif char == '{':
- self.pushState()
- elif char == '}':
- self.popState()
- else:
- if not char.isspace():
- self.putChar(char)
-
-
-class RtfTextOnly(RtfParser):
-
- def __init__(self):
- RtfParser.__init__(self)
- self.level = 0
-
- def pushState(self):
- self.level = self.level + 1
-
- def popState(self):
- self.level = self.level - 1
-
- def putChar(self, ch):
- if self.par:
- self.output += ch
-
- def doControl(self, token, arg):
- if token[0:3] == 'par':
- self.par = True
- pass
diff --git a/TurtleArt/audiograb.py b/TurtleArt/audiograb.py
deleted file mode 100644
index 3ecdc11..0000000
--- a/TurtleArt/audiograb.py
+++ /dev/null
@@ -1,622 +0,0 @@
-#! /usr/bin/python
-#
-# Author: Arjun Sarwal arjun@laptop.org
-# Copyright (C) 2007, Arjun Sarwal
-# Copyright (C) 2009,10 Walter Bender
-# Copyright (C) 2009, Benjamin Berg, Sebastian Berg
-# Copyright (C) 2009, Sayamindu Dasgupta
-# Copyright (C) 2010, Sascha Silbe
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import pygst
-import gst
-import gst.interfaces
-from numpy import fromstring
-import os
-import subprocess
-from string import find
-from threading import Timer
-
-# Initial device settings
-RATE = 48000
-MIC_BOOST = True
-DC_MODE_ENABLE = False
-CAPTURE_GAIN = 50
-BIAS = True
-
-# Setting on quit
-QUIT_MIC_BOOST = False
-QUIT_DC_MODE_ENABLE = False
-QUIT_CAPTURE_GAIN = 100
-QUIT_BIAS = True
-
-import logging
-
-_logger = logging.getLogger('TurtleArt')
-_logger.setLevel(logging.DEBUG)
-logging.basicConfig()
-
-from taconstants import SENSOR_AC_NO_BIAS, SENSOR_AC_BIAS, SENSOR_DC_NO_BIAS, \
- SENSOR_DC_BIAS, XO1
-
-
-class AudioGrab:
- """ The interface between measure and the audio device """
-
- def __init__(self, callable1, activity):
- """ Initialize the class: callable1 is a data buffer;
- activity is the parent class"""
-
- self.callable1 = callable1
- self.activity = activity
- self.sensor = None
-
- self.temp_buffer = [0]
- self.picture_buffer = [] # place to hold screen grabs
-
- self.draw_graph_status = False
- self.screenshot = True
-
- self.rate = 48000
- self.final_count = 0
- self.count_temp = 0
- self.entry_count = 0
-
- self.counter_buffer = 0
-
- self._dc_control = None
- self._mic_bias_control = None
- self._capture_control = None
- self._mic_boost_control = None
- self._hardwired = False # Query controls or use hardwired names
-
- # Set up gst pipeline
- self.pipeline = gst.Pipeline("pipeline")
- self.alsasrc = gst.element_factory_make("alsasrc", "alsa-source")
- self.pipeline.add(self.alsasrc)
- self.caps1 = gst.element_factory_make("capsfilter", "caps1")
- self.pipeline.add(self.caps1)
- caps_str = "audio/x-raw-int,rate=%d,channels=1,depth=16" % (RATE)
- self.caps1.set_property("caps", gst.caps_from_string(caps_str))
- self.fakesink = gst.element_factory_make("fakesink", "fsink")
- self.pipeline.add(self.fakesink)
- self.fakesink.connect("handoff", self.on_buffer)
- self.fakesink.set_property("signal-handoffs", True)
- gst.element_link_many(self.alsasrc, self.caps1, self.fakesink)
-
- self.dont_queue_the_buffer = False
-
- self._mixer = gst.element_factory_make('alsamixer')
- rc = self._mixer.set_state(gst.STATE_PAUSED)
- assert rc == gst.STATE_CHANGE_SUCCESS
-
- # Query the available controls
- try: # F11+
- _logger.debug('controls: %r', [t.props.untranslated_label \
- for t in self._mixer.list_tracks()])
- self._dc_control = self._find_control(['dc mode'])
- self._mic_bias_control = self._find_control(['mic bias',
- 'dc input bias',
- 'v_refout'])
- self._mic_boost_control = self._find_control(['mic boost',
- 'mic boost (+20db)',
- 'internal mic boost',
- 'analog mic boost'])
- self._mic_gain_control = self._find_control(['mic'])
- self._capture_control = self._find_control(['capture'])
- self._master_control = self._find_control(['master'])
- except AttributeError: # F9- (no untranslated_label attribute)
- self._hardwired = True
-
- # Variables for saving and resuming state of sound device
- self.master = self.get_master()
- self.bias = BIAS
- self.dcmode = DC_MODE_ENABLE
- self.capture_gain = CAPTURE_GAIN
- self.mic_boost = MIC_BOOST
- self.mic = self.get_mic_gain()
-
- # Timer for interval sampling and switch to indicate when to capture
- self.capture_timer = None
- self.capture_interval_sample = False
-
- def set_handoff_signal(self, handoff_state):
- """Sets whether the handoff signal would generate an interrupt or not"""
- self.fakesink.set_property("signal-handoffs", handoff_state)
-
- def _new_buffer(self, buf):
- """ Use a new buffer """
- if not self.dont_queue_the_buffer:
- self.temp_buffer = buf
- self.callable1(buf)
- else:
- pass
-
- def on_buffer(self, element, buffer, pad):
- """The function that is called whenever new data is available
- This is the signal handler for the handoff signal"""
- if buffer is None:
- _logger.debug('audiograb buffer is None')
- return False
-
- temp_buffer = fromstring(buffer, 'int16')
- if not self.dont_queue_the_buffer:
- self._new_buffer(temp_buffer)
- return False
-
- def set_sensor(self, sensor):
- """Keep a reference to the sensot toolbar for logging"""
- self.sensor = sensor
-
- def start_sound_device(self):
- """Start or Restart grabbing data from the audio capture"""
- gst.event_new_flush_start()
- self.pipeline.set_state(gst.STATE_PLAYING)
-
- def stop_sound_device(self):
- """Stop grabbing data from capture device"""
- gst.event_new_flush_stop()
- self.pipeline.set_state(gst.STATE_NULL)
-
- def set_sampling_rate(self, sr):
- """Sets the sampling rate of the capture device
- Sampling rate must be given as an integer for example 16000 for
- setting 16Khz sampling rate
- The sampling rate would be set in the device to the nearest available"""
- self.pause_grabbing()
- caps_str = "audio/x-raw-int,rate=%d,channels=1,depth=16" % (sr, )
- self.caps1.set_property("caps", gst.caps_from_string(caps_str))
- self.resume_grabbing()
-
- def get_sampling_rate(self):
- """Gets the sampling rate of the capture device"""
- return int(self.caps1.get_property("caps")[0]['rate'])
-
- def set_callable1(self, callable1):
- """Sets the callable to the drawing function for giving the
- data at the end of idle-add"""
- self.callable1 = callable1
-
- def start_grabbing(self):
- """Called right at the start of the Activity"""
- self.start_sound_device()
-
- def pause_grabbing(self):
- """When Activity goes into background"""
- self.save_state()
- self.stop_sound_device()
-
- def resume_grabbing(self):
- """When Activity becomes active after going to background"""
- self.start_sound_device()
- self.resume_state()
-
- def stop_grabbing(self):
- """Not used ???"""
- self.stop_sound_device()
- self.set_handoff_signal(False)
-
- def _find_control(self, prefixes):
- """Try to find a mixer control matching one of the prefixes.
-
- The control with the best match (smallest difference in length
- between label and prefix) will be returned. If no match is found,
- None is returned.
- """
- def best_prefix(label, prefixes):
- matches =\
- [len(label) - len(p) for p in prefixes if label.startswith(p)]
- if not matches:
- return None
-
- matches.sort()
- return matches[0]
-
- controls = []
- for track in self._mixer.list_tracks():
- label = track.props.untranslated_label.lower()
- diff = best_prefix(label, prefixes)
- if diff is not None:
- controls.append((track, diff))
-
- controls.sort(key=lambda e: e[1])
- if controls:
- _logger.debug("found control: %s" %\
- (str(controls[0][0].props.untranslated_label)))
- return controls[0][0]
-
- return None
-
- def save_state(self):
- """Saves the state of all audio controls"""
- self.master = self.get_master()
- self.bias = self.get_bias()
- self.dcmode = self.get_dc_mode()
- self.capture_gain = self.get_capture_gain()
- self.mic_boost = self.get_mic_boost()
-
- def resume_state(self):
- """Put back all audio control settings from the saved state"""
- self.set_master(self.master)
- self.set_bias(self.bias)
- self.set_dc_mode(self.dcmode)
- self.set_capture_gain(self.capture_gain)
- self.set_mic_boost(self.mic_boost)
-
- def _get_mute(self, control, name, default):
- """Get mute status of a control"""
- if not control:
- return default
-
- value = bool(control.flags & gst.interfaces.MIXER_TRACK_MUTE)
- _logger.debug('Getting %s (%s) mute status: %r', name,
- control.props.untranslated_label, value)
- return value
-
- def _set_mute(self, control, name, value):
- """Mute a control"""
- if not control:
- return
-
- self._mixer.set_mute(control, value)
- _logger.debug('Set mute for %s (%s) to %r', name,
- control.props.untranslated_label, value)
-
- def _get_volume(self, control, name):
- """Get volume of a control and convert to a scale of 0-100"""
- if not control:
- return 100
-
- try: # sometimes get_volume does not return a tuple
- hw_volume = self._mixer.get_volume(control)[0]
- except IndexError:
- return 100
-
- min_vol = control.min_volume
- max_vol = control.max_volume
- percent = (hw_volume - min_vol)*100//(max_vol - min_vol)
- return percent
-
- def _set_volume(self, control, name, value):
- """Sets the level of a control on a scale of 0-100"""
- if not control:
- return
-
- # convert value to scale of control
- min_vol = control.min_volume
- max_vol = control.max_volume
- if min_vol != max_vol:
- hw_volume = value*(max_vol - min_vol)//100 + min_vol
- self._mixer.set_volume(control, (hw_volume,)*control.num_channels)
-
- def amixer_set(self, control, state):
- """ Direct call to amixer for old systems. """
- if state:
- os.system("amixer set '%s' unmute" % (control))
- else:
- os.system("amixer set '%s' mute" % (control))
-
- def mute_master(self):
- """Mutes the Master Control"""
- if not self._hardwired and self.activity.hw != XO1:
- self._set_mute(self._master_control, 'Master', True)
- else:
- self.amixer_set('Master', False)
-
- def unmute_master(self):
- """Unmutes the Master Control"""
- if not self._hardwired and self.activity.hw != XO1:
- self._set_mute(self._master_control, 'Master', True)
- else:
- self.amixer_set('Master', True)
-
- def set_master(self, master_val):
- """Sets the Master gain slider settings
- master_val must be given as an integer between 0 and 100 indicating the
- percentage of the slider to be set"""
- if not self._hardwired:
- self._set_volume(self._master_control, 'Master', master_val)
- else:
- os.system("amixer set Master " + str(master_val) + "%")
-
- def get_master(self):
- """Gets the Master gain slider settings. The value returned is an
- integer between 0-100 and is an indicative of the percentage 0 - 100%"""
- if not self._hardwired:
- return self._get_volume(self._master_control, 'master')
- else:
- p = str(subprocess.Popen(["amixer", "get", "Master"],
- stdout=subprocess.PIPE).communicate()[0])
- p = p[find(p, "Front Left:"):]
- p = p[find(p, "[")+1:]
- p = p[:find(p, "%]")]
- return int(p)
-
- def set_bias(self, bias_state=False):
- """Enables / disables bias voltage."""
- if not self._hardwired and self.activity.hw != XO1:
- if self._mic_bias_control is None:
- return
- # if not isinstance(self._mic_bias_control,
- # gst.interfaces.MixerOptions):
- if self._mic_bias_control not in self._mixer.list_tracks():
- return self._set_mute(self._mic_bias_control, 'Mic Bias',
- not bias_state)
-
- # We assume that values are sorted from lowest (=off) to highest.
- # Since they are mixed strings ("Off", "50%", etc.), we cannot
- # easily ensure this by sorting with the default sort order.
- try:
- if bias_state:
- # self._mixer.set_option(self._mic_bias_control, values[-1])
- self._mixer.set_volume(self._mic_bias_control,
- self._mic_bias_control.max_volume)
- else:
- self._mixer.set_volume(self._mic_bias_control,
- self._mic_bias_control.min_volume)
- # self._mixer.set_option(self._mic_bias_control, values[0])
- except TypeError:
- self._set_mute(self._mic_bias_control, 'Mic Bias',
- not bias_state)
- elif self._hardwired:
- self.amixer_set('V_REFOUT Enable', bias_state)
- else:
- self.amixer_set('MIC Bias Enable', bias_state)
-
- def get_bias(self):
- """Check whether bias voltage is enabled."""
- if not self._hardwired:
- if self._mic_bias_control is None:
- return False
- if self._mic_bias_control not in self._mixer.list_tracks():
- return not self._get_mute(self._mic_bias_control, 'Mic Bias',
- False)
- current = self._mixer.get_volume(self._mic_bias_control)
- # same ordering assertion as in set_bias() applies
- # if current == values[0]:
- if current == self._mic_bias_control.min_volume:
- return False
- return True
- else:
- p = str(subprocess.Popen(["amixer", "get", "'V_REFOUT Enable'"],
- stdout=subprocess.PIPE).communicate()[0])
- p = p[find(p, "Mono:"):]
- p = p[find(p, "[")+1:]
- p = p[:find(p, "]")]
- if p == "on":
- return True
- return False
-
- def set_dc_mode(self, dc_mode=False):
- """Sets the DC Mode Enable control
- pass False to mute and True to unmute"""
- if not self._hardwired and self.activity.hw != XO1:
- if self._dc_control is not None:
- self._set_mute(self._dc_control, 'DC mode', not dc_mode)
- else:
- self.amixer_set('DC Mode Enable', dc_mode)
-
- def get_dc_mode(self):
- """Returns the setting of DC Mode Enable control
- i .e. True: Unmuted and False: Muted"""
- if not self._hardwired:
- if self._dc_control is not None:
- return not self._get_mute(self._dc_control, 'DC mode', False)
- else:
- return False
- else:
- p = str(subprocess.Popen(["amixer", "get", "'DC Mode Enable'"],
- stdout=subprocess.PIPE).communicate()[0])
- p = p[find(p, "Mono:"):]
- p = p[find(p, "[")+1:]
- p = p[:find(p, "]")]
- if p == "on":
- return True
- else:
- return False
-
- def set_mic_boost(self, mic_boost=False):
- """Set Mic Boost.
- True = +20dB, False = 0dB"""
- if not self._hardwired:
- if self._mic_boost_control is None:
- return
- if self._mic_boost_control not in self._mixer.list_tracks():
- return self._set_mute(self._mic_boost_control, 'Mic Boost',
- mic_boost)
- value = self._mixer.get_volume(self._mic_boost_control)
- try:
- if mic_boost:
- self._mixer.set_volume(self._mic_boost_control,
- self._mic_boost_control.max_volume)
- else:
- self._mixer.set_volume(self._mic_boost_control,
- self._mic_boost_control.min_volume)
- except TypeError:
- return self._set_mute(self._mic_boost_control, 'Mic Boost',
- not mic_boost)
- else:
- self.amixer_set('Mic Boost (+20dB)', mic_boost)
-
- def get_mic_boost(self):
- """Return Mic Boost setting.
- True = +20dB, False = 0dB"""
- if not self._hardwired:
- if self._mic_boost_control is None:
- return False
- if self._mic_boost_control not in self._mixer.list_tracks():
- return self._get_mute(self._mic_boost_control, 'Mic Boost',
- False)
- current = self._mixer.get_volume(self._mic_boost_control)
- _logger.debug('current: %s' % (str(current)))
- if current != self._mic_boost_control.min_volume:
- return True
- return False
- else:
- p = str(subprocess.Popen(["amixer", "get", "'Mic Boost (+20dB)'"],
- stdout=subprocess.PIPE).communicate()[0])
- p = p[find(p, "Mono:"):]
- p = p[find(p, "[")+1:]
- p = p[:find(p, "]")]
- if p == "on":
- return True
- else:
- return False
-
- def set_capture_gain(self, capture_val):
- """Sets the Capture gain slider settings
- capture_val must be given as an integer between 0 and 100 indicating the
- percentage of the slider to be set"""
- if not self._hardwired and self.activity.hw != XO1:
- if self._capture_control is not None:
- self._set_volume(self._capture_control, 'Capture', capture_val)
- else:
- os.system("amixer set Capture " + str(capture_val) + "%")
-
- def get_capture_gain(self):
- """Gets the Capture gain slider settings. The value returned is an
- integer between 0-100 and is an indicative of the percentage 0 - 100%"""
- if not self._hardwired:
- if self._capture_control is not None:
- return self._get_volume(self._capture_control, 'Capture')
- else:
- return 0
- else:
- p = str(subprocess.Popen(["amixer", "get", "Capture"],
- stdout=subprocess.PIPE).communicate()[0])
- p = p[find(p, "Front Left:"):]
- p = p[find(p, "[")+1:]
- p = p[:find(p, "%]")]
- return int(p)
-
- def set_mic_gain(self, mic_val):
- """Sets the MIC gain slider settings
- mic_val must be given as an integer between 0 and 100 indicating the
- percentage of the slider to be set"""
- if not self._hardwired and self.activity.hw != XO1:
- self._set_volume(self._mic_gain_control, 'Mic', mic_val)
- else:
- os.system("amixer set Mic " + str(mic_val) + "%")
-
- def get_mic_gain(self):
- """Gets the MIC gain slider settings. The value returned is an
- integer between 0-100 and is an indicative of the percentage 0 - 100%"""
- if not self._hardwired:
- return self._get_volume(self._mic_gain_control, 'Mic')
- else:
- p = str(subprocess.Popen(["amixer", "get", "Mic"],
- stdout=subprocess.PIPE).communicate()[0])
- try:
- p = p[find(p, "Mono:"):]
- p = p[find(p, "[")+1:]
- p = p[:find(p, "%]")]
- return int(p)
- except:
- return(0)
-
- def set_sensor_type(self, sensor_type=SENSOR_AC_BIAS):
- """Set the type of sensor you want to use. Set sensor_type according
- to the following
- SENSOR_AC_NO_BIAS - AC coupling with Bias Off --> Very rarely used.
- Use when connecting a dynamic microphone externally
- SENSOR_AC_BIAS - AC coupling with Bias On --> The default settings.
- The internal MIC uses these
- SENSOR_DC_NO_BIAS - DC coupling with Bias Off --> measuring voltage
- output sensor. For example LM35 which gives output proportional
- to temperature
- SENSOR_DC_BIAS - DC coupling with Bias On --> measuing resistance.
- """
- PARAMETERS = {
- SENSOR_AC_NO_BIAS: (False, False, 50, True),
- SENSOR_AC_BIAS: (False, True, 40, True),
- SENSOR_DC_NO_BIAS: (True, False, 0, False),
- SENSOR_DC_BIAS: (True, True, 0, False)
- }
- mode, bias, gain, boost = PARAMETERS[sensor_type]
- _logger.debug("====================================")
- _logger.debug("Set Sensor Type to %s" % (str(sensor_type)))
- self._set_sensor_type(mode, bias, gain, boost)
- _logger.debug("====================================")
-
- def _set_sensor_type(self, mode=None, bias=None, gain=None, boost=None):
- """Helper to modify (some) of the sensor settings."""
- if mode is not None:
- self.set_dc_mode(mode)
- if self._dc_control is not None:
- os.system("amixer get '%s'" %\
- (self._dc_control.props.untranslated_label))
- if bias is not None:
- self.set_bias(bias)
- if self._mic_bias_control is not None:
- os.system("amixer get '%s'" %\
- (self._mic_bias_control.props.untranslated_label))
- if gain is not None:
- self.set_capture_gain(gain)
- if self._capture_control is not None:
- os.system("amixer get '%s'" %\
- (self._capture_control.props.untranslated_label))
- if boost is not None:
- self.set_mic_boost(boost)
- if self._mic_boost_control is not None:
- os.system("amixer get '%s'" %\
- (self._mic_boost_control.props.untranslated_label))
-
- def on_activity_quit(self):
- """When Activity quits"""
- self.set_mic_boost(QUIT_MIC_BOOST)
- self.set_dc_mode(QUIT_DC_MODE_ENABLE)
- self.set_capture_gain(QUIT_CAPTURE_GAIN)
- self.set_bias(QUIT_BIAS)
- self.stop_sound_device()
-
-
-class AudioGrab_XO1(AudioGrab):
- """ Use default parameters for OLPC XO 1.0 laptop """
- pass
-
-
-class AudioGrab_XO15(AudioGrab):
- """ Override parameters for OLPC XO 1.5 laptop """
- def set_sensor_type(self, sensor_type=SENSOR_AC_BIAS):
- """Helper to modify (some) of the sensor settings."""
- PARAMETERS = {
- SENSOR_AC_NO_BIAS: (False, False, 80, True),
- SENSOR_AC_BIAS: (False, True, 80, True),
- SENSOR_DC_NO_BIAS: (True, False, 80, False),
- SENSOR_DC_BIAS: (True, True, 90, False)
- }
- _logger.debug("====================================")
- _logger.debug("Set Sensor Type to %s" % (str(sensor_type)))
- mode, bias, gain, boost = PARAMETERS[sensor_type]
- self._set_sensor_type(mode, bias, gain, boost)
- _logger.debug("====================================")
-
-
-class AudioGrab_Unknown(AudioGrab):
- """ Override parameters for generic hardware """
- def set_sensor_type(self, sensor_type=SENSOR_AC_BIAS):
- """Helper to modify (some) of the sensor settings."""
- PARAMETERS = {
- SENSOR_AC_NO_BIAS: (None, False, 50, True),
- SENSOR_AC_BIAS: (None, True, 40, True),
- SENSOR_DC_NO_BIAS: (True, False, 80, False),
- SENSOR_DC_BIAS: (True, True, 90, False)
- }
- _logger.debug("====================================")
- _logger.debug("Set Sensor Type to %s" % (str(sensor_type)))
- mode, bias, gain, boost = PARAMETERS[sensor_type]
- self._set_sensor_type(mode, bias, gain, boost)
- _logger.debug("====================================")
diff --git a/TurtleArt/rfidutils.py b/TurtleArt/rfidutils.py
deleted file mode 100644
index f2c74b4..0000000
--- a/TurtleArt/rfidutils.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# utils.py - Helper functions for tis2000.py
-# Copyright (C) 2010 Emiliano Pastorino <epastorino@plan.ceibal.edu.uy>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import logging
-
-def find_device():
- """
- Search for devices.
- Return a device instance or None.
- """
- device = None
- for i in os.listdir(os.path.join('.', 'devices')):
- if not os.path.isdir(os.path.join('.', 'devices', i)):
- try:
- _tempmod = __import__('devices.%s'%i.split('.')[0], globals(),
- locals(), ['RFIDReader'], -1)
- devtemp = _tempmod.RFIDReader()
- if devtemp.get_present() == True:
- device = devtemp
- except Exception, e:
- # logging.error("FIND_DEVICE: %s: %s"%(i, e))
- pass
- if device is None:
- logging.debug("No RFID device found")
- return device
-
-
-def strhex2bin(strhex):
- """
- Convert a string representing an hex value into a
- string representing the same value in binary format.
- """
- dic = { '0':"0000",
- '1':"0001",
- '2':"0010",
- '3':"0011",
- '4':"0100",
- '5':"0101",
- '6':"0110",
- '7':"0111",
- '8':"1000",
- '9':"1001",
- 'A':"1010",
- 'B':"1011",
- 'C':"1100",
- 'D':"1101",
- 'E':"1110",
- 'F':"1111"
- }
- binstr = ""
- for i in strhex:
- binstr = binstr + dic[i.upper()]
- return binstr
-
-def strbin2dec(strbin):
- """
- Convert a string representing a binary value into a
- string representing the same value in decimal format.
- """
- strdec = "0"
- for i in range(1, strbin.__len__()+1):
- strdec = str(int(strdec)+int(strbin[-i])*int(pow(2, i-1)))
- return strdec
-
-def dec2bin(ndec):
- """
- Convert a decimal number into a string representing
- the same value in binary format.
- """
- if ndec < 1:
- return "0"
- binary = []
- while ndec != 0:
- binary.append(ndec%2)
- ndec = ndec/2
- strbin = ""
- binary.reverse()
- for i in binary:
- strbin = strbin+str(i)
- return strbin
-
-def bin2hex(strbin):
- """
- Convert a string representing a binary number into a string
- representing the same value in hexadecimal format.
- """
- dic = { "0000":"0",
- "0001":"1",
- "0010":"2",
- "0011":"3",
- "0100":"4",
- "0101":"5",
- "0110":"6",
- "0111":"7",
- "1000":"8",
- "1001":"9",
- "1010":"A",
- "1011":"B",
- "1100":"C",
- "1101":"D",
- "1110":"E",
- "1111":"F"
- }
- while strbin.__len__()%4 != 0:
- strbin = '0' + strbin
- strh = ""
- for i in range(0, strbin.__len__()/4):
- strh = strh + dic[str(strbin[i*4:i*4+4])]
- return strh
diff --git a/TurtleArt/ringbuffer.py b/TurtleArt/ringbuffer.py
deleted file mode 100644
index 2afb5c9..0000000
--- a/TurtleArt/ringbuffer.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright (C) 2009, Benjamin Berg, Sebastian Berg
-# Copyright (C) 2010, Walter Bender
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import numpy as np
-
-
-class RingBuffer1d(object):
- """This class implements an array being written in as a ring and that can
- be read from continuously ending with the newest data or starting with the
- oldest. It returns a numpy array copy of the data;
- """
-
- def __init__(self, length, dtype=None):
- """Initialize the 1 dimensional ring buffer with the given lengths.
- The initial values are all 0s
- """
- self.offset = 0
-
- self._data = np.zeros(length, dtype=dtype)
-
- self.stored = 0
-
- def fill(self, number):
- self._data.fill(number)
- self.offset = 0
-
- def append(self, data):
- """Append to the ring buffer (and overwrite old data). If len(data)
- is greater then the ring buffers length, the newest data takes
- precedence.
- """
- data = np.asarray(data)
-
- if len(self._data) == 0:
- return
-
- if len(data) >= len(self._data):
- self._data[:] = data[-len(self._data):]
- self.offset = 0
- self.stored = len(self._data)
-
- elif len(self._data) - self.offset >= len(data):
- self._data[self.offset: self.offset + len(data)] = data
- self.offset = self.offset + len(data)
- self.stored += len(data)
- else:
- self._data[self.offset:] = data[:len(self._data) - self.offset]
- self._data[:len(data) - (len(self._data) - self.offset)] = \
- data[-len(data) + (len(self._data) - self.offset):]
- self.offset = len(data) - (len(self._data) - self.offset)
- self.stored += len(data)
-
- if len(self._data) <= self.stored:
- self.read = self._read
-
- def read(self, number=None, step=1):
- """Read the ring Buffer. Number can be positive or negative.
- Positive values will give the latest information, negative values will
- give the newest added information from the buffer. (in normal order)
-
- Before the buffer is filled once: This returns just None
- """
- return np.array([])
-
- def _read(self, number=None, step=1):
- """Read the ring Buffer. Number can be positive or negative.
- Positive values will give the latest information, negative values will
- give the newest added information from the buffer. (in normal order)
- """
- if number == None:
- number = len(self._data) // step
-
- number *= step
- assert abs(number) <= len(self._data), \
- 'Number to read*step must be smaller then length'
-
- if number < 0:
- if abs(number) <= self.offset:
- return self._data[self.offset + number:self.offset:step]
-
- spam = (self.offset - 1) % step
-
- return np.concatenate(
- (self._data[step - spam - 1 + self.offset + number::step],
- self._data[spam:self.offset:step]))
-
- if number - (len(self._data) - self.offset) > 0:
- spam = ((self.offset + number) - self.offset - 1) % step
- return np.concatenate(
- (self._data[self.offset:self.offset + number:step],
- self._data[spam:number -
- (len(self._data) - self.offset):step]))
-
- return self._data[self.offset:self.offset + number:step].copy()
diff --git a/TurtleArt/sprites.py b/TurtleArt/sprites.py
index fdcd72f..c633397 100644
--- a/TurtleArt/sprites.py
+++ b/TurtleArt/sprites.py
@@ -426,12 +426,15 @@ class Sprite:
b = ord(array[offset + 2])
return(r, g, b, a)
except IndexError:
+ """
print "Index Error: %d %d (%d, %d) (w: %d, h: %d) (%dx%d)"\
% (len(array), offset, x, y,
self.images[i].get_width(),
self.images[i].get_height(),
self.rect.width, self.rect.height)
- return(-1, -1, -1, -1)
+ """
+ pass
+ return(-1, -1, -1, -1)
else:
w, h = self.images[i].get_size()
if x < 0 or x > (w - 1) or y < 0 or y > (h - 1):
diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py
new file mode 100644
index 0000000..bfed2d7
--- /dev/null
+++ b/TurtleArt/tabasics.py
@@ -0,0 +1,1270 @@
+# -*- coding: utf-8 -*-
+#Copyright (c) 2011, Walter Bender
+
+#Permission is hereby granted, free of charge, to any person obtaining a copy
+#of this software and associated documentation files (the "Software"), to deal
+#in the Software without restriction, including without limitation the rights
+#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#copies of the Software, and to permit persons to whom the Software is
+#furnished to do so, subject to the following conditions:
+
+#The above copyright notice and this permission notice shall be included in
+#all copies or substantial portions of the Software.
+
+#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#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
+simply add a block of code to this file or to turtle_block_plugin.py,
+which contains additional blocks. (Even better, write your own plugin!!)
+
+
+Adding a new palette is simply a matter of:
+ palette = make_palette('mypalette', # the name of your palette
+ colors=["#00FF00", "#00A000"],
+ help_string=_('Palette of my custom commands'))
+
+For example, if we want to add a new turtle command, 'uturn', we'd use the
+add_block method in the Palette class.
+ palette.add_block('uturn', # the name of your block
+ style='basic-style', # the block style
+ label=_('u turn'), # the label for the block
+ prim_name='uturn', # code reference (see below)
+ help_string=_('turns the turtle 180 degrees'))
+
+ # 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))
+
+That's it. When you next run Turtle Art, you will have a 'uturn' block
+on the 'mypalette' palette.
+
+You will have to create icons for the palette-selector buttons. These
+are kept in the icons subdirectory. You need two icons:
+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
+from math import sqrt
+from random import uniform
+
+from gettext import gettext as _
+
+from tapalette import make_palette, define_logo_function
+from talogo import primitive_dictionary, logoerror
+from tautils import convert, chr_to_ord, round_int, strtype
+from taconstants import BLACK, WHITE, CONSTANTS
+
+def _num_type(x):
+ """ Is x a number type? """
+ if type(x) == int:
+ return True
+ if type(x) == float:
+ return True
+ if type(x) == ord:
+ return True
+ return False
+
+
+def _millisecond():
+ """ Current time in milliseconds """
+ return time() * 1000
+
+
+class Palettes():
+ """ a class for creating the palettes of blocks """
+
+ def __init__(self, parent):
+ self.tw = parent
+
+ self._turtle_palette()
+
+ self._pen_palette()
+
+ self._color_palette()
+
+ self._numbers_palette()
+
+ self._flow_palette()
+
+ self._blocks_palette()
+
+ self._trash_palette()
+
+ # Palette definitions
+
+ def _turtle_palette(self):
+ """ The basic Turtle Art turtle palette """
+
+ palette = make_palette('turtle',
+ colors=["#00FF00", "#00A000"],
+ help_string=_('Palette of turtle commands'))
+
+ primitive_dictionary['move'] = self._prim_move
+ palette.add_block('forward',
+ style='basic-style-1arg',
+ label=_('forward'),
+ prim_name='forward',
+ 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))
+
+ palette.add_block('back',
+ style='basic-style-1arg',
+ label=_('back'),
+ prim_name='back',
+ default=100,
+ logo_command='back',
+ help_string=_('moves turtle backward'))
+ self.tw.lc.def_prim('back', 1,
+ lambda self, x: primitive_dictionary['move'](
+ self.tw.canvas.forward, -x))
+
+ primitive_dictionary['clean'] = self.tw.lc.prim_clear
+ palette.add_block('clean',
+ style='basic-style-extended-vertical',
+ label=_('clean'),
+ prim_name='clean',
+ logo_command='clean',
+ help_string=_('clears the screen and reset the \
+turtle'))
+ self.tw.lc.def_prim('clean', 0,
+ lambda self: primitive_dictionary['clean']())
+
+ primitive_dictionary['right'] = self._prim_right
+ palette.add_block('left',
+ style='basic-style-1arg',
+ label=_('left'),
+ prim_name='left',
+ default=90,
+ logo_command='left',
+ help_string=_('turns turtle counterclockwise (angle \
+in degrees)'))
+ self.tw.lc.def_prim('left', 1,
+ lambda self, x: primitive_dictionary['right'](-x))
+
+ palette.add_block('right',
+ style='basic-style-1arg',
+ label=_('right'),
+ prim_name='right',
+ default=90,
+ 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))
+
+ primitive_dictionary['arc'] = self._prim_arc
+ palette.add_block('arc',
+ style='basic-style-2arg',
+ label=[_('arc'), _('angle'), _('radius')],
+ prim_name='arc',
+ 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))
+ define_logo_function('taarc', 'to taarc :a :r\rrepeat round :a \
+[right 1 forward (0.0175 * :r)]\rend\r')
+
+ palette.add_block('setxy2',
+ style='basic-style-2arg',
+ label=[_('set xy'), _('x'), _('y')],
+ prim_name='setxy2',
+ logo_command='tasetxy',
+ 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))
+ define_logo_function('tasetxy', 'to tasetxy :x :y\rsetxy :x :y\rend\r')
+
+ primitive_dictionary['set'] = self._prim_set
+ palette.add_block('seth',
+ style='basic-style-1arg',
+ label=_('set heading'),
+ prim_name='seth',
+ default=0,
+ 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))
+
+ palette.add_block('xcor',
+ style='box-style',
+ label=_('xcor'),
+ help_string=_('holds current x-coordinate value of \
+the turtle (can be used in place of a number block)'),
+ value_block=True,
+ prim_name='xcor',
+ logo_command='xcor')
+ self.tw.lc.def_prim(
+ 'xcor', 0, lambda self: self.tw.canvas.xcor / self.tw.coord_scale)
+
+ palette.add_block('ycor',
+ style='box-style',
+ label=_('ycor'),
+ help_string=_('holds current y-coordinate value of \
+the turtle (can be used in place of a number block)'),
+ value_block=True,
+ prim_name='ycor',
+ logo_command='ycor')
+ self.tw.lc.def_prim(
+ 'ycor', 0, lambda self: self.tw.canvas.ycor / self.tw.coord_scale)
+
+ palette.add_block('heading',
+ style='box-style',
+ label=_('heading'),
+ help_string=_('holds current heading value of the \
+turtle (can be used in place of a number block)'),
+ value_block=True,
+ prim_name='heading',
+ logo_command='heading')
+ self.tw.lc.def_prim(
+ 'heading', 0, lambda self: self.tw.canvas.heading)
+
+ palette.add_block('turtle-label',
+ hidden=True,
+ style='blank-style',
+ label=['turtle'])
+
+ # Deprecated
+ palette.add_block('setxy',
+ hidden=True,
+ style='basic-style-2arg',
+ label=[_('set xy'), _('x'), _('y')],
+ prim_name='setxy',
+ default=[0, 0],
+ 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))
+ define_logo_function('tasetxypenup', 'to tasetxypenup :x :y\rpenup\r\
+setxy :x :y\rpendown\rend\r')
+
+ def _pen_palette(self):
+ """ The basic Turtle Art pen palette """
+
+ palette = make_palette('pen',
+ colors=["#00FFFF", "#00A0A0"],
+ help_string=_('Palette of pen commands'))
+
+ palette.add_block('penup',
+ style='basic-style-extended-vertical',
+ label=_('pen up'),
+ 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))
+
+ palette.add_block('pendown',
+ style='basic-style-extended-vertical',
+ label=_('pen down'),
+ 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))
+
+ palette.add_block('setpensize',
+ style='basic-style-1arg',
+ label=_('set pen size'),
+ prim_name='setpensize',
+ default=5,
+ 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\rsetpensize \
+round :a\rend\r')
+
+ palette.add_block('fillscreen',
+ style='basic-style-2arg',
+ label=[_('fill screen'), _('color'), _('shade')],
+ prim_name='fillscreen',
+ default=[60, 80],
+ 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))
+ define_logo_function('tasetbackground', 'to tasetbackground :color \
+:shade\rtasetshade :shade\rsetbackground :color\rend\r')
+
+ palette.add_block('pensize',
+ style='box-style',
+ label=_('pen size'),
+ help_string=_('holds current pen size (can be used \
+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)
+ define_logo_function('tapensize', 'to tapensize\routput first round \
+pensize\rend\r')
+
+ palette.add_block('startfill',
+ style='basic-style-extended-vertical',
+ label=_('start fill'),
+ 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())
+
+ palette.add_block('stopfill',
+ style='basic-style-extended-vertical',
+ label=_('end fill'),
+ 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())
+
+ def _color_palette(self):
+ """ The basic Turtle Art color palette """
+
+ palette = make_palette('colors',
+ colors=["#00FFFF", "#00A0A0"],
+ help_string=_('Palette of pen colors'))
+
+ palette.add_block('setcolor',
+ style='basic-style-1arg',
+ label=_('set color'),
+ prim_name='setcolor',
+ default=0,
+ 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))
+
+ palette.add_block('setshade',
+ style='basic-style-1arg',
+ label=_('set shade'),
+ prim_name='setshade',
+ default=50,
+ 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))
+
+ palette.add_block('setgray',
+ style='basic-style-1arg',
+ label=_('set gray'),
+ prim_name='setgray',
+ 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))
+
+ palette.add_block('color',
+ style='box-style',
+ label=_('color'),
+ help_string=_('holds current pen color (can be used \
+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)
+
+ palette.add_block('shade',
+ style='box-style',
+ label=_('shade'),
+ help_string=_('holds current pen shade'),
+ value_block=True,
+ prim_name='shade',
+ logo_command=':shade')
+ self.tw.lc.def_prim('shade', 0, lambda self: self.tw.canvas.shade)
+
+ palette.add_block('gray',
+ style='box-style',
+ label=_('gray'),
+ help_string=_('holds current gray level (can be 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._make_constant(palette, 'red', CONSTANTS['red'])
+ self._make_constant(palette, 'orange', CONSTANTS['orange'])
+ self._make_constant(palette, 'yellow', CONSTANTS['yellow'])
+ self._make_constant(palette, 'green', CONSTANTS['green'])
+ self._make_constant(palette, 'cyan', CONSTANTS['cyan'])
+ self._make_constant(palette, 'blue', CONSTANTS['blue'])
+ self._make_constant(palette, 'purple', CONSTANTS['purple'])
+ self._make_constant(palette, 'white', WHITE)
+ self._make_constant(palette, 'black', 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', '\
+to tasetpalette :i :r :g :b :myshade \r\
+make "s ((:myshade - 50) / 50) \r\
+ifelse lessp :s 0 [ \r\
+make "s (1 + (:s *0.8)) \r\
+make "r (:r * :s) \r\
+make "g (:g * :s) \r\
+make "b (:b * :s) \r\
+] [ \
+make "s (:s * 0.9) \r\
+make "r (:r + ((99-:r) * :s)) \r\
+make "g (:g + ((99-:g) * :s)) \r\
+make "b (:b + ((99-:b) * :s)) \r\
+] \
+setpalette :i (list :r :g :b) \r\
+end \r\
+\
+to rgb :myi :mycolors :myshade \r\
+make "myr first :mycolors \r\
+make "mycolors butfirst :mycolors \r\
+make "myg first :mycolors \r\
+make "mycolors butfirst :mycolors \r\
+make "myb first :mycolors \r\
+make "mycolors butfirst :mycolors \r\
+tasetpalette :myi :myr :myg :myb :myshade \r\
+output :mycolors \r\
+end \r\
+\
+to processcolor :mycolors :myshade \r\
+if emptyp :mycolors [stop] \r\
+make "i :i + 1 \r\
+processcolor (rgb :i :mycolors :myshade) :myshade \r\
+end \r\
+\
+to tasetshade :shade \r\
+make "myshade modulo :shade 200 \r\
+if greaterp :myshade 99 [make "myshade (199-:myshade)] \r\
+make "i 7 \r\
+make "mycolors :colors \r\
+processcolor :mycolors :myshade \r\
+end \r\
+\
+to tasetpencolor :c \r\
+make "color (modulo (round :c) 100) \r\
+setpencolor :color + 8 \r\
+end \r\
+\
+make "colors [ \
+99 0 0 99 5 0 99 10 0 99 15 0 99 20 0 \
+99 25 0 99 30 0 99 35 0 99 40 0 99 45 0 \
+99 50 0 99 55 0 99 60 0 99 65 0 99 70 0 \
+99 75 0 99 80 0 99 85 0 99 90 0 99 95 0 \
+99 99 0 90 99 0 80 99 0 70 99 0 60 99 0 \
+50 99 0 40 99 0 30 99 0 20 99 0 10 99 0 \
+ 0 99 0 0 99 5 0 99 10 0 99 15 0 99 20 \
+ 0 99 25 0 99 30 0 99 35 0 99 40 0 99 45 \
+ 0 99 50 0 99 55 0 99 60 0 99 65 0 99 70 \
+ 0 99 75 0 99 80 0 99 85 0 99 90 0 99 95 \
+ 0 99 99 0 95 99 0 90 99 0 85 99 0 80 99 \
+ 0 75 99 0 70 99 0 65 99 0 60 99 0 55 99 \
+ 0 50 99 0 45 99 0 40 99 0 35 99 0 30 99 \
+ 0 25 99 0 20 99 0 15 99 0 10 99 0 5 99 \
+ 0 0 99 5 0 99 10 0 99 15 0 99 20 0 99 \
+25 0 99 30 0 99 35 0 99 40 0 99 45 0 99 \
+50 0 99 55 0 99 60 0 99 65 0 99 70 0 99 \
+75 0 99 80 0 99 85 0 99 90 0 99 95 0 99 \
+99 0 99 99 0 90 99 0 80 99 0 70 99 0 60 \
+99 0 50 99 0 40 99 0 30 99 0 20 99 0 10] \r\
+make "shade 50 \r\
+tasetshade :shade \r')
+
+ def _numbers_palette(self):
+ """ The basic Turtle Art numbers palette """
+
+ palette = make_palette('numbers',
+ colors=["#FF00FF", "#A000A0"],
+ help_string=_('Palette of numeric operators'))
+
+ primitive_dictionary['plus'] = self._prim_plus
+ palette.add_block('plus2',
+ style='number-style',
+ label='+',
+ special_name=_('plus'),
+ prim_name='plus',
+ logo_command='sum',
+ help_string=_('adds two alphanumeric inputs'))
+ self.tw.lc.def_prim(
+ 'plus', 2, lambda self, x, y: primitive_dictionary['plus'](x, y))
+
+ primitive_dictionary['minus'] = self._prim_minus
+ palette.add_block('minus2',
+ style='number-style-porch',
+ label='–',
+ special_name=_('minus'),
+ prim_name='minus',
+ logo_command='taminus',
+ help_string=_('subtracts bottom numeric input from \
+top numeric input'))
+ self.tw.lc.def_prim(
+ 'minus', 2, lambda self, x, y: primitive_dictionary['minus'](x, y))
+ define_logo_function('taminus', 'to taminus :y :x\routput sum :x minus \
+:y\rend\r')
+
+ primitive_dictionary['product'] = self._prim_product
+ palette.add_block('product2',
+ style='number-style',
+ label='×',
+ special_name=_('multiply'),
+ prim_name='product',
+ logo_command='product',
+ help_string=_('multiplies two numeric inputs'))
+ self.tw.lc.def_prim(
+ 'product', 2,
+ lambda self, x, y: primitive_dictionary['product'](x, y))
+
+ primitive_dictionary['division'] = self._prim_careful_divide
+ palette.add_block('division2',
+ style='number-style-porch',
+ label='/',
+ special_name=_('divide'),
+ prim_name='division',
+ logo_command='quotient',
+ help_string=_('divides top numeric input (numerator) \
+by bottom numeric input (denominator)'))
+ self.tw.lc.def_prim(
+ 'division', 2,
+ lambda self, x, y: primitive_dictionary['division'](x, y))
+
+ primitive_dictionary['id'] = self._prim_identity
+ palette.add_block('identity2',
+ style='number-style-1arg',
+ label='←',
+ special_name=_('identity'),
+ prim_name='id',
+ help_string=_('identity operator used for extending \
+blocks'))
+ self.tw.lc.def_prim('id', 1,
+ lambda self, x: primitive_dictionary['id'](x))
+
+ primitive_dictionary['remainder'] = self._prim_mod
+ palette.add_block('remainder2',
+ style='number-style-porch',
+ label=_('mod'),
+ special_name=_('mod'),
+ prim_name='remainder',
+ logo_command='remainder',
+ help_string=_('modular (remainder) operator'))
+ self.tw.lc.def_prim('remainder', 2,
+ lambda self, x, y: primitive_dictionary['remainder'](x, y))
+
+ primitive_dictionary['sqrt'] = self._prim_sqrt
+ palette.add_block('sqrt',
+ style='number-style-1arg',
+ label=_('√'),
+ special_name=_('square root'),
+ prim_name='sqrt',
+ logo_command='tasqrt',
+ help_string=_('calculates square root'))
+ self.tw.lc.def_prim('sqrt', 1,
+ lambda self, x: primitive_dictionary['sqrt'](x))
+
+ primitive_dictionary['random'] = self._prim_random
+ palette.add_block('random',
+ style='number-style-block',
+ label=[_('random'), _('min'), _('max')],
+ default=[0, 100],
+ prim_name='random',
+ logo_command='tarandom',
+ help_string=_('returns random number between minimum \
+(top) and maximum (bottom) values'))
+ self.tw.lc.def_prim(
+ 'random', 2, lambda self, x, y: primitive_dictionary['random'](
+ x, y))
+ define_logo_function('tarandom', 'to tarandom :min :max\r \
+output (random (:max - :min)) + :min\rend\r')
+
+ palette.add_block('number',
+ style='box-style',
+ label='100',
+ default=100,
+ special_name=_('number'),
+ help_string=_('used as numeric input in mathematic \
+operators'))
+
+ primitive_dictionary['more'] = self._prim_more
+ palette.add_block('greater2',
+ style='compare-porch-style',
+ label='>',
+ special_name=_('greater than'),
+ prim_name='greater?',
+ logo_command='greater?',
+ help_string=_('logical greater-than operator'))
+ self.tw.lc.def_prim(
+ 'greater?', 2, lambda self, x, y: primitive_dictionary['more'](x, y))
+
+ primitive_dictionary['less'] = self._prim_less
+ palette.add_block('less2',
+ style='compare-porch-style',
+ label='<',
+ special_name=_('less than'),
+ prim_name='less?',
+ logo_command='less?',
+ help_string=_('logical less-than operator'))
+ self.tw.lc.def_prim(
+ 'less?', 2, lambda self, x, y: primitive_dictionary['less'](x, y))
+
+ primitive_dictionary['equal'] = self._prim_equal
+ palette.add_block('equal2',
+ style='compare-style',
+ label='=',
+ special_name=_('equal'),
+ prim_name='equal?',
+ logo_command='equal?',
+ help_string=_('logical equal-to operator'))
+ self.tw.lc.def_prim(
+ 'equal?', 2, lambda self, x, y: primitive_dictionary['equal'](x, y))
+
+ palette.add_block('not',
+ style='not-style',
+ label=_('not'),
+ prim_name='not',
+ logo_command='not',
+ help_string=_('logical NOT operator'))
+ self.tw.lc.def_prim('not', 1, lambda self, x: not x)
+
+ primitive_dictionary['and'] = self._prim_and
+ palette.add_block('and2',
+ style='boolean-style',
+ label=_('and'),
+ prim_name='and',
+ logo_command='and',
+ special_name=_('and'),
+ help_string=_('logical AND operator'))
+ self.tw.lc.def_prim(
+ 'and', 2, lambda self, x, y: primitive_dictionary['and'](x, y))
+
+ primitive_dictionary['or'] = self._prim_or
+ palette.add_block('or2',
+ style='boolean-style',
+ label=_('or'),
+ prim_name='or',
+ logo_command='or',
+ special_name=_('or'),
+ help_string=_('logical OR operator'))
+ self.tw.lc.def_prim(
+ 'or', 2, lambda self, x, y: primitive_dictionary['or'](x, y))
+
+ def _flow_palette(self):
+ """ The basic Turtle Art flow palette """
+
+ palette = make_palette('flow',
+ colors=["#FFC000", "#A08000"],
+ help_string=_('Palette of flow operators'))
+
+ primitive_dictionary['wait'] = self._prim_wait
+ palette.add_block('wait',
+ style='basic-style-1arg',
+ label=_('wait'),
+ prim_name='wait',
+ default=1,
+ logo_command='wait',
+ help_string=_('pauses program execution a specified \
+number of seconds'))
+ self.tw.lc.def_prim('wait', 1, primitive_dictionary['wait'], True)
+
+ primitive_dictionary['forever'] = self._prim_forever
+ palette.add_block('forever',
+ style='flow-style',
+ label=_('forever'),
+ prim_name='forever',
+ default=[None, 'vspace'],
+ logo_command='forever',
+ help_string=_('loops forever'))
+ self.tw.lc.def_prim('forever', 1, primitive_dictionary['forever'], True)
+
+ primitive_dictionary['repeat'] = self._prim_repeat
+ palette.add_block('repeat',
+ style='flow-style-1arg',
+ label=[' ', _('repeat')],
+ prim_name='repeat',
+ default=[4, None, 'vspace'],
+ logo_command='repeat',
+ special_name=_('repeat'),
+ help_string=_('loops specified number of times'))
+ self.tw.lc.def_prim('repeat', 2, primitive_dictionary['repeat'], True)
+
+ primitive_dictionary['if'] = self._prim_if
+ palette.add_block('if',
+ style='flow-style-boolean',
+ label=[' ', _('if'), _('then')],
+ prim_name='if',
+ default=[None, None, 'vspace'],
+ special_name=_('if then'),
+ logo_command='if',
+ help_string=_('if-then operator that uses boolean \
+operators from Numbers palette'))
+ self.tw.lc.def_prim('if', 2, primitive_dictionary['if'], True)
+
+ primitive_dictionary['ifelse'] = self._prim_ifelse
+ palette.add_block('ifelse',
+ style='flow-style-else',
+ label=[' ', _('if'), _('then else')],
+ prim_name='ifelse',
+ default=[None, 'vspace', None, 'vspace'],
+ logo_command='ifelse',
+ special_name=_('if then else'),
+ help_string=_('if-then-else operator that uses \
+boolean operators from Numbers palette'))
+ self.tw.lc.def_prim('ifelse', 3, primitive_dictionary['ifelse'], True)
+
+ palette.add_block('hspace',
+ style='flow-style-tail',
+ label=' ',
+ prim_name='nop',
+ special_name=_('horizontal space'),
+ help_string=_('jogs stack right'))
+ self.tw.lc.def_prim('nop', 0, lambda self: None)
+
+ palette.add_block('vspace',
+ style='basic-style-extended-vertical',
+ label=' ',
+ prim_name='nop',
+ special_name=_('vertical space'),
+ help_string=_('jogs stack down'))
+ self.tw.lc.def_prim('nop', 0, lambda self: None)
+
+ primitive_dictionary['stopstack'] = self._prim_stopstack
+ palette.add_block('stopstack',
+ style='basic-style-tail',
+ label=_('stop action'),
+ prim_name='stopstack',
+ logo_command='stop',
+ help_string=_('stops current action'))
+ self.tw.lc.def_prim('stopstack', 0,
+ lambda self: primitive_dictionary['stopstack']())
+
+ def _blocks_palette(self):
+ """ The basic Turtle Art blocks palette """
+
+ palette = make_palette('blocks',
+ colors=["#FFFF00", "#A0A000"],
+ help_string=_('Palette of variable blocks'))
+
+ primitive_dictionary['start'] = self._prim_start
+ palette.add_block('start',
+ style='basic-style-head',
+ label=_('start'),
+ prim_name='start',
+ logo_command='to start\r',
+ help_string=_('connects action to toolbar run \
+buttons'))
+ self.tw.lc.def_prim('start', 0,
+ lambda self: primitive_dictionary['start']())
+
+ primitive_dictionary['setbox'] = self._prim_setbox
+ palette.add_block('storeinbox1',
+ style='basic-style-1arg',
+ label=_('store in box 1'),
+ prim_name='storeinbox1',
+ default=100,
+ logo_command='make "box1',
+ help_string=_('stores numeric value in Variable 1'))
+ self.tw.lc.def_prim('storeinbox1', 1,
+ lambda self, x: primitive_dictionary['setbox'](
+ 'box1', None, x))
+
+ palette.add_block('storeinbox2',
+ style='basic-style-1arg',
+ label=_('store in box 2'),
+ prim_name='storeinbox2',
+ default=100,
+ logo_command='make "box2',
+ help_string=_('stores numeric value in Variable 2'))
+ self.tw.lc.def_prim('storeinbox2', 1,
+ lambda self, x: primitive_dictionary['setbox'](
+ 'box2', None, x))
+
+ palette.add_block('string',
+ style='box-style',
+ label=_('text'),
+ default=_('text'),
+ special_name=_('text'),
+ help_string=_('string value'))
+
+ palette.add_block('box1',
+ style='box-style',
+ label=_('box 1'),
+ prim_name='box1',
+ logo_command=':box1',
+ help_string=_('Variable 1 (numeric value)'),
+ value_block=True)
+ self.tw.lc.def_prim('box1', 0, lambda self: self.tw.lc.boxes['box1'])
+
+ palette.add_block('box2',
+ style='box-style',
+ label=_('box 2'),
+ prim_name='box2',
+ logo_command=':box2',
+ help_string=_('Variable 2 (numeric value)'),
+ value_block=True)
+ self.tw.lc.def_prim('box2', 0, lambda self: self.tw.lc.boxes['box2'])
+
+ primitive_dictionary['box'] = self._prim_box
+ palette.add_block('box',
+ style='number-style-1strarg',
+ label=_('box'),
+ prim_name='box',
+ default=_('my box'),
+ logo_command='box',
+ help_string=_('named variable (numeric value)'))
+ self.tw.lc.def_prim('box', 1,
+ lambda self, x: primitive_dictionary['box'](x))
+
+ palette.add_block('storein',
+ style='basic-style-2arg',
+ label=[_('store in'), _('box'), _('value')],
+ prim_name='storeinbox',
+ logo_command='storeinbox',
+ default=[_('my box'), 100],
+ help_string=_('stores numeric value in named \
+variable'))
+ self.tw.lc.def_prim('storeinbox', 2,
+ lambda self, x, y: primitive_dictionary['setbox'](
+ 'box3', x, y))
+
+ palette.add_block('hat',
+ style='basic-style-head-1arg',
+ label=_('action'),
+ prim_name='nop3',
+ default=_('stack'),
+ logo_command='to action',
+ help_string=_('top of nameable action stack'))
+ self.tw.lc.def_prim('nop3', 1, lambda self, x: None)
+
+ palette.add_block('hat1',
+ style='basic-style-head',
+ label=_('action 1'),
+ prim_name='nop1',
+ logo_command='to stack1\r',
+ help_string=_('top of Action 1 stack'))
+ self.tw.lc.def_prim('nop1', 0, lambda self: None)
+
+ palette.add_block('hat2',
+ style='basic-style-head',
+ label=_('action 2'),
+ prim_name='nop2',
+ logo_command='to stack2\r',
+ help_string=_('top of Action 2 stack'))
+ self.tw.lc.def_prim('nop2', 0, lambda self: None)
+
+ primitive_dictionary['stack'] = self._prim_stack
+ palette.add_block('stack',
+ style='basic-style-1arg',
+ label=_('action'),
+ prim_name='stack',
+ logo_command='action',
+ default=_('action'),
+ help_string=_('invokes named action stack'))
+ self.tw.lc.def_prim('stack', 1, primitive_dictionary['stack'], True)
+
+ primitive_dictionary['stack1'] = self._prim_stack1
+ palette.add_block('stack1',
+ style='basic-style-extended-vertical',
+ label=_('action 1'),
+ prim_name='stack1',
+ logo_command='stack1',
+ help_string=_('invokes Action 1 stack'))
+ self.tw.lc.def_prim('stack1', 0, primitive_dictionary['stack1'], True)
+
+ primitive_dictionary['stack2'] = self._prim_stack2
+ palette.add_block('stack2',
+ style='basic-style-extended-vertical',
+ label=_('action 2'),
+ prim_name='stack2',
+ logo_command='stack2',
+ help_string=_('invokes Action 2 stack'))
+ self.tw.lc.def_prim('stack2', 0, primitive_dictionary['stack2'], True)
+
+ def _trash_palette(self):
+ """ The basic Turtle Art turtle palette """
+
+ palette = make_palette('trash',
+ colors=["#FFFF00", "#A0A000"],
+ help_string=_('trash'))
+
+ palette.add_block('empty',
+ style='basic-style-tail',
+ label=_('empty trash'),
+ help_string=_('permanently deletes items in trash'))
+
+ palette.add_block('restoreall',
+ style='basic-style-head',
+ label=_('restore all'),
+ help_string=_('restore all blocks from trash'))
+
+ palette.add_block('trashall',
+ style='basic-style-tail',
+ label=_('clear all'),
+ help_string=_('move all blocks to trash'))
+
+ # Block primitives
+
+ def _prim_and(self, x, y):
+ """ Logical and """
+ return x & y
+
+ def _prim_arc(self, cmd, value1, value2):
+ """ Turtle draws an arc of degree, radius """
+ cmd(float(value1), float(value2))
+ self.tw.lc.update_label_value(
+ 'xcor', self.tw.canvas.xcor / 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)
+
+ def _prim_box(self, x):
+ """ Retrieve value from named box """
+ if type(convert(x, float, False)) == float:
+ if int(float(x)) == x:
+ x = int(x)
+ try:
+ return self.tw.lc.boxes['box3' + str(x)]
+ except KeyError:
+ raise logoerror("#emptybox")
+
+ def _prim_forever(self, blklist):
+ """ Do list forever """
+ while True:
+ self.tw.lc.icall(self.tw.lc.evline, blklist[:])
+ yield True
+ if self.tw.lc.procstop:
+ break
+ self.tw.lc.ireturn()
+ yield True
+
+ def _prim_if(self, boolean, blklist):
+ """ If bool, do list """
+ if boolean:
+ self.tw.lc.icall(self.tw.lc.evline, blklist[:])
+ yield True
+ self.tw.lc.ireturn()
+ yield True
+
+ def _prim_ifelse(self, boolean, list1, list2):
+ """ If bool, do list1, else do list2 """
+ if boolean:
+ self.tw.lc.ijmp(self.tw.lc.evline, list1[:])
+ yield True
+ else:
+ self.tw.lc.ijmp(self.tw.lc.evline, list2[:])
+ yield True
+
+ def _prim_move(self, cmd, value1, value2=None, pendown=True):
+ """ Turtle moves by method specified in value1 """
+ if value2 is None:
+ cmd(value1)
+ else:
+ cmd(float(value1), float(value2), pendown=pendown)
+ self.tw.lc.update_label_value('xcor',
+ self.tw.canvas.xcor / self.tw.coord_scale)
+ self.tw.lc.update_label_value('ycor',
+ self.tw.canvas.ycor / self.tw.coord_scale)
+
+ def _prim_or(self, x, y):
+ """ Logical or """
+ return x | y
+
+ def _prim_repeat(self, num, blklist):
+ """ Repeat list num times. """
+ num = self.tw.lc.int(num)
+ for i in range(num):
+ self.tw.lc.icall(self.tw.lc.evline, blklist[:])
+ yield True
+ if self.tw.lc.procstop:
+ break
+ self.tw.lc.ireturn()
+ yield True
+
+ def _prim_right(self, value):
+ """ Turtle rotates clockwise """
+ self.tw.canvas.right(float(value))
+ self.tw.lc.update_label_value('heading', self.tw.canvas.heading)
+
+ def _prim_set(self, name, cmd, value=None):
+ """ Set a value and update the associated value blocks """
+ if value is not None:
+ cmd(value)
+ self.tw.lc.update_label_value(name, value)
+
+ def _prim_setbox(self, name, x, val):
+ """ Define value of named box """
+ if x is not None:
+ if type(convert(x, float, False)) == float:
+ if int(float(x)) == x:
+ x = int(x)
+ self.tw.lc.boxes[name + str(x)] = val
+ return
+
+ self.tw.lc.boxes[name] = val
+ self.tw.lc.update_label_value(name, val)
+
+ def _prim_stack(self, x):
+ """ Process a named stack """
+ if type(convert(x, float, False)) == float:
+ if int(float(x)) == x:
+ x = int(x)
+ if 'stack3' + str(x) not in self.tw.lc.stacks or \
+ self.tw.lc.stacks['stack3' + str(x)] is None:
+ raise logoerror("#nostack")
+ self.tw.lc.icall(self.tw.lc.evline,
+ self.tw.lc.stacks['stack3' + str(x)][:])
+ yield True
+ self.tw.lc.procstop = False
+ self.tw.lc.ireturn()
+ yield True
+
+ def _prim_stack1(self):
+ """ Process Stack 1 """
+ if self.tw.lc.stacks['stack1'] is None:
+ raise logoerror("#nostack")
+ self.tw.lc.icall(self.tw.lc.evline,
+ self.tw.lc.stacks['stack1'][:])
+ yield True
+ self.tw.lc.procstop = False
+ self.tw.lc.ireturn()
+ yield True
+
+ def _prim_stack2(self):
+ """ 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'][:])
+ yield True
+ self.tw.lc.procstop = False
+ self.tw.lc.ireturn()
+ yield True
+
+ def _prim_start(self):
+ """ Start block: recenter """
+ if self.tw.running_sugar:
+ self.tw.activity.recenter()
+
+ def _prim_stopstack(self):
+ """ 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()
+ endtime = _millisecond() + wait_time * 1000.
+ while _millisecond() < endtime:
+ yield True
+ self.tw.active_turtle.hide()
+ self.tw.lc.ireturn()
+ yield True
+
+ # Math primitivies
+
+ def _prim_careful_divide(self, x, y):
+ """ Raise error on divide by zero """
+ try:
+ return x / y
+ except ZeroDivisionError:
+ raise logoerror("#zerodivide")
+ except TypeError:
+ try:
+ return self._string_to_num(x) / self._string_to_num(y)
+ except ZeroDivisionError:
+ raise logoerror("#zerodivide")
+ except ValueError:
+ raise logoerror("#syntaxerror")
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_equal(self, x, y):
+ """ Numeric and logical equal """
+ try:
+ return float(x) == float(y)
+ except TypeError:
+ typex, typey = False, False
+ if strtype(x):
+ typex = True
+ if strtype(y):
+ typey = True
+ if typex and typey:
+ return x == y
+ try:
+ return self._string_to_num(x) == self._string_to_num(y)
+ except ValueError:
+ raise logoerror("#syntaxerror")
+
+ def _prim_less(self, x, y):
+ """ Compare numbers and strings """
+ try:
+ return float(x) < float(y)
+ except ValueError:
+ typex, typey = False, False
+ if strtype(x):
+ typex = True
+ if strtype(y):
+ typey = True
+ if typex and typey:
+ return x < y
+ try:
+ return self._string_to_num(x) < self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_more(self, x, y):
+ """ Compare numbers and strings """
+ return self._prim_less(y, x)
+
+ def _prim_plus(self, x, y):
+ """ Add numbers, concat strings """
+ if _num_type(x) and _num_type(y):
+ return(x + y)
+ else:
+ if _num_type(x):
+ xx = str(round_int(x))
+ else:
+ xx = str(x)
+ if _num_type(y):
+ yy = str(round_int(y))
+ else:
+ yy = str(y)
+ return(xx + yy)
+
+ def _prim_minus(self, x, y):
+ """ Numerical subtraction """
+ if _num_type(x) and _num_type(y):
+ return(x - y)
+ try:
+ return self._string_to_num(x) - self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_product(self, x, y):
+ """ Numerical multiplication """
+ if _num_type(x) and _num_type(y):
+ return(x * y)
+ try:
+ return self._string_to_num(x) * self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_mod(self, x, y):
+ """ Numerical mod """
+ if _num_type(x) and _num_type(y):
+ return(x % y)
+ try:
+ return self._string_to_num(x) % self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+ except ValueError:
+ raise logoerror("#syntaxerror")
+
+ def _prim_sqrt(self, x):
+ """ Square root """
+ if _num_type(x):
+ if x < 0:
+ raise logoerror("#negroot")
+ return sqrt(x)
+ try:
+ return sqrt(self._string_to_num(x))
+ except ValueError:
+ raise logoerror("#negroot")
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_random(self, x, y):
+ """ Random integer """
+ if _num_type(x) and _num_type(y):
+ return(int(round(uniform(x, y), 0)))
+ xx, xflag = chr_to_ord(x)
+ yy, yflag = chr_to_ord(y)
+ if xflag and yflag:
+ return chr(int(round(uniform(xx, yy), 0)))
+ if not xflag:
+ xx = self._string_to_num(x)
+ if not yflag:
+ yy = self._string_to_num(y)
+ try:
+ return(int(round(uniform(xx, yy), 0)))
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_identity(self, x):
+ """ Identity function """
+ return(x)
+
+ # Utilities
+
+ def _string_to_num(self, x):
+ """ Try to comvert a string to a number """
+ if type(x) is float:
+ return(x)
+ if type(x) is int:
+ return(x)
+ if type(x) is ord:
+ return(int(x))
+ xx = convert(x.replace(self.tw.decimal_point, '.'), float)
+ if type(xx) is float:
+ return xx
+ else:
+ xx, xflag = chr_to_ord(x)
+ if xflag:
+ return xx
+ else:
+ raise logoerror("#syntaxerror")
+
+ def _make_constant(self, palette, block_name, constant):
+ """ Factory for constant blocks """
+ palette.add_block(block_name, style='box-style',
+ label=_(block_name), prim_name=block_name,
+ logo_command=block_name)
+ self.tw.lc.def_prim(block_name, 0, lambda self: constant)
diff --git a/TurtleArt/tablock.py b/TurtleArt/tablock.py
index 05b95ae..bcca2cd 100644
--- a/TurtleArt/tablock.py
+++ b/TurtleArt/tablock.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-#Copyright (c) 2010 Walter Bender
+#Copyright (c) 2010,11 Walter Bender
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
@@ -20,31 +20,21 @@
#THE SOFTWARE.
import gtk
-
from gettext import gettext as _
-from taconstants import EXPANDABLE, EXPANDABLE_BLOCKS, EXPANDABLE_ARGS, \
- PRIMITIVES, OLD_NAMES, BLOCK_SCALE, BLOCK_NAMES, CONTENT_BLOCKS, \
- PALETTES, COLORS, BASIC_STYLE_HEAD, BASIC_STYLE_HEAD_1ARG, \
- BASIC_STYLE_TAIL, BASIC_STYLE, BASIC_STYLE_EXTENDED, BASIC_STYLE_1ARG, \
- BASIC_STYLE_VAR_ARG, BULLET_STYLE, BASIC_STYLE_2ARG, BOX_STYLE, \
- BOX_STYLE_MEDIA, NUMBER_STYLE, NUMBER_STYLE_VAR_ARG, NUMBER_STYLE_BLOCK, \
- NUMBER_STYLE_PORCH, NUMBER_STYLE_1ARG, NUMBER_STYLE_1STRARG, \
- COMPARE_STYLE, BOOLEAN_STYLE, NOT_STYLE, FLOW_STYLE, FLOW_STYLE_TAIL, \
- FLOW_STYLE_1ARG, FLOW_STYLE_BOOLEAN, FLOW_STYLE_WHILE, FLOW_STYLE_ELSE, \
- COLLAPSIBLE_TOP, COLLAPSIBLE_TOP_NO_ARM, COLLAPSIBLE_TOP_NO_LABEL, \
- COLLAPSIBLE_TOP_NO_ARM_NO_LABEL, COLLAPSIBLE_BOTTOM, PORTFOLIO_STYLE_2x2, \
- PORTFOLIO_STYLE_1x1, PORTFOLIO_STYLE_2x1, PORTFOLIO_STYLE_1x2, \
- STANDARD_STROKE_WIDTH, BOX_COLORS, GRADIENT_COLOR, \
- BASIC_STYLE_EXTENDED_VERTICAL, CONSTANTS, INVISIBLE
+from taconstants import EXPANDABLE, EXPANDABLE_ARGS, OLD_NAMES, CONSTANTS, \
+ STANDARD_STROKE_WIDTH, BLOCK_SCALE, BOX_COLORS, GRADIENT_COLOR
+from tapalette import palette_blocks, block_colors, expandable_blocks, \
+ content_blocks, block_names, block_primitives, block_styles, \
+ special_block_colors
from tasprite_factory import SVG, svg_str_to_pixbuf
import sprites
-import logging
-_logger = logging.getLogger('turtleart-activity')
+from tautils import debug_output, error_output
class Blocks:
+
""" A class for the list of blocks and everything they share in common """
def __init__(self, font_scale_factor=1, decimal_point='.'):
@@ -130,7 +120,9 @@ class Block:
""" A class for the individual blocks """
def __init__(self, block_list, sprite_list, name, x, y, type='block',
- values=[], scale=BLOCK_SCALE, colors=['#FF0000', '#A00000']):
+ values=[], scale=BLOCK_SCALE[0],
+ colors=['#A0A0A0', '#808080']):
+
self.block_list = block_list
self.spr = None
self.shapes = [None, None]
@@ -150,6 +142,51 @@ class Block:
self._font_size = [6.0, 4.5]
self._image = None
+ self.block_methods = {
+ 'basic-style': self._make_basic_style,
+ 'blank-style': self._make_blank_style,
+ 'basic-style-head': self._make_basic_style_head,
+ 'basic-style-head-1arg': self._make_basic_style_head_1arg,
+ 'basic-style-tail': self._make_basic_style_tail,
+ 'basic-style-extended': [self._make_basic_style, 16, 16],
+ 'basic-style-extended-vertical': [self._make_basic_style, 0, 4],
+ 'basic-style-1arg': self._make_basic_style_1arg,
+ 'basic-style-2arg': self._make_basic_style_2arg,
+ 'basic-style-3arg': self._make_basic_style_3arg,
+ 'basic-style-var-arg': self._make_basic_style_var_arg,
+ 'invisible': self._make_invisible_style,
+ 'bullet-style': self._make_bullet_style,
+ 'box-style': self._make_box_style,
+ 'box-style-media': self._make_media_style,
+ 'number-style': self._make_number_style,
+ 'number-style-block': self._make_number_style_block,
+ 'number-style-porch': self._make_number_style_porch,
+ 'number-style-1arg': self._make_number_style_1arg,
+ 'number-style-1strarg': self._make_number_style_1strarg,
+ 'number-style-var-arg': self._make_number_style_var_arg,
+ 'compare-style': self._make_compare_style,
+ 'compare-porch-style': self._make_compare_porch_style,
+ 'boolean-style': self._make_boolean_style,
+ 'not-style': self._make_not_style,
+ 'flow-style': self._make_flow_style,
+ 'flow-style-tail': self._make_flow_style_tail,
+ 'flow-style-1arg': self._make_flow_style_1arg,
+ 'flow-style-boolean': self._make_flow_style_boolean,
+ 'flow-style-while': self._make_flow_style_while,
+ 'flow-style-else': self._make_flow_style_else,
+ 'collapsible-top': [self._make_collapsible_style_top, True, True],
+ 'collapsible-top-no-arm': [self._make_collapsible_style_top,
+ False, True],
+ 'collapsible-top-no-label': [self._make_collapsible_style_top,
+ True, False],
+ 'collapsible-top-no-arm-no-label': [
+ self._make_collapsible_style_top, False, False],
+ 'collapsible-bottom': self._make_collapsible_style_bottom,
+ 'portfolio-style-2x2': self._make_portfolio_style_2x2,
+ 'portfolio-style-1x1': self._make_portfolio_style_1x1,
+ 'portfolio-style-2x1': self._make_portfolio_style_2x1,
+ 'portfolio-style-1x2': self._make_portfolio_style_1x2}
+
if self.name in OLD_NAMES:
self.name = OLD_NAMES[self.name]
@@ -162,22 +199,38 @@ class Block:
# If there is already a block with the same name, reuse it
copy_block = None
- if self.name not in EXPANDABLE and \
- self.name not in EXPANDABLE_BLOCKS and \
- self.name not in EXPANDABLE_ARGS and \
- self.name not in BOX_STYLE and \
- self.name not in ['sandwichtop', 'sandwichtop_no_label']:
+ if self.cloneable():
for b in self.block_list.list:
if b.scale == self.scale and b.name == self.name:
copy_block = b
break
self._new_block_from_factory(sprite_list, x, y, copy_block)
- if name in PRIMITIVES:
- self.primitive = PRIMITIVES[self.name]
+ if name in block_primitives:
+ self.primitive = block_primitives[self.name]
self.block_list.append_to_list(self)
+ def expandable(self):
+ """ Can this block be expanded? """
+ if self.name in EXPANDABLE:
+ return True
+ if self.name in expandable_blocks:
+ return True
+ if self.name in EXPANDABLE_ARGS:
+ return True
+ return False
+
+ def cloneable(self):
+ """ Is it safe to clone this block? """
+ if self.expandable():
+ return False
+ if self.name in block_styles['box-style']:
+ return False
+ if self.name in ['sandwichtop', 'sandwichtop_no_label']:
+ return False
+ return True
+
def highlight(self):
""" We may want to highlight a block... """
if self.spr is not None:
@@ -310,7 +363,6 @@ class Block:
return (self.ex, self.ey)
def _new_block_from_factory(self, sprite_list, x, y, copy_block=None):
-
self.svg = SVG()
self.svg.set_scale(self.scale)
self.svg.set_innie([False])
@@ -335,10 +387,7 @@ class Block:
self.shapes[1] = copy_block.shapes[1]
self.docks = copy_block.docks[:]
else:
- if (self.name in EXPANDABLE or \
- self.name in EXPANDABLE_BLOCKS or \
- self.name in EXPANDABLE_ARGS) and \
- self.type == 'block':
+ if self.expandable() and self.type == 'block':
self.svg.set_show(True)
self._make_block(self.svg)
@@ -358,11 +407,11 @@ class Block:
else:
self._set_labels(i, str(v))
elif self.type == 'block' and self.name in CONSTANTS:
- self._set_labels(0, BLOCK_NAMES[self.name][0] + ' = ' + \
+ self._set_labels(0, block_names[self.name][0] + ' = ' + \
str(CONSTANTS[self.name]))
- elif self.name in BLOCK_NAMES:
- for i, n in enumerate(BLOCK_NAMES[self.name]):
+ elif self.name in block_names:
+ for i, n in enumerate(block_names[self.name]):
self._set_labels(i, n)
if copy_block is None:
@@ -374,18 +423,24 @@ class Block:
self.svg.margins[2], self.svg.margins[3])
def _set_label_attributes(self):
- if self.name in CONTENT_BLOCKS:
+ if self.name in content_blocks:
n = len(self.values)
if n == 0:
n = 1 # Force a scale to be set, even if there is no value.
else:
- if self.name in BLOCK_NAMES:
- n = len(BLOCK_NAMES[self.name])
+ if self.name in block_names:
+ n = len(block_names[self.name])
else:
- _logger.debug('WARNING: unknown block name %s' % (self.name))
+ debug_output('WARNING: unknown block name %s' % (self.name))
n = 0
for i in range(n):
- if i == 1: # top
+ if self.name in block_styles['compare-porch-style']:
+ self.spr.set_label_attributes(int(self._font_size[0] + 0.5),
+ True, 'center', 'bottom', i)
+ elif self.name in block_styles['number-style-porch']:
+ self.spr.set_label_attributes(int(self._font_size[0] + 0.5),
+ True, 'right', 'bottom', i)
+ elif i == 1: # top
self.spr.set_label_attributes(int(self._font_size[1] + 0.5),
True, 'right', 'top', i)
elif i == 2: # bottom
@@ -405,92 +460,26 @@ class Block:
self._bottom = 0
self.svg.set_stroke_width(STANDARD_STROKE_WIDTH)
self.svg.clear_docks()
- if self.name in BASIC_STYLE:
- self._make_basic_style(svg)
- elif self.name in BASIC_STYLE_HEAD:
- self._make_basic_style_head(svg)
- elif self.name in BASIC_STYLE_EXTENDED:
- self._make_basic_style(svg, 16, 16)
- elif self.name in BASIC_STYLE_EXTENDED_VERTICAL:
- self._make_basic_style(svg, 0, 4)
- elif self.name in BASIC_STYLE_HEAD_1ARG:
- self._make_basic_style_head_1arg(svg)
- elif self.name in BASIC_STYLE_TAIL:
- self._make_basic_style_tail(svg)
- elif self.name in BASIC_STYLE_1ARG:
- self._make_basic_style_1arg(svg)
- elif self.name in BASIC_STYLE_2ARG:
- self._make_basic_style_2arg(svg)
- elif self.name in BASIC_STYLE_VAR_ARG:
- self._make_basic_style_var_arg(svg)
- elif self.name in BULLET_STYLE:
- self._make_bullet_style(svg)
- elif self.name in BOX_STYLE:
- self._make_box_style(svg)
- elif self.name in BOX_STYLE_MEDIA:
- self._make_media_style(svg)
- elif self.name in NUMBER_STYLE:
- self._make_number_style(svg)
- elif self.name in NUMBER_STYLE_BLOCK:
- self._make_number_style_block(svg)
- elif self.name in NUMBER_STYLE_VAR_ARG:
- self._make_number_style_var_arg(svg)
- elif self.name in NUMBER_STYLE_1ARG:
- self._make_number_style_1arg(svg)
- elif self.name in NUMBER_STYLE_1STRARG:
- self._make_number_style_1strarg(svg)
- elif self.name in NUMBER_STYLE_PORCH:
- self._make_number_style_porch(svg)
- elif self.name in COMPARE_STYLE:
- self._make_compare_style(svg)
- elif self.name in BOOLEAN_STYLE:
- self._make_boolean_style(svg)
- elif self.name in NOT_STYLE:
- self._make_not_style(svg)
- elif self.name in FLOW_STYLE:
- self._make_flow_style(svg)
- elif self.name in FLOW_STYLE_TAIL:
- self._make_flow_style_tail(svg)
- elif self.name in FLOW_STYLE_1ARG:
- self._make_flow_style_1arg(svg)
- elif self.name in FLOW_STYLE_BOOLEAN:
- self._make_flow_style_boolean(svg)
- elif self.name in FLOW_STYLE_WHILE:
- self._make_flow_style_while(svg)
- elif self.name in FLOW_STYLE_ELSE:
- self._make_flow_style_else(svg)
- elif self.name in COLLAPSIBLE_TOP:
- self._make_collapsible_style_top(svg, arm=True, label=True)
- elif self.name in COLLAPSIBLE_TOP_NO_ARM:
- self._make_collapsible_style_top(svg, arm=False, label=True)
- elif self.name in COLLAPSIBLE_TOP_NO_LABEL:
- self._make_collapsible_style_top(svg, arm=True, label=False)
- elif self.name in COLLAPSIBLE_TOP_NO_ARM_NO_LABEL:
- self._make_collapsible_style_top(svg, arm=False, label=False)
- elif self.name in COLLAPSIBLE_BOTTOM:
- self._make_collapsible_style_bottom(svg)
- elif self.name in INVISIBLE:
- self._make_invisible_style(svg)
- elif self.name in PORTFOLIO_STYLE_2x2:
- self._make_portfolio_style_2x2(svg)
- elif self.name in PORTFOLIO_STYLE_2x1:
- self._make_portfolio_style_2x1(svg)
- elif self.name in PORTFOLIO_STYLE_1x1:
- self._make_portfolio_style_1x1(svg)
- elif self.name in PORTFOLIO_STYLE_1x2:
- self._make_portfolio_style_1x2(svg)
- else:
- self._make_basic_style(svg)
- _logger.debug("WARNING: I don't know how to create a %s block" % \
- (self.name))
+ for k in block_styles.keys():
+ if self.name in block_styles[k]:
+ if type(self.block_methods[k]) == type([]):
+ self.block_methods[k][0](svg, self.block_methods[k][1],
+ self.block_methods[k][2])
+ else:
+ self.block_methods[k](svg)
+ return
+ error_output('block type not found %s' % (self.name))
+ self.block_methods['basic-style'](svg)
def _set_colors(self, svg):
if self.name in BOX_COLORS:
self.colors = BOX_COLORS[self.name]
+ elif self.name in special_block_colors:
+ self.colors = special_block_colors[self.name]
else:
- for p in range(len(PALETTES)):
- if self.name in PALETTES[p]:
- self.colors = COLORS[p]
+ for p in range(len(palette_blocks)):
+ if self.name in palette_blocks[p]:
+ self.colors = block_colors[p]
self.svg.set_colors(self.colors)
def _make_basic_style(self, svg, extend_x=0, extend_y=0):
@@ -500,6 +489,13 @@ class Block:
self.svg.docks[0][1]], ['flow',
False, self.svg.docks[1][0], self.svg.docks[1][1]]]
+ def _make_blank_style(self, svg, extend_x=0, extend_y=0):
+ self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
+ self.svg.set_slot(False)
+ self.svg.set_tab(False)
+ self._make_block_graphics(svg, self.svg.basic_block)
+ self.docks = []
+
def _make_basic_style_head(self, svg):
self.svg.expand(10 + self.dx + self.ex, self.ey)
self.svg.set_slot(False)
@@ -553,6 +549,21 @@ class Block:
['flow', False, self.svg.docks[3][0],
self.svg.docks[3][1]]]
+ def _make_basic_style_3arg(self, svg):
+ self.svg.expand(10 + self.dx + self.ex, self.ey)
+ self.svg.set_innie([True, True, True])
+ self._make_block_graphics(svg, self.svg.basic_block)
+ self.docks = [['flow', True, self.svg.docks[0][0],
+ self.svg.docks[0][1]],
+ ['number', False, self.svg.docks[1][0],
+ self.svg.docks[1][1]],
+ ['number', False, self.svg.docks[2][0],
+ self.svg.docks[2][1]],
+ ['number', False, self.svg.docks[3][0],
+ self.svg.docks[3][1]],
+ ['flow', False, self.svg.docks[4][0],
+ self.svg.docks[4][1]]]
+
def _make_basic_style_var_arg(self, svg):
self.svg.expand(10 + self.dx + self.ex, self.ey)
innie = [True]
@@ -706,6 +717,10 @@ class Block:
self.svg.docks[2][1]],
['unavailable', False, 0, 0, ')']]
+ def _make_compare_porch_style(self, svg):
+ self.svg.set_porch(True)
+ self._make_compare_style(svg)
+
def _make_boolean_style(self, svg):
self.svg.expand(10 + self.dx + self.ex, self.ey)
self._make_block_graphics(svg, self.svg.boolean_and_or)
diff --git a/TurtleArt/tacamera.py b/TurtleArt/tacamera.py
deleted file mode 100644
index 2177288..0000000
--- a/TurtleArt/tacamera.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- coding: utf-8 -*-
-#Copyright (c) 2010, Walter Bender
-#Copyright (c) 2010, Tony Forster
-
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
-
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
-
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-
-import gst, time
-
-GST_PIPE = ['v4l2src', 'ffmpegcolorspace', 'pngenc']
-
-class Camera():
- """ A class for representing the video camera """
-
- def __init__(self, imagepath):
- GST_PIPE.append('filesink location=%s' % imagepath)
- self.pipe = gst.parse_launch('!'.join(GST_PIPE))
- self.bus = self.pipe.get_bus()
-
- def save_camera_input_to_file(self):
- """ Grab a frame from the camera """
- self.pipe.set_state(gst.STATE_PLAYING)
- self.bus.poll(gst.MESSAGE_EOS, -1)
-
- def stop_camera_input(self):
- self.pipe.set_state(gst.STATE_NULL)
-
diff --git a/TurtleArt/tacanvas.py b/TurtleArt/tacanvas.py
index d4395a2..bf866fb 100644
--- a/TurtleArt/tacanvas.py
+++ b/TurtleArt/tacanvas.py
@@ -1,5 +1,5 @@
#Copyright (c) 2007-8, Playful Invention Company.
-#Copyright (c) 2008-10, Walter Bender
+#Copyright (c) 2008-11, Walter Bender
#Copyright (c) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
#Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,15 +24,15 @@ import gtk
from math import sin, cos, pi
import pango
import cairo
+import base64
+from gettext import gettext as _
from sprites import Sprite
from tasprite_factory import SVG
-from tautils import image_to_base64, data_to_string, round_int
+from tautils import image_to_base64, get_path, data_to_string, round_int, \
+ debug_output
from taconstants import CANVAS_LAYER, BLACK, WHITE
-import logging
-_logger = logging.getLogger('turtleart-activity')
-
def wrap100(n):
""" A variant on mod... 101 -> 99; 199 -> 1 """
@@ -43,6 +43,23 @@ def wrap100(n):
return n
+def calc_poly_bounds(poly_points):
+ """ Calculate the minx, miny, width, height of polygon """
+ minx = poly_points[0][0]
+ miny = poly_points[0][1]
+ maxx, maxy = minx, miny
+ for p in poly_points:
+ if p[0] < minx:
+ minx = p[0]
+ elif p[0] > maxx:
+ maxx = p[0]
+ if p[1] < miny:
+ miny = p[1]
+ elif p[1] > maxy:
+ maxy = p[1]
+ return(minx, miny, maxx - minx, maxy - miny)
+
+
def calc_shade(c, s, invert=False):
""" Convert a color to the current shade (lightness/darkness). """
# Assumes 16 bit input values
@@ -119,8 +136,8 @@ class TurtleGraphics:
self.fgcolor = self.cm.alloc_color('red')
self.bgrgb = [255, 248, 222]
self.bgcolor = self.cm.alloc_color('#fff8de')
- self.textsize = 48 # depreciated
- self.textcolor = self.cm.alloc_color('blue')
+ self.textsize = 48 # deprecated
+ self.textcolor = self.cm.alloc_color('red') # deprecated
self.tw.active_turtle.show()
self.shade = 0
self.pendown = False
@@ -128,7 +145,6 @@ class TurtleGraphics:
self.ycor = 0
self.heading = 0
self.pensize = 5
- self.tcolor = 0
self.color = 0
self.gray = 100
self.fill = False
@@ -142,57 +158,72 @@ class TurtleGraphics:
""" Start accumulating points of a polygon to fill. """
self.fill = True
self.poly_points = []
+ if self.tw.saving_svg:
+ self.tw.svg_string += '<g>'
def stop_fill(self):
""" Fill the polygon. """
self.fill = False
if len(self.poly_points) == 0:
return
- minx = self.poly_points[0][0]
- miny = self.poly_points[0][1]
- maxx = minx
- maxy = miny
- for p in self.poly_points:
- if p[0] < minx:
- minx = p[0]
- elif p[0] > maxx:
- maxx = p[0]
- if p[1] < miny:
- miny = p[1]
- elif p[1] > maxy:
- maxy = p[1]
- w = maxx - minx
- h = maxy - miny
- self.canvas.images[0].draw_polygon(self.gc, True, self.poly_points)
+ 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 = []
+ if self.tw.saving_svg:
+ self.tw.svg_string += '</g>'
+
+ def fill_polygon(self, poly_points):
+ minx, miny, w, h = calc_poly_bounds(poly_points)
+ self.canvas.images[0].draw_polygon(self.gc, True, poly_points)
self.invalt(minx - self.pensize * self.tw.coord_scale / 2 - 3,
miny - self.pensize * self.tw.coord_scale / 2 - 3,
w + self.pensize * self.tw.coord_scale + 6,
h + self.pensize * self.tw.coord_scale + 6)
- self.poly_points = []
+ if self.tw.saving_svg and self.pendown:
+ self.svg.set_fill_color("#%02x%02x%02x" % (self.fgrgb[0],
+ self.fgrgb[1],
+ self.fgrgb[2]))
+ self.tw.svg_string += self.svg.new_path(poly_points[0][0],
+ poly_points[0][1])
+ for p in range(len(poly_points)):
+ if p > 0:
+ self.tw.svg_string += self.svg.line_to(poly_points[p][0],
+ poly_points[p][1])
+ self.tw.svg_string += "\"\n"
+ self.tw.svg_string += self.svg.style()
+ self.svg.set_fill_color('none')
def clearscreen(self, share=True):
"""Clear the canvas and reset most graphics attributes to defaults."""
- rect = gtk.gdk.Rectangle(0, 0, self.width, self.height)
+ rect = gtk.gdk.Rectangle(0, 0, self.width * 2, self.height * 2)
self.gc.set_foreground(self.bgcolor)
self.canvas.images[0].draw_rectangle(self.gc, True, *rect)
self.invalt(0, 0, self.width, self.height)
self.setpensize(5, share)
self.setgray(100, share)
self.setcolor(0, share)
- self.settextcolor(70)
self.setshade(50, share)
for turtle_key in iter(self.tw.turtles.dict):
- 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, share)
- self.setpen(False, share)
- self.setxy(0, 0, share)
- self.setpen(True, share)
- self.tw.active_turtle.hide()
+ # 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, share)
+ self.setpen(False, share)
+ self.setxy(0, 0, share)
+ self.setpen(True, share)
+ self.tw.active_turtle.hide()
self.set_turtle(self.tw.default_turtle_name)
self.tw.svg_string = ''
self.svg.reset_min_max()
@@ -208,44 +239,46 @@ class TurtleGraphics:
self.xcor += nn * sin(self.heading * DEGTOR)
self.ycor += nn * cos(self.heading * DEGTOR)
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ 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.saving_svg and self.pendown:
- self.tw.svg_string += self.svg.new_path(oldx,
- self.height / 2 - oldy)
- self.tw.svg_string += self.svg.line_to(self.xcor,
- self.height / 2 - self.ycor)
- self.tw.svg_string += "\"\n"
- self.tw.svg_string += self.svg.style()
- event = "f|%s" % (data_to_string([self._get_my_nick(), int(n)]))
- self._send_event(event, share)
+
+ if self.tw.sharing() and share:
+ event = "f|%s" % (data_to_string([self._get_my_nick(), int(n)]))
+ self.tw.send_event(event)
def seth(self, n, share=True):
""" Set the turtle heading. """
try:
self.heading = n
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
self.heading %= 360
self.turn_turtle()
- event = "r|%s" % (data_to_string([self._get_my_nick(), round_int(self.heading)]))
- self._send_event(event, share)
+ 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:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
self.heading %= 360
self.turn_turtle()
- event = "r|%s" % (data_to_string([self._get_my_nick(), round_int(self.heading)]))
- self._send_event(event, share)
+ 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 """
@@ -257,11 +290,14 @@ class TurtleGraphics:
else:
self.rarc(a, rr)
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
self.move_turtle()
- event = "a|%s" % (data_to_string([self._get_my_nick(), [round_int(a), round_int(r)]]))
- self._send_event(event, share)
+ 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 """
@@ -274,8 +310,7 @@ class TurtleGraphics:
oldx, oldy = self.xcor, self.ycor
cx = self.xcor + r * cos(self.heading * DEGTOR)
cy = self.ycor - r * sin(self.heading * DEGTOR)
- x = self.width / 2 + int(cx - r)
- y = self.height / 2 - int(cy + r)
+ x, y = self.turtle_to_screen_coordinates(int(cx - r), int(cy + r))
w = int(2 * r)
h = w
if self.pendown:
@@ -289,10 +324,10 @@ class TurtleGraphics:
self.xcor = cx - r * cos(self.heading * DEGTOR)
self.ycor = cy + r * sin(self.heading * DEGTOR)
if self.tw.saving_svg and self.pendown:
- self.tw.svg_string += self.svg.new_path(oldx,
- self.height / 2 - oldy)
- self.tw.svg_string += self.svg.arc_to(self.xcor,
- self.height / 2 - self.ycor, r, a, 0, s)
+ x, y = self.turtle_to_screen_coordinates(oldx, oldy)
+ self.tw.svg_string += self.svg.new_path(x, y)
+ x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor)
+ self.tw.svg_string += self.svg.arc_to(x, y, r, a, 0, s)
self.tw.svg_string += "\"\n"
self.tw.svg_string += self.svg.style()
@@ -307,8 +342,7 @@ class TurtleGraphics:
oldx, oldy = self.xcor, self.ycor
cx = self.xcor - r * cos(self.heading * DEGTOR)
cy = self.ycor + r * sin(self.heading * DEGTOR)
- x = self.width / 2 + int(cx - r)
- y = self.height / 2 - int(cy + r)
+ x, y = self.turtle_to_screen_coordinates(int(cx - r), int(cy + r))
w = int(2 * r)
h = w
if self.pendown:
@@ -323,11 +357,10 @@ class TurtleGraphics:
self.xcor = cx + r * cos(self.heading * DEGTOR)
self.ycor = cy - r * sin(self.heading * DEGTOR)
if self.tw.saving_svg and self.pendown:
- self.tw.svg_string += self.svg.new_path(oldx,
- self.height / 2 - oldy)
- self.tw.svg_string += self.svg.arc_to(self.xcor,
- self.height / 2 - self.ycor,
- r, a, 0, s)
+ x, y = self.turtle_to_screen_coordinates(oldx, oldy)
+ self.tw.svg_string += self.svg.new_path(x, y)
+ x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor)
+ self.tw.svg_string += self.svg.arc_to(x, y, r, a, 0, s)
self.tw.svg_string += "\"\n"
self.tw.svg_string += self.svg.style()
@@ -339,16 +372,19 @@ class TurtleGraphics:
try:
self.xcor, self.ycor = x, y
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
if self.pendown and pendown:
self.gc.set_foreground(self.fgcolor)
self.draw_line(oldx, oldy, self.xcor, self.ycor)
-
self.move_turtle()
- event = "x|%s" % (data_to_string([self._get_my_nick(), [round_int(x), round_int(y)]]))
- self._send_event(event, share)
+
+ 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 """
@@ -357,81 +393,85 @@ class TurtleGraphics:
ps = 0
self.pensize = ps
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
self.tw.active_turtle.set_pen_size(ps)
self.gc.set_line_attributes(int(self.pensize * self.tw.coord_scale),
- gtk.gdk.LINE_SOLID, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER)
+ gtk.gdk.LINE_SOLID, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER)
self.svg.set_stroke_width(self.pensize)
- event = "w|%s" % (data_to_string([self._get_my_nick(), round_int(ps)]))
- self._send_event(event, share)
+ 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 setcolor(self, c, share=True):
""" Set the pen color """
try:
self.color = c
- self.tcolor = c
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
self.tw.active_turtle.set_color(c)
self.set_fgcolor()
- self.set_textcolor()
- event = "c|%s" % (data_to_string([self._get_my_nick(), round_int(c)]))
- self._send_event(event, share)
+ 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:
- _logger.debug("bad value sent to %s" % (__name__))
+ 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.set_textcolor()
self.tw.active_turtle.set_gray(self.gray)
- event = "g|%s" % (data_to_string([self._get_my_nick(), round_int(self.gray)]))
- self._send_event(event, share)
+ 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 settextcolor(self, c):
+ def settextcolor(self, c): # deprecated
""" Set the text color """
- try:
- self.tcolor = c
- except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
- return
- self.set_textcolor()
+ return
- def settextsize(self, c): # depreciated
+ def settextsize(self, c): # deprecated
""" Set the text size """
try:
self.tw.textsize = c
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ 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:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
self.tw.active_turtle.set_shade(s)
self.set_fgcolor()
- self.set_textcolor()
- event = "s|%s" % (data_to_string([self._get_my_nick(), round_int(s)]))
- self._send_event(event, share)
+ 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 fillscreen(self, c, s):
""" Fill screen with color/shade and reset to defaults """
oldc, olds = self.color, self.shade
self.setcolor(c, False)
self.setshade(s, False)
- rect = gtk.gdk.Rectangle(0, 0, self.width, self.height)
+ rect = gtk.gdk.Rectangle(0, 0, self.width * 2, self.height * 2)
self.gc.set_foreground(self.fgcolor)
self.bgrgb = self.fgrgb[:]
self.canvas.images[0].draw_rectangle(self.gc, True, *rect)
@@ -473,16 +513,17 @@ class TurtleGraphics:
def set_textcolor(self):
""" Set the text color to foreground color. """
- self.tw.textcolor = self.fgcolor
+ return
def setpen(self, bool, share=True):
""" Lower or raise the pen """
self.pendown = bool
self.tw.active_turtle.set_pen_state(bool)
- event = "p|%s" % (data_to_string([self._get_my_nick(), bool]))
- self._send_event(event, share)
+ if self.tw.sharing() and share:
+ event = "p|%s" % (data_to_string([self._get_my_nick(), bool]))
+ self.tw.send_event(event)
- def draw_pixbuf(self, pixbuf, a, b, x, y, w, h, path):
+ def draw_pixbuf(self, pixbuf, a, b, x, y, w, h, path, share=True):
""" Draw a pixbuf """
w *= self.tw.coord_scale
h *= self.tw.coord_scale
@@ -492,20 +533,40 @@ class TurtleGraphics:
if self.tw.running_sugar:
# In Sugar, we need to embed the images inside the SVG
self.tw.svg_string += self.svg.image(x - self.width / 2,
- y, w, h, path, image_to_base64(pixbuf, self.tw.activity))
+ y, w, h, path, image_to_base64(pixbuf,
+ get_path(self.tw.activity, 'instance')))
else:
+ # Outside of Sugar, we save a path
self.tw.svg_string += self.svg.image(x - self.width / 2,
y, w, h, path)
-
- def draw_text(self, label, x, y, size, w):
+ if self.tw.sharing() and share:
+ if self.tw.running_sugar:
+ tmp_path = get_path(self.tw.activity, 'instance')
+ else:
+ tmp_path = '/tmp'
+ data = image_to_base64(pixbuf, 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]]))
+ self.tw.send_event(event)
+
+ def draw_text(self, label, x, y, size, w, share=True):
""" Draw text """
w *= self.tw.coord_scale
- self.gc.set_foreground(self.tw.textcolor)
+ self.gc.set_foreground(self.fgcolor)
fd = pango.FontDescription('Sans')
try:
fd.set_size(int(size * self.tw.coord_scale) * pango.SCALE)
except TypeError, ValueError:
- _logger.debug("bad value sent to %s" % (__name__))
+ debug_output("bad value sent to %s" % (__name__),
+ self.tw.running_sugar)
return
if self.tw.interactive_mode:
if type(label) == str or type(label) == unicode:
@@ -529,32 +590,57 @@ class TurtleGraphics:
context.move_to(x, y + h)
context.show_text(message)
- if self.tw.saving_svg and self.pendown:
- self.tw.svg_string += self.svg.text(x - self.width / 2,
+ if self.tw.saving_svg: # and self.pendown:
+ self.tw.svg_string += self.svg.text(x, # - self.width / 2,
y + size, size, w, label)
+ 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
def draw_line(self, x1, y1, x2, y2):
""" Draw a line """
- x1, y1 = self.width / 2 + int(x1), self.height / 2 - int(y1)
- x2, y2 = self.width / 2 + int(x2), self.height / 2 - int(y2)
+ x1, y1 = self.turtle_to_screen_coordinates(x1, y1)
+ x2, y2 = self.turtle_to_screen_coordinates(x2, y2)
if x1 < x2:
- minx, maxx = x1, x2
+ minx, maxx = int(x1), int(x2)
else:
- minx, maxx = x2, x1
+ minx, maxx = int(x2), int(x1)
if y1 < y2:
- miny, maxy = y1, y2
+ miny, maxy = int(y1), int(y2)
else:
- miny, maxy = y2, y1
+ miny, maxy = int(y2), int(y1)
w, h = maxx - minx, maxy - miny
- self.canvas.images[0].draw_line(self.gc, x1, y1, x2, y2)
+ self.canvas.images[0].draw_line(self.gc, int(x1), int(y1), int(x2),
+ int(y2))
if self.fill and self.poly_points == []:
- self.poly_points.append((x1, y1))
+ self.poly_points.append((int(x1), int(y1)))
if self.fill:
- self.poly_points.append((x2, y2))
- self.invalt(minx - self.pensize * self.tw.coord_scale / 2 - 3,
- miny - self.pensize * self.tw.coord_scale / 2 - 3,
+ self.poly_points.append((int(x2), int(y2)))
+ self.invalt(minx - int(self.pensize * self.tw.coord_scale / 2) - 3,
+ miny - int(self.pensize * self.tw.coord_scale / 2) - 3,
w + self.pensize * self.tw.coord_scale + 6,
h + self.pensize * self.tw.coord_scale + 6)
+ if self.tw.saving_svg and self.pendown:
+ self.tw.svg_string += self.svg.new_path(x1, y1)
+ self.tw.svg_string += self.svg.line_to(x2, y2)
+ self.tw.svg_string += "\"\n"
+ self.tw.svg_string += self.svg.style()
def turn_turtle(self):
""" Change the orientation of the turtle """
@@ -562,8 +648,7 @@ class TurtleGraphics:
def move_turtle(self):
""" Move the turtle """
- x, y = self.width / 2 + int(self.xcor), \
- self.height / 2 - int(self.ycor)
+ x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor)
self.tw.active_turtle.move(
(int(self.cx + x - self.tw.active_turtle.spr.rect.width / 2),
int(self.cy + y - self.tw.active_turtle.spr.rect.height / 2)))
@@ -611,9 +696,9 @@ class TurtleGraphics:
def get_pixel(self):
""" Read the pixel at x, y """
if self.tw.interactive_mode:
- return self.canvas.get_pixel(
- (self.width / 2 + int(self.xcor),
- self.height / 2 - int(self.ycor)), 0, self.tw.color_mode)
+ x, y = self.turtle_to_screen_coordinates(self.xcor, self.ycor)
+ return self.canvas.get_pixel((int(x), int(y)), 0,
+ self.tw.color_mode)
else:
return(-1, -1, -1, -1)
@@ -625,13 +710,16 @@ class TurtleGraphics:
self.seth(0, False)
self.setxy(0, 0, False, pendown=False)
self.tw.active_turtle.set_pen_state(True)
- self.tw.active_turtle = self.tw.turtles.get_turtle(k, False)
+ 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.width / 2 + tx + \
- self.tw.active_turtle.spr.rect.width / 2
- self.ycor = self.height / 2 - ty - \
- self.tw.active_turtle.spr.rect.height / 2
+ self.xcor, self.ycor = self.screen_to_turtle_coordinates(tx, ty)
+ 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)
@@ -651,11 +739,3 @@ class TurtleGraphics:
def _get_my_nick(self):
return self.tw.nick
-
- def _send_event(self, entry, share):
- if not share:
- return
-
- if self.tw.sharing():
- print "Sending: %s" % entry
- self.tw.send_event(entry)
diff --git a/TurtleArt/tacollaboration.py b/TurtleArt/tacollaboration.py
index 52164e0..e1534a4 100644
--- a/TurtleArt/tacollaboration.py
+++ b/TurtleArt/tacollaboration.py
@@ -1,9 +1,34 @@
+#Copyright (c) 2011, Walter Bender
+#Copyright (c) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
+
+#Permission is hereby granted, free of charge, to any person obtaining a copy
+#of this software and associated documentation files (the "Software"), to deal
+#in the Software without restriction, including without limitation the rights
+#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#copies of the Software, and to permit persons to whom the Software is
+#furnished to do so, subject to the following conditions:
+
+#The above copyright notice and this permission notice shall be included in
+#all copies or substantial portions of the Software.
+
+#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+#THE SOFTWARE.
from dbus.service import signal
from dbus.gobject_service import ExportedGObject
-import logging
import telepathy
-from TurtleArt.tautils import data_to_string, data_from_string
+
+import gtk
+import base64
+
+from TurtleArt.tautils import data_to_string, data_from_string, get_path, \
+ base64_to_image, debug_output, error_output
+from TurtleArt.taconstants import DEFAULT_TURTLE_COLORS
try:
from sugar import profile
@@ -17,43 +42,63 @@ except:
SERVICE = 'org.laptop.TurtleArtActivity'
IFACE = SERVICE
PATH = '/org/laptop/TurtleArtActivity'
-_logger = logging.getLogger('turtleart-activity')
+
class Collaboration():
def __init__(self, tw, activity):
""" A simplistic sharing model: the sharer is the master """
self._tw = tw
self._tw.send_event = self.send_event
+ self._tw.remote_turtle_dictionary = {}
self._activity = activity
+ self._setup_dispatch_table()
def setup(self):
# TODO: hand off role of master is sharer leaves
self.pservice = presenceservice.get_instance()
- self.initiating = None # sharing (True) or joining (False)
+ self.initiating = None # sharing (True) or joining (False)
# Add my buddy object to the list
owner = self.pservice.get_owner()
self.owner = owner
self._tw.buddies.append(self.owner)
- self._share = ""
-
+ self._share = ''
self._activity.connect('shared', self._shared_cb)
self._activity.connect('joined', self._joined_cb)
+ def _setup_dispatch_table(self):
+ self._processing_methods = {
+ 't': self._turtle_request,
+ 'T': self._receive_turtle_dict,
+ 'f': self._move_forward,
+ 'a': self._move_in_arc,
+ 'r': self._rotate_turtle,
+ 'x': self._setxy,
+ 'W': self._draw_text,
+ 'c': self._set_pen_color,
+ 'g': self._set_pen_gray_level,
+ 's': self._set_pen_shade,
+ 'w': self._set_pen_width,
+ 'p': self._set_pen_state,
+ 'F': self._fill_polygon,
+ 'P': self._draw_pixbuf
+ }
+
def _shared_cb(self, activity):
self._shared_activity = self._activity._shared_activity
if self._shared_activity is None:
- _logger.error("Failed to share or join activity ... \
- _shared_activity is null in _shared_cb()")
+ debug_output('Failed to share or join activity ... \
+ _shared_activity is null in _shared_cb()',
+ self._tw.running_sugar)
return
self._tw.set_sharing(True)
self.initiating = True
self.waiting_for_turtles = False
- self.turtle_dictionary = self._get_dictionary()
-
- _logger.debug('I am sharing...')
+ self._tw.remote_turtle_dictionary = self._get_dictionary()
+
+ debug_output('I am sharing...', self._tw.running_sugar)
self.conn = self._shared_activity.telepathy_conn
self.tubes_chan = self._shared_activity.telepathy_tubes_chan
@@ -62,7 +107,8 @@ class Collaboration():
self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
'NewTube', self._new_tube_cb)
- _logger.debug('This is my activity: making a tube...')
+ debug_output('This is my activity: making a tube...',
+ self._tw.running_sugar)
id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
SERVICE, {})
@@ -70,8 +116,9 @@ class Collaboration():
def _joined_cb(self, activity):
self._shared_activity = self._activity._shared_activity
if self._shared_activity is None:
- _logger.error("Failed to share or join activity ... \
- _shared_activity is null in _shared_cb()")
+ debug_output('Failed to share or join activity ... \
+ _shared_activity is null in _shared_cb()',
+ self._tw.running_sugar)
return
self._tw.set_sharing(True)
@@ -85,7 +132,8 @@ class Collaboration():
self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
'NewTube', self._new_tube_cb)
- _logger.debug('I am joining an activity: waiting for a tube...')
+ debug_output('I am joining an activity: waiting for a tube...',
+ self._tw.running_sugar)
self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
reply_handler=self._list_tubes_reply_cb,
error_handler=self._list_tubes_error_cb)
@@ -98,13 +146,13 @@ class Collaboration():
self._new_tube_cb(*tube_info)
def _list_tubes_error_cb(self, e):
- _logger.error('ListTubes() failed: %s', e)
+ error_output('ListTubes() failed: %s' % (e), self._tw.running_sugar)
def _new_tube_cb(self, id, initiator, type, service, params, state):
""" Create a new tube. """
- _logger.debug('New tube: ID=%d initator=%d type=%d service=%s '
- 'params=%r state=%d', id, initiator, type, service,
- params, state)
+ debug_output('New tube: ID=%d initator=%d type=%d service=%s \
+ params=%r state=%d' % (id, initiator, type, service,
+ params, state), self._tw.running_sugar)
if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE):
if state == telepathy.TUBE_STATE_LOCAL_PENDING:
@@ -120,106 +168,35 @@ class Collaboration():
self.event_received_cb)
# Now that we have the tube, we can ask for the turtle dictionary.
- if self.waiting_for_turtles:
- _logger.debug("Sending a request for the turtle dictionary")
- # we need to send our own nick and colors
+ if self.waiting_for_turtles: # A joiner must wait for turtles.
+ debug_output('Sending a request for the turtle dictionary',
+ self._tw.running_sugar)
+ # We need to send our own nick, colors, and turtle position
colors = self._get_colors()
- event = "t|" + data_to_string([self._get_nick(), colors])
- _logger.debug(event)
+ event = 't|' + data_to_string([self._get_nick(), colors])
+ debug_output(event, self._tw.running_sugar)
self.send_event(event)
- def event_received_cb(self, text):
+ def event_received_cb(self, event_message):
"""
Events are sent as a tuple, nick|cmd, where nick is a turle name
and cmd is a turtle event. Everyone gets the turtle dictionary from
the sharer and watches for 't' events, which indicate that a new
turtle has joined.
"""
- if len(text) == 0:
+ if len(event_message) == 0:
return
- # Save active Turtle
+
+ # Save active Turtle
save_active_turtle = self._tw.active_turtle
- e = text.split("|", 2)
- text = e[1]
- if e[0] == 't': # request for turtle dictionary
- if text > 0:
- [nick, colors] = data_from_string(text)
- if nick != self._tw.nick:
- # There may not be a turtle dictionary.
- if hasattr(self, "turtle_dictionary"):
- self.turtle_dictionary[nick] = colors
- else:
- self.turtle_dictionary = {nick: colors}
- # Add new turtle for the joiner.
- self._tw.canvas.set_turtle(nick, colors)
- # Sharer should send turtle dictionary.
- if self.initiating:
- text = data_to_string(self.turtle_dictionary)
- self.send_event("T|" + text)
- elif e[0] == 'T': # Receiving the turtle dictionary.
- if self.waiting_for_turtles:
- if len(text) > 0:
- self.turtle_dictionary = data_from_string(text)
- for nick in self.turtle_dictionary:
- if nick != self._tw.nick:
- colors = self.turtle_dictionary[nick]
- # add new turtle for the joiner
- self._tw.canvas.set_turtle(nick, colors)
- self.waiting_for_turtles = False
- elif e[0] == 'f': # move a turtle forward
- if len(text) > 0:
- [nick, x] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.forward(x, False)
- elif e[0] == 'a': # move a turtle in an arc
- if len(text) > 0:
- [nick, [a, r]] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.arc(a, r, False)
- elif e[0] == 'r': # rotate turtle
- if len(text) > 0:
- [nick, h] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.seth(h, False)
- elif e[0] == 'x': # set turtle xy position
- if len(text) > 0:
- [nick, [x, y]] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setxy(x, y, False)
- elif e[0] == 'c': # set turtle pen color
- if len(text) > 0:
- [nick, x] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setcolor(x, False)
- elif e[0] == 'g': # set turtle pen gray level
- if len(text) > 0:
- [nick, x] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setgray(x, False)
- elif e[0] == 's': # set turtle pen shade
- if len(text) > 0:
- [nick, x] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setshade(x, False)
- elif e[0] == 'w': # set turtle pen width
- if len(text) > 0:
- [nick, x] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setpensize(x, False)
- elif e[0] == 'p': # set turtle pen state
- if len(text) > 0:
- [nick, x] = data_from_string(text)
- if nick != self._tw.nick:
- self._tw.canvas.set_turtle(nick)
- self._tw.canvas.setpen(x, False)
+
+ try:
+ command, payload = event_message.split('|', 2)
+ self._processing_methods[command](payload)
+ except ValueError:
+ debug_output('Could not split event message.',
+ self._tw.running_sugar)
+
# Restore active Turtle
self._tw.canvas.set_turtle(self._tw.turtles.get_turtle_key(
save_active_turtle))
@@ -229,19 +206,193 @@ class Collaboration():
if hasattr(self, 'chattube') and self.chattube is not None:
self.chattube.SendText(entry)
+ def _turtle_request(self, payload):
+ ''' incoming turtle from a joiner '''
+ if payload > 0:
+ [nick, colors] = data_from_string(payload)
+ if nick != self._tw.nick: # It is not me.
+ # There may not be a turtle dictionary.
+ if hasattr(self._tw, 'remote_turtle_dictionary'):
+ # 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.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.label_remote_turtle(nick, colors)
+
+ # Sharer should send the updated remote turtle dictionary to everyone.
+ if self.initiating:
+ if not self._tw.nick in self._tw.remote_turtle_dictionary:
+ self._tw.remote_turtle_dictionary[self._tw.nick] = \
+ self._get_colors()
+ event_payload = data_to_string(self._tw.remote_turtle_dictionary)
+ self.send_event('T|' + event_payload)
+ self._send_my_xy() # And the sender should report her xy position.
+
+ def _receive_turtle_dict(self, payload):
+ ''' Any time there is a new joiner, an updated turtle dictionary is
+ circulated. Everyone must report their turtle positions so that we
+ are in sync. '''
+ if self.waiting_for_turtles:
+ if len(payload) > 0:
+ # Grab the new remote turtles dictionary.
+ remote_turtle_dictionary = data_from_string(payload)
+ # Add see what is new.
+ for nick in remote_turtle_dictionary:
+ if nick == self._tw.nick:
+ debug_output('skipping my nick %s' \
+ % (nick), self._tw.running_sugar)
+ elif nick != self._tw.remote_turtle_dictionary:
+ # Add new the turtle.
+ colors = remote_turtle_dictionary[nick]
+ self._tw.remote_turtle_dictionary[nick] = colors
+ self._tw.canvas.set_turtle(nick, colors)
+ # Label the remote turtle.
+ self._tw.label_remote_turtle(nick, colors)
+ debug_output('adding %s to remote turtle dictionary' \
+ % (nick), self._tw.running_sugar)
+ else:
+ debug_output('%s already in remote turtle dictionary' \
+ % (nick), self._tw.running_sugar)
+ self.waiting_for_turtles = False
+ self._send_my_xy()
+
+ def _send_my_xy(self):
+ ''' Set xy location so joiner can sync turtle positions. '''
+ self._tw.canvas.set_turtle(self._get_nick())
+ if self._tw.canvas.pendown:
+ 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)]])))
+ 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)])))
+
+ def _draw_pixbuf(self, payload):
+ if len(payload) > 0:
+ [nick, [a, b, x, y, w, h, width, height, data]] =\
+ data_from_string(payload)
+ if nick != self._tw.nick:
+ if self._tw.running_sugar:
+ tmp_path = get_path(self._tw.activity, 'instance')
+ else:
+ tmp_path = '/tmp'
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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(
+ poly_points[i][0], poly_points[i][1])))
+ self._tw.canvas.fill_polygon(shared_poly_points)
+
def _get_dictionary(self):
- d = { self._get_nick(): self._get_colors()}
- return d
+ return {self._get_nick(): self._get_colors()}
def _get_nick(self):
return self._tw.nick
def _get_colors(self):
- if profile:
- colors = profile.get_color().to_string()
+ colors = None
+ if self._tw.running_sugar:
+ if profile.get_color() is not None:
+ colors = profile.get_color().to_string()
else:
colors = self._activity.get_colors()
- return colors
+ if colors is None:
+ colors = '%s,%s' % (DEFAULT_TURTLE_COLORS[0],
+ DEFAULT_TURTLE_COLORS[1])
+ return colors.split(',')
+
class ChatTube(ExportedGObject):
@@ -249,7 +400,7 @@ class ChatTube(ExportedGObject):
"""Class for setting up tube for sharing."""
super(ChatTube, self).__init__(tube, PATH)
self.tube = tube
- self.is_initiator = is_initiator # Are we sharing or joining activity?
+ self.is_initiator = is_initiator # Are we sharing or joining activity?
self.stack_received_cb = stack_received_cb
self.stack = ''
diff --git a/TurtleArt/taconstants.py b/TurtleArt/taconstants.py
index 77ebefb..30920d6 100644
--- a/TurtleArt/taconstants.py
+++ b/TurtleArt/taconstants.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-#Copyright (c) 2010, Walter Bender
+#Copyright (c) 2010-11 Walter Bender
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
@@ -19,79 +19,6 @@
#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, it is generally a
-matter of modifying some tables below and then adding the primitive to
-talogo.py. For example, if we want to add a new turtle command,
-'uturn', we'd make the following changes:
-
-(1) We'd add 'uturn' to the PALETTES list of lists:
-
-PALETTES = [['forward', 'back', 'clean', 'left', 'right', 'uturn', 'show',
- 'seth', 'setxy', 'heading', 'xcor', 'ycor', 'setscale',
- 'arc', 'scale'],
- ['penup','pendown', 'setpensize', 'fillscreen', 'pensize',...
-
-(2) Then we'd add it to one of the block-style definitions. Since it takes
-no arguments, we'd add it here:
-
-BASIC_STYLE = ['clean', 'penup', 'pendown', 'stack1', 'stack2', 'vspace',
- 'hideblocks', 'showblocks', 'clearheap', 'printheap', 'kbinput', 'uturn']
-
-(3) Then we give it a name (Note the syntax _('string to be
-translated') used by the language-internationalization system; also
-note that the name is an array, as some blocks contain multiple
-strings.):
-
-BLOCK_NAMES = {
-...
- 'uturn':[_('u-turn')],
-...
- }
-
-(4) and a help-menu entry:
-
-HELP_STRINGS = {
-...
- 'uturn':_('change the heading of the turtle 180 degrees'),
-...
- }
-
-(5) Next, we need to define it as a primitive for the Logo command
-parser (generally just the same name):
-
-PRIMITIVES = {
-...
- 'uturn':'uturn',
-...
- }
-
-(6) Since there are no default arguments, we don't need to do anything
-else here. But we do need to define the actual function in talogo.py
-
-DEFPRIM = {
-...
- 'uturn':[0, lambda self: self.tw.canvas.seth(self.tw.canvas.heading+180)],
-...
- }
-
-That's it. When you next run Turtle Art, you will have a 'uturn' block
-on the Turtle Palette.
-
-Adding a new palette is simply a matter of: (1) adding an additional
-entry to PALETTE_NAMES; (2) new list of blocks to PALETTES; and (3) an
-additional entry in COLORS. However you will have to: (4) create icons
-for the palette-selector buttons. These are kept in the icons
-subdirectory. You need two icons: yourpalettenameoff.svg and
-yourpalettenameon.svg, where yourpalettename is the same string as the
-entry you added to the PALETTE_NAMES list. Note that the icons should
-be the same size (55x55) as the others. This is the default icon size
-for Sugar toolbars.
-
-"""
-
from gettext import gettext as _
#
@@ -108,52 +35,7 @@ TAB_LAYER = 710
STATUS_LAYER = 900
TOP_LAYER = 1000
-#
-# Block-palette categories
-#
-
-PALETTE_NAMES = ['turtle', 'pen', 'colors', 'numbers', 'flow', 'blocks',
- 'extras', 'sensor', 'portfolio', 'trash']
-
-PALETTES = [['clean', 'forward', 'back', 'show', 'left', 'right',
- 'seth', 'setxy2', 'heading', 'xcor', 'ycor', 'setscale',
- 'arc', 'scale', 'leftpos', 'toppos', 'rightpos',
- 'bottompos'],
- ['penup', 'pendown', 'setpensize', 'fillscreen', 'pensize',
- 'setcolor', 'setshade', 'setgray', 'color', 'shade',
- 'gray', 'startfill', 'stopfill'],
- ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple',
- 'white', 'black'],
- ['plus2', 'minus2', 'product2',
- 'division2', 'identity2', 'remainder2', 'sqrt', 'random',
- 'number', 'greater2', 'less2', 'equal2', 'not', 'and2', 'or2'],
- ['wait', 'forever', 'repeat', 'if', 'ifelse', 'while', 'until',
- 'hspace', 'vspace', 'stopstack'],
- ['start', 'hat1', 'stack1', 'hat', 'hat2', 'stack2', 'stack',
- 'storeinbox1', 'storeinbox2', 'string', 'box1', 'box2', 'box',
- 'storein'],
- ['push', 'printheap', 'clearheap', 'pop', 'comment', 'print',
- 'myfunc1arg', 'userdefined',
- 'cartesian', 'width', 'height', 'polar', 'addturtle', 'reskin',
- 'sandwichtop_no_label', 'sandwichbottom'],
- ['kbinput', 'keyboard', 'readpixel', 'see',
- 'sound', 'volume', 'pitch'],
- ['journal', 'audio', 'video', 'description', 'hideblocks',
- 'showblocks', 'fullscreen', 'savepix', 'savesvg', 'mediawait',
- 'picturelist', 'picture1x1a', 'picture1x1', 'picture2x2',
- 'picture2x1', 'picture1x2'],
- ['empty', 'restoreall']]
-
-#
-# Block-style attributes
-#
-
-COLORS = [["#00FF00", "#00A000"], ["#00FFFF", "#00A0A0"],
- ["#00FFFF", "#00A0A0"], ["#FF00FF", "#A000A0"],
- ["#FFC000", "#A08000"], ["#FFFF00", "#A0A000"],
- ["#FF0000", "#A00000"], ["#FF0000", "#A00000"],
- ["#0000FF", "#0000A0"], ["#FFFF00", "#A0A000"]]
-
+# Special-case some block colors
BOX_COLORS = {'red': ["#FF0000", "#A00000"],
'orange': ["#FFD000", "#AA8000"],
'yellow': ["#FFFF00", "#A0A000"],
@@ -173,9 +55,10 @@ SELECTOR_WIDTH = 55
ICON_SIZE = 55
GRADIENT_COLOR = "#FFFFFF"
STANDARD_STROKE_WIDTH = 1.0
-BLOCK_SCALE = 2.0
+BLOCK_SCALE = [0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0]
PALETTE_SCALE = 1.5
DEFAULT_TURTLE = 'Yertle'
+DEFAULT_TURTLE_COLORS = ['#008000', '#00A000']
HORIZONTAL_PALETTE = 0
VERTICAL_PALETTE = 1
BLACK = -9999
@@ -190,78 +73,23 @@ DEFAULT_SCALE = 33
XO1 = 'xo1'
XO15 = 'xo1.5'
UNKNOWN = 'unknown'
-SENSOR_AC_NO_BIAS = 'external'
-SENSOR_AC_BIAS = 'sound'
-SENSOR_DC_NO_BIAS = 'voltage'
-SENSOR_DC_BIAS = 'resistance'
-#
-# Block-style definitions
-#
-BASIC_STYLE_HEAD = ['start', 'hat1', 'hat2', 'restore', 'restoreall']
-BASIC_STYLE_HEAD_1ARG = ['hat']
-BASIC_STYLE_TAIL = ['stopstack', 'empty']
-BASIC_STYLE = []
-BASIC_STYLE_EXTENDED_VERTICAL = ['clean', 'penup', 'pendown', 'stack1',
- 'stack2', 'hideblocks', 'showblocks', 'clearheap', 'printheap', 'kbinput',
- 'fullscreen', 'cartesian', 'polar', 'startfill', 'mediawait',
- 'stopfill', 'readpixel', 'readcamera', 'vspace']
-INVISIBLE = ['sandwichcollapsed']
-BASIC_STYLE_EXTENDED = ['picturelist', 'picture1x1', 'picture2x2',
- 'picture2x1', 'picture1x2', 'picture1x1a']
-BASIC_STYLE_1ARG = ['forward', 'back', 'left', 'right', 'seth', 'show', 'image',
- 'setscale', 'setpensize', 'setcolor', 'setshade', 'print', 'showaligned',
- 'settextsize', 'settextcolor', 'print', 'wait', 'storeinbox1', 'savepix',
- 'storeinbox2', 'wait', 'stack', 'push', 'nop', 'addturtle', 'comment',
- 'savesvg', 'setgray', 'skin', 'reskin']
-BASIC_STYLE_VAR_ARG = ['userdefined', 'userdefined2args', 'userdefined3args']
-BULLET_STYLE = ['templatelist', 'list']
-BASIC_STYLE_2ARG = ['arc', 'setxy', 'setxy2', 'fillscreen', 'storein', 'write']
-BOX_STYLE = ['number', 'xcor', 'ycor', 'heading', 'pensize', 'color', 'shade',
- 'textcolor', 'textsize', 'box1', 'box2', 'string', 'leftpos', 'scale',
- 'toppos', 'rightpos', 'bottompos', 'width', 'height', 'pop', 'keyboard',
- 'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'white',
- 'black', 'titlex', 'titley', 'leftx', 'topy', 'rightx', 'bottomy',
- 'sound', 'volume', 'pitch', 'voltage', 'resistance', 'gray', 'see', 'rfid',
- 'luminance']
-BOX_STYLE_MEDIA = ['description', 'audio', 'journal', 'video', 'camera']
-NUMBER_STYLE = ['plus2', 'product2', 'myfunc']
-NUMBER_STYLE_VAR_ARG = ['myfunc1arg', 'myfunc2arg', 'myfunc3arg']
-NUMBER_STYLE_BLOCK = ['random']
-NUMBER_STYLE_PORCH = ['minus2', 'division2', 'remainder2']
-NUMBER_STYLE_1ARG = ['sqrt', 'identity2']
-NUMBER_STYLE_1STRARG = ['box']
-COMPARE_STYLE = ['greater2', 'less2', 'equal2']
-BOOLEAN_STYLE = ['and2', 'or2']
-NOT_STYLE = ['not']
-FLOW_STYLE = ['forever']
-FLOW_STYLE_TAIL = ['hspace']
-FLOW_STYLE_1ARG = ['repeat']
-FLOW_STYLE_BOOLEAN = ['if', 'while', 'until']
-FLOW_STYLE_WHILE = ['while2']
-FLOW_STYLE_ELSE = ['ifelse']
-COLLAPSIBLE_TOP = ['sandwichtop']
-COLLAPSIBLE_TOP_NO_ARM = ['sandwichtop_no_arm']
-COLLAPSIBLE_TOP_NO_LABEL = ['sandwichtop_no_label']
-COLLAPSIBLE_TOP_NO_ARM_NO_LABEL = ['sandwichtop_no_arm_no_label']
-COLLAPSIBLE_BOTTOM = ['sandwichbottom']
-
-# Depreciated block styles
-PORTFOLIO_STYLE_2x2 = ['template2x2']
-PORTFOLIO_STYLE_1x1 = ['template1x1', 'template1x1a']
-PORTFOLIO_STYLE_2x1 = ['template2x1']
-PORTFOLIO_STYLE_1x2 = ['template1x2']
+CONSTANTS = {'leftpos': None, 'toppos': None, 'rightpos': None,
+ 'bottompos': None, 'width': None, 'height': None, 'red': 0,
+ 'orange': 10, 'yellow': 20, 'green': 40, 'cyan': 50, 'blue': 70,
+ 'purple': 90, 'titlex': None, 'titley': None, 'leftx': None,
+ 'topy': None, 'rightx': None, 'bottomy': None}
#
# Blocks that are expandable
#
-EXPANDABLE = ['vspace', 'hspace', 'identity2']
+EXPANDABLE_STYLE = ['boolean-style', 'compare-porch-style', 'compare-style',
+ 'number-style-porch', 'number-style', 'basic-style-2arg',
+ 'number-style-block']
-EXPANDABLE_BLOCKS = ['plus2', 'minus2', 'division2', 'remainder2', 'product2',
- 'random', 'equal2', 'greater2', 'less2', 'and2', 'or2',
- 'arc', 'setxy', 'setxy2', 'fillscreen', 'storein', 'write']
+EXPANDABLE = ['vspace', 'hspace', 'identity2']
-EXPANDABLE_ARGS = ['templatelist', 'list', 'myfunc1arg', 'myfunc2arg',
+EXPANDABLE_ARGS = ['list', 'myfunc1arg', 'myfunc2arg',
'myfunc3arg', 'userdefined', 'userdefined2args',
'userdefined3args']
#
@@ -270,418 +98,18 @@ EXPANDABLE_ARGS = ['templatelist', 'list', 'myfunc1arg', 'myfunc2arg',
COLLAPSIBLE = ['sandwichbottom', 'sandwichcollapsed']
#
-# Depreciated block styles that need dock adjustments
+# Deprecated block styles that need dock adjustments
#
OLD_DOCK = ['and', 'or', 'plus', 'minus', 'division', 'product', 'remainder']
#
-# Blocks that contain media
-#
-CONTENT_BLOCKS = ['number', 'string', 'description', 'audio', 'video',
- 'journal', 'camera']
-
-#
# These blocks get a special skin
#
BLOCKS_WITH_SKIN = ['journal', 'audio', 'description', 'nop', 'userdefined',
- 'video', 'userdefined2args', 'userdefined3args']
+ 'video', 'userdefined2args', 'userdefined3args', 'camera']
PYTHON_SKIN = ['nop', 'userdefined', 'userdefined2args', 'userdefined3args']
-#
-# These blocks hold constants
-#
-CONSTANTS = {'leftpos':None, 'toppos':None, 'rightpos':None, 'bottompos':None,
- 'width':None, 'height':None, 'red':0, 'orange':10, 'yellow':20,
- 'green':40, 'cyan':50, 'blue':70, 'purple':90, 'titlex':None,
- 'titley':None, 'leftx':None, 'topy':None, 'rightx':None,
- 'bottomy':None}
-
-#
-# Block-name dictionary used for labels
-#
-BLOCK_NAMES = {
- 'addturtle': [_('turtle')],
- 'and2': [_('and')],
- 'arc': [_('arc'), _('angle'), _('radius')],
- 'audio': [' '],
- 'back': [_('back')],
- 'black': [_('black')],
- 'blocks': [_('blocks')],
- 'blue': [_('blue')],
- 'bottompos': [_('bottom')],
- 'bottomy': [_('picture bottom')],
- 'box': [_('box')],
- 'box1': [_('box 1')],
- 'box2': [_('box 2')],
- 'camera': [' '],
- 'cartesian': [_('Cartesian')],
- 'clean': [_(' clean ')],
- 'clearheap': [_('empty heap')],
- 'color': [_('color')],
- 'colors': [_('colors')],
- 'comment': [_('comment')],
- 'cyan': [_('cyan')],
- 'decription': [' '],
- 'division2': ['/'],
- 'empty': [_('empty trash')],
- 'equal2': ['='],
- 'extras': [_('extras')],
- 'fillscreen': [_('fill screen'), _('color'), _('shade')],
- 'flow': [_('flow')],
- 'forever': [_('forever')],
- 'forward': [_('forward')],
- 'fullscreen': [_('full screen')],
- 'gray': [_('gray')],
- 'greater2': [">"],
- 'green': [_('green')],
- 'hat': [_('action')],
- 'hat1': [_('action 1')],
- 'hat2': [_('action 2')],
- 'heading': [_('heading')],
- 'height': [_('height')],
- 'hideblocks': [_('hide blocks')],
- 'hspace': [' '],
- 'identity2': ['←'],
- 'if': [' ', _('if'), _('then')],
- 'ifelse': [' ', _('if'), _('then else')],
- 'image': [_('show')],
- 'journal': [' '],
- 'kbinput': [_('query keyboard')],
- 'keyboard': [_('keyboard')],
- 'left': [_('left')],
- 'leftpos': [_('left')],
- 'leftx': [_('picture left')],
- 'less2': ['<'],
- 'list': ['list'],
- 'luminance': [_('brightness')],
- 'mediawait': [_('media wait')],
- 'minus2': ['–'],
- 'myfunc': [_('Python'), 'f(x)', 'x'],
- 'myfunc1arg': [_('Python'), 'f(x)', 'x'],
- 'myfunc2arg': [_('Python'), 'f(x,y)', ' '],
- 'myfunc3arg': [_('Python'), 'f(x,y,z)', ' '],
- 'nop': [_(' ')],
- 'not': [_('not')],
- 'number': ['100'],
- 'numbers': [_('numbers')],
- 'orange': [_('orange')],
- 'or2': [_('or')],
- 'pen': [_('pen')],
- 'pendown': [_('pen down')],
- 'pensize': [_('pen size')],
- 'penup': [_('pen up')],
- 'picturelist': [' '],
- 'picture1x1': [' '],
- 'picture1x1a': [' '],
- 'picture2x2': [' '],
- 'picture2x1': [' '],
- 'picture1x2': [' '],
- 'pitch': [_('pitch')],
- 'plus2': [' + '],
- 'polar': [_('polar')],
- 'pop': [_('pop')],
- 'portfolio': [_('portfolio')],
- 'printheap': [_('show heap')],
- 'print': [_('print')],
- 'product2': ['×'],
- 'purple': [_('purple')],
- 'push': [_('push')],
- 'random': [_('random'), _('min'), _('max')],
- 'readcamera': [_('read camera')],
- 'readpixel': [_('read pixel')],
- 'red': [_('red')],
- 'remainder2': [_('mod')],
- 'repeat': [' ', _('repeat')],
- 'reskin': [_('turtle shell')],
- 'resistance': [_('resistance')],
- 'restore': [_('restore last')],
- 'restoreall': [_('restore all')],
- 'rfid': [_('RFID')],
- 'right': [_('right')],
- 'rightpos': [_('right')],
- 'rightx': [_('picture right')],
- 'savepix': [_('save picture')],
- 'savesvg': [_('save SVG')],
- 'sandwichbottom': [' ', ' '],
- 'sandwichcollapsed': [' '],
- 'sandwichtop': [_('top of stack')],
- 'sandwichtop_no_arm': [_('top of stack')],
- 'sandwichtop_no_label': [' ', ' '],
- 'sandwichtop_no_arm_no_label': [' ', _('click to open')],
- 'scale': [_('scale')],
- 'see': [_('turtle sees')],
- 'sensor': [_('sensors')],
- 'setcolor': [_('set color')],
- 'setgray': [_('set gray')],
- 'seth': [_('set heading')],
- 'setpensize': [_('set pen size')],
- 'setscale': [_('set scale')],
- 'setshade': [_('set shade')],
- 'settextcolor': [_('set text color')],
- 'settextsize': [_('set text size')],
- 'setxy': [_('set xy'), _('x'), _('y')],
- 'setxy2': [_('set xy'), _('x'), _('y')],
- 'shade': [_('shade')],
- 'show': [_('show')],
- 'showblocks': [_('show blocks')],
- 'showaligned': [_('show aligned')],
- 'skin': [_('turtle shell')],
- 'sound': [_('sound')],
- 'sqrt': ['√'],
- 'stack': [_('action')],
- 'stack1': [_('action 1')],
- 'stack2': [_('action 2')],
- 'start': [_('start')],
- 'startfill': [_('start fill')],
- 'stopfill': [_('end fill')],
- 'stopstack': [_('stop action')],
- 'storein': [_('store in'), _('box'), _('value')],
- 'storeinbox1': [_('store in box 1')],
- 'storeinbox2': [_('store in box 2')],
- 'string': [_('text')],
- 'template1x1': [' '],
- 'template1x1a': [' '],
- 'template1x2': [' '],
- 'template2x1': [' '],
- 'template2x2': [' '],
- 'templatelist': [' '],
- 'textsize': [_('text size')],
- 'titlex': [_('title x')],
- 'titley': [_('title y')],
- 'toppos': [_('top')],
- 'topy': [_('picture top')],
- 'trash': [_('trash')],
- 'turtle': [_('turtle')],
- 'until': [_('until')],
- 'userdefined': [_(' ')],
- 'userdefined2args': [_(' ')],
- 'userdefined3args': [_(' ')],
- 'video': [' '],
- 'voltage': [_('voltage')],
- 'volume': [_('volume')],
- 'vspace': [' '],
- 'wait': [_('wait')],
- 'while': [_('while')],
- 'while2': [_('while')],
- 'white': [_('white')],
- 'width': [_('width')],
- 'write': [_('write')],
- 'xcor': [_('xcor')],
- 'ycor': [_('ycor')],
- 'yellow': [_('yellow')]}
-
-#
-# Logo primitives
-#
-
-PRIMITIVES = {
- 'addturtle': 'turtle',
- 'and2': 'and',
- 'arc': 'arc',
- 'back': 'back',
- 'black': 'black',
- 'blue': 'blue',
- 'bottompos': 'bpos',
- 'bottomy': 'boty',
- 'box1': 'box1',
- 'box2': 'box2',
- 'box': 'box',
- 'cartesian': 'cartesian',
- 'clean': 'clean',
- 'clearheap': 'clearheap',
- 'color': 'color',
- 'comment': 'comment',
- 'cyan': 'cyan',
- 'division2': 'division',
- 'equal2': 'equal?',
- 'fillscreen': 'fillscreen',
- 'forever': 'forever',
- 'forward': 'forward',
- 'fullscreen': 'fullscreen',
- 'gray': 'gray',
- 'greater2': 'greater?',
- 'green': 'green',
- 'hat': 'nop3',
- 'hat1': 'nop1',
- 'hat2': 'nop2',
- 'heading': 'heading',
- 'height': 'vres',
- 'hideblocks': 'hideblocks',
- 'hspace': 'nop',
- 'identity2': 'id',
- 'if': 'if',
- 'ifelse': 'ifelse',
- 'image': 'show',
- 'kbinput': 'kbinput',
- 'keyboard': 'keyboard',
- 'left': 'left',
- 'leftpos': 'lpos',
- 'leftx': 'leftx',
- 'less2': 'less?',
- 'list': 'bulletlist',
- 'luminance': 'luminance',
- 'mediawait': 'mediawait',
- 'minus2': 'minus',
- 'myfunc': 'myfunction',
- 'myfunc1arg': 'myfunction',
- 'myfunc2arg': 'myfunction2',
- 'myfunc3arg': 'myfunction3',
- 'nop': 'userdefined',
- 'not': 'not',
- 'orange': 'orange',
- 'or2': 'or',
- 'pendown': 'pendown',
- 'pensize': 'pensize',
- 'penup': 'penup',
- 'pitch': 'pitch',
- 'plus2': 'plus',
- 'polar': 'polar',
- 'pop': 'pop',
- 'printheap': 'printheap',
- 'print': 'print',
- 'product2': 'product',
- 'purple': 'purple',
- 'push': 'push',
- 'random': 'random',
- 'red': 'red',
- 'readcamera': 'readcamera',
- 'readpixel': 'readpixel',
- 'remainder2': 'mod',
- 'repeat': 'repeat',
- 'resistance': 'resistance',
- 'rfid': 'rfid',
- 'right': 'right',
- 'rightpos': 'rpos',
- 'rightx': 'rightx',
- 'sandwichtop': 'comment',
- 'sandwichtop_no_arm': 'comment',
- 'sandwichtop_no_label': 'nop',
- 'sandwichtop_no_arm_no_label': 'nop',
- 'sandwichbottom': 'nop',
- 'sandwichcollapsed': 'nop',
- 'savepix': 'savepix',
- 'savesvg': 'savesvg',
- 'see': 'see',
- 'scale': 'scale',
- 'setcolor': 'setcolor',
- 'setgray': 'setgray',
- 'seth': 'seth',
- 'setpensize': 'setpensize',
- 'setscale': 'setscale',
- 'setshade': 'setshade',
- 'settextsize': 'settextsize',
- 'settextcolor': 'settextcolor',
- 'setxy': 'setxy',
- 'setxy2': 'setxy2',
- 'shade': 'shade',
- 'show': 'show',
- 'showblocks': 'showblocks',
- 'showaligned': 'showaligned',
- 'skin': 'skin',
- 'sound': 'sound',
- 'sqrt': 'sqrt',
- 'stack': 'stack',
- 'stack1': 'stack1',
- 'stack2': 'stack2',
- 'start': 'start',
- 'startfill': 'startfill',
- 'stopfill': 'stopfill',
- 'stopstack': 'stopstack',
- 'storein': 'storeinbox',
- 'storeinbox1': 'storeinbox1',
- 'storeinbox2': 'storeinbox2',
- 'template1x1': 't1x1',
- 'template1x1a': 't1x1a',
- 'template1x2': 't1x2',
- 'template2x1': 't2x1',
- 'template2x2': 't2x2',
- 'templatelist': 'bullet',
- 'textsize': 'textsize',
- 'titlex': 'titlex',
- 'titley': 'titley',
- 'toppos': 'tpos',
- 'topy': 'topy',
- 'userdefined': 'userdefined',
- 'userdefined2args': 'userdefined2',
- 'userdefined3args': 'userdefined3',
- 'voltage': 'voltage',
- 'volume': 'volume',
- 'vspace': 'nop',
- 'wait': 'wait',
- 'while2': 'while',
- 'white': 'white',
- 'width': 'hres',
- 'write': 'write',
- 'xcor': 'xcor',
- 'ycor': 'ycor',
- 'yellow': 'yellow'}
-
-#
-# block default values
-#
-
-DEFAULTS = {
- 'addturtle': [1],
- 'arc': [90, 100],
- 'audio': [None],
- 'back': [100],
- 'box': [_('my box')],
- 'camera': ['CAMERA'],
- 'comment': [_('comment')],
- 'description': [None],
- 'fillscreen': [60, 80],
- 'forever': [None, 'vspace'],
- 'forward': [100],
- 'hat': [_('action')],
- 'if': [None, None, 'vspace'],
- 'ifelse': [None, 'vspace', None, 'vspace'],
- 'journal': [None],
- 'left': [90],
- 'list': ['∙ ', '∙ '],
- 'media': [None],
- 'myfunc': ['x', 100],
- 'myfunc1arg': ['x', 100],
- 'myfunc2arg': ['x+y', 100, 100],
- 'myfunc3arg': ['x+y+z', 100, 100, 100],
- 'nop': [100],
- 'number': [100],
- 'random': [0, 100],
- 'repeat': [4, None, 'vspace'],
- 'right': [90],
- 'sandwichtop': [_('label')],
- 'sandwichtop_no_arm': [_('label')],
- 'savepix': [_('picture name')],
- 'savesvg': [_('picture name')],
- 'setcolor': [0],
- 'setgray': [100],
- 'seth': [0],
- 'setpensize': [5],
- 'setscale': [33],
- 'setshade': [50],
- 'settextsize': [48],
- 'settextcolor': [0],
- 'setxy': [0, 0],
- 'setxy2': [0, 0],
- 'show': [_('text')],
- 'showaligned': [_('text')],
- 'stack': [_('action')],
- 'storeinbox1': [100],
- 'storeinbox2': [100],
- 'storein': [_('my box'), 100],
- 'string': [_('text')],
- 'template1x1': [_('Title'), 'None'],
- 'template1x1a': [_('Title'), 'None'],
- 'template1x2': [_('Title'), 'None', 'None'],
- 'template2x1': [_('Title'), 'None', 'None'],
- 'template2x2': [_('Title'), 'None', 'None', 'None', 'None'],
- 'templatelist': [_('Title'), '∙ '],
- 'userdefined': [100],
- 'userdefined2args': [100, 100],
- 'userdefined3args': [100, 100, 100],
- 'video': [None],
- 'wait': [1],
- 'write': [_('text'), 32]}
#
# Blocks that can interchange strings and numbers for their arguments
@@ -697,6 +125,9 @@ STRING_OR_NUMBER_ARGS = ['plus2', 'equal2', 'less2', 'greater2', 'box',
CONTENT_ARGS = ['show', 'showaligned', 'push', 'storein', 'storeinbox1',
'storeinbox2']
+PREFIX_DICTIONARY = {'journal': '#smedia_', 'description': '#sdescr_',
+ 'audio': '#saudio_', 'video': '#svideo_'}
+
#
# Status blocks
#
@@ -709,7 +140,7 @@ MEDIA_SHAPES = ['audiooff', 'audioon', 'audiosmall',
'pythonoff', 'pythonon', 'pythonsmall',
'list', '1x1', '1x1a', '2x1', '1x2', '2x2']
-OVERLAY_SHAPES = ['Cartesian', 'Cartesian_labeled', 'polar']
+OVERLAY_SHAPES = ['Cartesian', 'Cartesian_labeled', 'polar', 'metric']
STATUS_SHAPES = ['status', 'info', 'nostack', 'dupstack', 'noinput',
'emptyheap', 'emptybox', 'nomedia', 'nocode', 'overflowerror',
@@ -735,7 +166,8 @@ OLD_NAMES = {'product': 'product2', 'storeinbox': 'storein', 'minus': 'minus2',
'template1': 'template1x1', 'template2': 'template2x1',
'template6': 'template1x2', 'template7': 'template2x2',
'template4': 'template1x1a', 'hres': 'width', 'vres': 'height',
- 'sandwichtop2': 'sandwichtop'}
+ 'sandwichtop2': 'sandwichtop', 'image': 'show',
+ 'container': 'indentity2', 'insertimage': 'show'}
#
# Define the relative size and postion of media objects
@@ -744,7 +176,7 @@ OLD_NAMES = {'product': 'product2', 'storeinbox': 'storein', 'minus': 'minus2',
TITLEXY = (0.9375, 0.875)
#
-# Relative placement of portfolio objects (used by depreciated blocks)
+# Relative placement of portfolio objects (used by deprecated blocks)
#
TEMPLATES = {'t1x1': (0.5, 0.5, 0.0625, 0.125, 1.05, 0),
't2z1': (0.5, 0.5, 0.0625, 0.125, 1.05, 1.05),
@@ -755,215 +187,21 @@ TEMPLATES = {'t1x1': (0.5, 0.5, 0.0625, 0.125, 1.05, 0),
'insertimage': (0.333, 0.333)}
#
-# Names for blocks without names for popup help
-#
-SPECIAL_NAMES = {
- 'audio': _('audio'),
- 'camera': _('camera'),
- 'division2': _('divide'),
- 'equal2': _('equal'),
- 'greater2': _('greater than'),
- 'hspace': _('horizontal space'),
- 'identity2': _('identity'),
- 'if': _('if then'),
- 'ifelse': _('if then else'),
- 'journal': _('journal'),
- 'less2': _('less than'),
- 'minus2': _('minus'),
- 'nop': _('Python code'),
- 'number': _('number'),
- 'plus2': _('plus'),
- 'product2': _('multiply'),
- 'sqrt': _('square root'),
- 'template1x1': _('presentation 1x1'),
- 'template1x1a': _('presentation 1x1'),
- 'template1x2': _('presentation 1x2'),
- 'template2x1': _('presentation 2x1'),
- 'template2x2': _('presentation 2x2'),
- 'templatelist': _('presentation bulleted list'),
- 'textsize': _('text size'),
- 'video': _('video'),
- 'vspace': _('vertical space')}
-
-#
-# Help messages
-#
-HELP_STRINGS = {
- 'addturtle': _("chooses which turtle to command"),
- 'and2': _("logical AND operator"),
- 'arc': _("moves turtle along an arc"),
- 'audio': _("Sugar Journal audio object"),
- 'back': _("moves turtle backward"),
- 'blocks': _("Palette of variable blocks"),
- 'bottompos': _("ycor of bottom of screen"),
- 'box1': _("Variable 1 (numeric value)"),
- 'box2': _("Variable 2 (numeric value)"),
- 'box': _("named variable (numeric value)"),
- 'camera': _('camera output'),
- 'cartesian': _("displays Cartesian coordinates"),
- 'clean': _("clears the screen and reset the turtle"),
- 'clearheap': _("emptys FILO (first-in-last-out heap)"),
- 'color': _("holds current pen color (can be used in place of a number block)"),
- 'colors': _("Palette of pen colors"),
- 'comment': _("places a comment in your code"),
- 'debugoff': _("Debug"),
- 'description': _("Sugar Journal description field"),
- 'division2': _("divides top numeric input (numerator) by bottom numeric input (denominator)"),
- 'empty': _("permanently deletes items in trash"),
- 'eraseron': _("Clean"),
- 'equal2': _("logical equal-to operator"),
- 'extras': _("Palette of extra options"),
- 'fillscreen': _("fills the background with (color, shade)"),
- 'flow': _("Palette of flow operators"),
- 'forever': _("loops forever"),
- 'forward': _("moves turtle forward"),
- 'fullscreen': _("hides the Sugar toolbars"),
- 'gray': _("holds current gray level (can be used in place of a number block)"),
- 'greater2': _("logical greater-than operator"),
- 'hat1': _("top of Action 1 stack"),
- 'hat2': _("top of Action 2 stack"),
- 'hat': _("top of nameable action stack"),
- 'heading': _("holds current heading value of the turtle (can be used in place of a number block)"),
- 'height': _("the canvas height"),
- 'hideblocks': _("declutters canvas by hiding blocks"),
- 'hideshowoff': _("Hide blocks"),
- 'hspace': _("jogs stack right"),
- 'identity2': _("identity operator used for extending blocks"),
- 'ifelse': _("if-then-else operator that uses boolean operators from Numbers palette"),
- 'if': _("if-then operator that uses boolean operators from Numbers palette"),
- 'journal': _("Sugar Journal media object"),
- 'kbinput': _("query for keyboard input (results stored in keyboard block)"),
- 'keyboard': _("holds results of query-keyboard block"),
- 'leftpos': _("xcor of left of screen"),
- 'left': _("turns turtle counterclockwise (angle in degrees)"),
- 'less2': _("logical less-than operator"),
- 'luminance': _("light level detected by camera"),
- 'mediawait': _("wait for current video or audio to complete"),
- 'minus2': _("subtracts bottom numeric input from top numeric input"),
- 'myfunc': _("a programmable block: used to add advanced math equations, e.g., sin(x)"),
- 'myfunc1arg': _("a programmable block: used to add advanced single-variable math equations, e.g., sin(x)"),
- 'myfunc2arg': _("a programmable block: used to add advanced multi-variable math equations, e.g., sqrt(x*x+y*y)"),
- 'myfunc3arg': _("a programmable block: used to add advanced multi-variable math equations, e.g., sin(x+y+z)"),
- 'next': _('displays next palette'),
- 'nop': _("runs code found in the tamyblock.py module found in the Journal"),
- 'not': _("logical NOT operator"),
- 'numbers': _("Palette of numeric operators"),
- 'number': _("used as numeric input in mathematic operators"),
- 'or': _("logical OR operator"),
- 'orientation': _("changes the orientation of the palette of blocks"),
- 'pendown': _("Turtle will draw when moved."),
- 'pen': _("Palette of pen commands"),
- 'pensize': _("holds current pen size (can be used in place of a number block)"),
- 'penup': _("Turtle will not draw when moved."),
- 'picture1x1': _("presentation template: select Journal object (with description)"),
- 'picture1x1a': _("presentation template: select Journal object (no description)"),
- 'picture1x2': _("presentation template: select two Journal objects"),
- 'picture2x1': _("presentation template: select two Journal objects"),
- 'picture2x2': _("presentation template: select four Journal objects"),
- 'picturelist': _("presentation template: list of bullets"),
- 'pitch': _('microphone input pitch'),
- 'plus2': _("adds two alphanumeric inputs"),
- 'polar': _("displays polar coordinates"),
- 'pop': _("pops value off FILO (first-in last-out heap)"),
- 'portfolio': _("Palette of presentation templates"),
- 'print': _("prints value in status block at bottom of the screen"),
- 'printheap': _("shows values in FILO (first-in last-out heap)"),
- 'product2': _("multiplies two numeric inputs"),
- 'push': _("pushes value onto FILO (first-in last-out heap)"),
- 'random': _("returns random number between minimum (top) and maximum (bottom) values"),
- 'readcamera': _("Average RGB color from camera is pushed to the stack"),
- 'readpixel': _("RGB color under the turtle is pushed to the stack"),
- 'remainder2': _("modular (remainder) operator"),
- 'repeat': _("loops specified number of times"),
- 'resistance': _("sensor input resistance"),
- 'reskin': _("put a custom 'shell' on the turtle"),
- 'restore': _("restores most recent blocks from trash"),
- 'restoreall': _("restore all blocks from trash"),
- 'rfid': _("RFID"),
- 'rightpos': _("xcor of right of screen"),
- 'right': _("turns turtle clockwise (angle in degrees)"),
- 'run-fastoff': _("Run"),
- 'run-slowoff': _("Step"),
- 'sandwichbottom': _("bottom block in a collapsibe stack: click to collapse"),
- 'sandwichcollapsed': _("bottom block in a collapsed stack: click to open"),
- 'sandwichtop': _("top of a collapsible stack"),
- 'sandwichtop_no_label': _("top of a collapsed stack"),
- 'sandwichtop_no_arm': _("top of a collapsible stack"),
- 'sandwichtop_no_arm_no_label': _("top of a collapsed stack"),
- 'savepix': _("saves a picture to the Sugar Journal"),
- 'savesvg': _("saves turtle graphics as an SVG file in the Sugar Journal"),
- 'scale': _("holds current scale value"),
- 'see': _('returns the color that the turtle "sees"'),
- 'sensor': _("Palette of sensor blocks"),
- 'setcolor': _("sets color of the line drawn by the turtle"),
- 'setgray': _("sets gray level of the line drawn by the turtle"),
- 'seth': _("sets the heading of the turtle (0 is towards the top of the screen.)"),
- 'setpensize': _("sets size of the line drawn by the turtle"),
- 'setscale': _("sets the scale of media"),
- 'setshade': _("sets shade of the line drawn by the turtle"),
- 'settextcolor': _("sets color of text drawn by the turtle"),
- 'settextsize': _("sets size of text drawn by turtle"),
- 'setxy': _("moves turtle to position xcor, ycor; (0, 0) is in the center of the screen."),
- 'setxy2': _("moves turtle to position xcor, ycor; (0, 0) is in the center of the screen."),
- 'shade': _("holds current pen shade"),
- 'show': _("draws text or show media from the Journal"),
- 'showblocks': _("restores hidden blocks"),
- 'skin': _("put a custom 'shell' on the turtle"),
- 'sound': _("raw microphone input signal"),
- 'sqrt': _("calculates square root"),
- 'stack1': _("invokes Action 1 stack"),
- 'stack2': _("invokes Action 2 stack"),
- 'stack': _("invokes named action stack"),
- 'start': _("connects action to toolbar run buttons"),
- 'startfill': _("starts filled polygon (used with end fill block)"),
- 'stopfill': _("completes filled polygon (used with start fill block)"),
- 'stopiton': _("Stop turtle"),
- 'stopstack': _("stops current action"),
- 'storeinbox1': _("stores numeric value in Variable 1"),
- 'storeinbox2': _("stores numeric value in Variable 2"),
- 'storein': _("stores numeric value in named variable"),
- 'string': _("string value"),
- 'template1x1': _("presentation template: select Journal object (with description)"),
- 'template1x1a': _("presentation template: select Journal object (no description)"),
- 'template1x2': _("presentation template: select two Journal objects"),
- 'template2x1': _("presentation template: select two Journal objects"),
- 'template2x2': _("presentation template: select four Journal objects"),
- 'templatelist': _("presentation template: list of bullets"),
- 'textcolor': _("holds current text color (can be used in place of a number block)"),
- 'textsize': _("holds current text size (can be used in place of a number block)"),
- 'toppos': _("ycor of top of screen"),
- 'trash': _("Trashcan"),
- 'turtle': _("Palette of turtle commands"),
- 'until': _("do-until-True operator that uses boolean operators from Numbers palette"),
- 'userdefined': _("runs code found in the tamyblock.py module found in the Journal"),
- 'userdefined2args': _("runs code found in the tamyblock.py module found in the Journal"),
- 'userdefined3args': _("runs code found in the tamyblock.py module found in the Journal"),
- 'video': _("Sugar Journal video object"),
- 'voltage': _("sensor voltage"),
- 'volume': _("microphone input volume"),
- 'vspace': _("jogs stack down"),
- 'wait': _("pauses program execution a specified number of seconds"),
- 'while': _("do-while-True operator that uses boolean operators from Numbers palette"),
- 'width': _("the canvas width"),
- 'xcor': _("holds current x-coordinate value of the turtle (can be used in place of a number block)"),
- 'ycor': _("holds current y-coordinate value of the turtle (can be used in place of a number block)")}
-
-#
# 'dead key' Unicode dictionaries
#
DEAD_KEYS = ['grave', 'acute', 'circumflex', 'tilde', 'diaeresis', 'abovering']
-DEAD_DICTS = [{'A':192, 'E':200, 'I':204, 'O':210, 'U':217, 'a':224, 'e':232,
- 'i':236, 'o':242, 'u':249},
- {'A':193, 'E':201, 'I':205, 'O':211, 'U':218, 'a':225, 'e':233,
- 'i':237, 'o':243, 'u':250},
- {'A':194, 'E':202, 'I':206, 'O':212, 'U':219, 'a':226, 'e':234,
- 'i':238, 'o':244, 'u':251},
- {'A':195, 'O':211, 'N':209, 'U':360, 'a':227, 'o':245, 'n':241,
- 'u':361},
- {'A':196, 'E':203, 'I':207, 'O':211, 'U':218, 'a':228, 'e':235,
- 'i':239, 'o':245, 'u':252},
- {'A':197, 'a':229}]
+DEAD_DICTS = [{'A': 192, 'E': 200, 'I': 204, 'O': 210, 'U': 217, 'a': 224,
+ 'e': 232, 'i': 236, 'o': 242, 'u': 249},
+ {'A': 193, 'E': 201, 'I': 205, 'O': 211, 'U': 218, 'a': 225,
+ 'e': 233, 'i': 237, 'o': 243, 'u': 250},
+ {'A': 194, 'E': 202, 'I': 206, 'O': 212, 'U': 219, 'a': 226,
+ 'e': 234, 'i': 238, 'o': 244, 'u': 251},
+ {'A': 195, 'O': 211, 'N': 209, 'U': 360, 'a': 227, 'o': 245,
+ 'n': 241, 'u': 361},
+ {'A': 196, 'E': 203, 'I': 207, 'O': 211, 'U': 218, 'a': 228,
+ 'e': 235, 'i': 239, 'o': 245, 'u': 252},
+ {'A': 197, 'a': 229}]
NOISE_KEYS = ['Shift_L', 'Shift_R', 'Control_L', 'Caps_Lock', 'Pause',
'Alt_L', 'Alt_R', 'KP_Enter', 'ISO_Level3_Shift', 'KP_Divide',
'Escape', 'Return', 'KP_Page_Up', 'Up', 'Down', 'Menu',
diff --git a/TurtleArt/taexporthtml.py b/TurtleArt/taexporthtml.py
index 09042f8..843b8b0 100644
--- a/TurtleArt/taexporthtml.py
+++ b/TurtleArt/taexporthtml.py
@@ -22,67 +22,68 @@ import pygtk
pygtk.require('2.0')
import gtk
import os.path
-from tautils import data_to_string, save_picture, image_to_base64
-from gettext import gettext as _
from cgi import escape
+from gettext import gettext as _
+from tautils import data_to_string, save_picture, image_to_base64, get_path
-def save_html(self, tw, embed_flag=True):
- """ Either: Save canvas and code or pictures to HTML """
- self.embed_images = embed_flag
-
- # A dictionary to define the HTML wrappers around template elements
- self.html_glue = {
- 'doctype': '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' + \
- 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n',
- 'html': ('<html>\n", "</html>\n'),
- 'html_svg': ('<html xmlns="http://www.w3.org/1999/xhtml">\n',
- '</html>\n'),
- 'head': ('<head>\n<!-- Created by Turtle Art -->\n', '</head>\n'),
- 'meta': '<meta http-equiv="content-type" content="text/html; ' + \
- 'charset=UTF-8"/>\n',
- 'title': ('<title>', '</title>\n'),
- 'style': ('<style type="text/css">\n<!--\n', '-->\n</style>\n'),
- 'body': ('<body>\n', '\n</body>\n'),
- 'div': ('<div>\n', '</div>\n'),
- 'slide': ('\n<a name="slide', '"></a>\n'),
- 'h1': ('<h1>', '</h1>\n'),
- 'table': ('<table cellpadding="10\'>\n', '</table>\n'),
- 'tr': ('<tr>\n', '</tr>\n'),
- 'td': ('<td valign="top" width="400" height="300">\n',
- '\n</td>\n'),
- 'img': ('<img width="400" height="300" alt="Image" ' + \
+# A dictionary to define the HTML wrappers around template elements
+HTML_GLUE = {
+ 'doctype': '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' + \
+ 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n',
+ 'html': ('<html>\n', '</html>\n'),
+ 'html_svg': ('<html xmlns="http://www.w3.org/1999/xhtml">\n',
+ '</html>\n'),
+ 'head': ('<head>\n<!-- Created by Turtle Art -->\n', '</head>\n'),
+ 'meta': '<meta http-equiv="content-type" content="text/html; ' + \
+ 'charset=UTF-8"/>\n',
+ 'title': ('<title>', '</title>\n'),
+ 'style': ('<style type="text/css">\n<!--\n', '-->\n</style>\n'),
+ 'body': ('<body>\n', '\n</body>\n'),
+ 'div': ('<div>\n', '</div>\n'),
+ 'slide': ('\n<a name="slide', '"></a>\n'),
+ 'h1': ('<h1>', '</h1>\n'),
+ 'table': ('<table cellpadding="10\'>\n', '</table>\n'),
+ 'tr': ('<tr>\n', '</tr>\n'),
+ 'td': ('<td valign="top" width="400" height="300">\n',
+ '\n</td>\n'),
+ 'img': ('<img width="400" height="300" alt="Image" ' + \
'src="file://"', '".png" />\n'),
- 'img2': ('<img alt="Image" src="image"', '".png" />\n'),
- 'img3': ('<img alt="Image" src="file://"', '"" />\n'),
- 'ul': ('<table>\n', '</table>\n'),
- 'li': ('<tr><td>', '</td></tr>\n')}
+ 'img2': ('<img alt="Image" src="image"', '".png" />\n'),
+ 'img3': ('<img alt="Image" src="file://"', '"" />\n'),
+ 'ul': ('<table>\n', '</table>\n'),
+ 'li': ('<tr><td>', '</td></tr>\n')}
- comment = '<!--\n\<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"' + \
- ' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\n\
+COMMENT = '<!--\n\<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"' + \
+ ' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\n\
<!ENTITY ns_svg "http://www.w3.org/2000/svg">\n\
<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">\n\
]>\n\
-->\n'
- if self.embed_images == True:
- self.html_glue['img'] = ('<img width="400" height="300" alt=" + \
- ""Image" src="data:image/png;base64,\n"',
- '" "/>\n')
- self.html_glue['img2'] = ('<img alt="Image" src="data:image/png;" + \
- "base64,\n"', '" "/>\n')
+
+
+def save_html(self, tw, embed_flag=True):
+ """ Either save the canvas and code or pictures to HTML """
+
+ if embed_flag:
+ HTML_GLUE['img'] = ('<img width="400" height="300" alt=' + \
+ '"Image" src="data:image/png;base64,\n',
+ '"/>\n')
+ HTML_GLUE['img2'] = ('<img alt="Image" src="data:image/png;"' + \
+ '"base64,\n"', '"/>\n')
"""
- If there are saved_pictures, put them into a .html; otherwise, save a
- screendump and the turtle project code.
+ If there are saved_pictures, put them into a .html; otherwise,
+ save a screendump and the turtle project code.
"""
- code = ''
+ htmlcode = ''
if len(tw.saved_pictures) > 0:
for i, p in enumerate(tw.saved_pictures):
- code += self.html_glue['slide'][0] + str(i)
- code += self.html_glue['slide'][1] + \
- self.html_glue['div'][0] + \
- self.html_glue['h1'][0]
- if self.embed_images == True:
+ htmlcode += HTML_GLUE['slide'][0] + str(i)
+ htmlcode += HTML_GLUE['slide'][1] + \
+ HTML_GLUE['div'][0] + \
+ HTML_GLUE['h1'][0]
+ if embed_flag:
f = open(p, 'r')
imgdata = f.read()
f.close()
@@ -90,10 +91,11 @@ def save_html(self, tw, embed_flag=True):
tmp = imgdata
else:
pixbuf = gtk.gdk.pixbuf_new_from_file(p)
- imgdata = image_to_base64(pixbuf, tw.activity)
- tmp = self.html_glue['img2'][0]
+ imgdata = image_to_base64(pixbuf,
+ get_path(tw.activity, 'instance'))
+ tmp = HTML_GLUE['img2'][0]
tmp += imgdata
- tmp += self.html_glue['img2'][1]
+ tmp += HTML_GLUE['img2'][1]
else:
if p.endswith(('.svg')):
f = open(p, 'r')
@@ -101,49 +103,49 @@ def save_html(self, tw, embed_flag=True):
f.close()
tmp = imgdata
else:
- tmp = self.html_glue['img3'][0]
+ tmp = HTML_GLUE['img3'][0]
tmp += p
- tmp += self.html_glue['img3'][1]
- code += tmp + \
- self.html_glue['h1'][1] + \
- self.html_glue['div'][1]
+ tmp += HTML_GLUE['img3'][1]
+ htmlcode += tmp + \
+ HTML_GLUE['h1'][1] + \
+ HTML_GLUE['div'][1]
else:
- if self.embed_images == True:
+ if embed_flag:
imgdata = image_to_base64(save_picture(self.tw.canvas),
- tw.activity)
+ get_path(tw.activity, 'instance'))
else:
imgdata = os.path.join(self.tw.load_save_folder, 'image')
self.tw.save_as_image(imgdata)
- code += (self.html_glue['img'][0] + imgdata + \
- self.html_glue['img'][1])
- code += self.html_glue['div'][0]
- code += escape(data_to_string(tw.assemble_data_to_save(False, True)))
- code += self.html_glue['div'][1]
+ htmlcode += (HTML_GLUE['img'][0] + imgdata + \
+ HTML_GLUE['img'][1])
+ htmlcode += HTML_GLUE['div'][0]
+ htmlcode += escape(data_to_string(
+ tw.assemble_data_to_save(False, True)))
+ htmlcode += HTML_GLUE['div'][1]
if tw.running_sugar:
title = _('Turtle Art') + ' ' + tw.activity.metadata['title']
else:
title = _('Turtle Art')
- header = self.html_glue['doctype'] + \
- self.html_glue['html'][0]
- style = self.html_glue['style'][0] + \
- self.html_glue['style'][1]
+ header = HTML_GLUE['doctype'] + \
+ HTML_GLUE['html'][0]
+ style = HTML_GLUE['style'][0] + \
+ HTML_GLUE['style'][1]
if len(tw.saved_pictures) > 0:
if tw.saved_pictures[0].endswith(('.svg')):
- header = self.html_glue['html_svg'][0]
- style = comment
+ header = HTML_GLUE['html_svg'][0]
+ style = COMMENT
- code = header + \
- self.html_glue['head'][0] + \
- self.html_glue['meta'] + \
- self.html_glue['title'][0] + \
+ return header + \
+ HTML_GLUE['head'][0] + \
+ HTML_GLUE['meta'] + \
+ HTML_GLUE['title'][0] + \
title + \
- self.html_glue['title'][1] + \
+ HTML_GLUE['title'][1] + \
style + \
- self.html_glue['head'][1] + \
- self.html_glue['body'][0] + \
- code + \
- self.html_glue['body'][1] + \
- self.html_glue['html'][1]
- return code
+ HTML_GLUE['head'][1] + \
+ HTML_GLUE['body'][0] + \
+ htmlcode + \
+ HTML_GLUE['body'][1] + \
+ HTML_GLUE['html'][1]
diff --git a/TurtleArt/taexportlogo.py b/TurtleArt/taexportlogo.py
index bd8a1e6..127689b 100644
--- a/TurtleArt/taexportlogo.py
+++ b/TurtleArt/taexportlogo.py
@@ -1,4 +1,4 @@
-#Copyright (c) 2008-10, Walter Bender
+#Copyright (c) 2008-11, Walter Bender
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
@@ -18,351 +18,255 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
-IGNORE = ['hideblocks', 'showblocks', 'fullscreen', 'polar', 'cartesian',
- 'sandwichbottom', 'id']
+from gettext import gettext as _
-import math
try:
from sugar.datastore import datastore
+ HAS_DATASTORE = True
except:
- pass
+ HAS_DATASTORE = False
+
+from TurtleArt.tapalette import logo_commands, logo_functions
+from TurtleArt.taconstants import TITLEXY, CONSTANTS
def save_logo(tw):
""" Set up the Turtle Art color palette and color processing. """
- color_processing = '\
-to tasetpalette :i :r :g :b :myshade \r\
-make "s ((:myshade - 50) / 50) \r\
-ifelse lessp :s 0 [ \r\
-make "s (1 + (:s *0.8)) \r\
-make "r (:r * :s) \r\
-make "g (:g * :s) \r\
-make "b (:b * :s) \r\
-] [ \
-make "s (:s * 0.9) \r\
-make "r (:r + ((99-:r) * :s)) \r\
-make "g (:g + ((99-:g) * :s)) \r\
-make "b (:b + ((99-:b) * :s)) \r\
-] \
-setpalette :i (list :r :g :b) \r\
-end \r\
-\
-to rgb :myi :mycolors :myshade \r\
-make "myr first :mycolors \r\
-make "mycolors butfirst :mycolors \r\
-make "myg first :mycolors \r\
-make "mycolors butfirst :mycolors \r\
-make "myb first :mycolors \r\
-make "mycolors butfirst :mycolors \r\
-tasetpalette :myi :myr :myg :myb :myshade \r\
-output :mycolors \r\
-end \r\
-\
-to processcolor :mycolors :myshade \r\
-if emptyp :mycolors [stop] \r\
-make "i :i + 1 \r\
-processcolor (rgb :i :mycolors :myshade) :myshade \r\
-end \r\
-\
-to tasetshade :shade \r\
-make "myshade modulo :shade 200 \r\
-if greaterp :myshade 99 [make "myshade (199-:myshade)] \r\
-make "i 7 \r\
-make "mycolors :colors \r\
-processcolor :mycolors :myshade \r\
-end \r\
-\
-to tasetpencolor :c \r\
-make "color (modulo (round :c) 100) \r\
-setpencolor :color + 8 \r\
-end \r\
-\
-make "colors [ \
-99 0 0 99 5 0 99 10 0 99 15 0 99 20 0 \
-99 25 0 99 30 0 99 35 0 99 40 0 99 45 0 \
-99 50 0 99 55 0 99 60 0 99 65 0 99 70 0 \
-99 75 0 99 80 0 99 85 0 99 90 0 99 95 0 \
-99 99 0 90 99 0 80 99 0 70 99 0 60 99 0 \
-50 99 0 40 99 0 30 99 0 20 99 0 10 99 0 \
- 0 99 0 0 99 5 0 99 10 0 99 15 0 99 20 \
- 0 99 25 0 99 30 0 99 35 0 99 40 0 99 45 \
- 0 99 50 0 99 55 0 99 60 0 99 65 0 99 70 \
- 0 99 75 0 99 80 0 99 85 0 99 90 0 99 95 \
- 0 99 99 0 95 99 0 90 99 0 85 99 0 80 99 \
- 0 75 99 0 70 99 0 65 99 0 60 99 0 55 99 \
- 0 50 99 0 45 99 0 40 99 0 35 99 0 30 99 \
- 0 25 99 0 20 99 0 15 99 0 10 99 0 5 99 \
- 0 0 99 5 0 99 10 0 99 15 0 99 20 0 99 \
-25 0 99 30 0 99 35 0 99 40 0 99 45 0 99 \
-50 0 99 55 0 99 60 0 99 65 0 99 70 0 99 \
-75 0 99 80 0 99 85 0 99 90 0 99 95 0 99 \
-99 0 99 99 0 90 99 0 80 99 0 70 99 0 60 \
-99 0 50 99 0 40 99 0 30 99 0 20 99 0 10] \r\
-make "shade 50 \r\
-tasetshade :shade \r'
-
- bs = tw.just_blocks()
- code = ''
+
+ # We need to catch several special cases: stacks, boxes, labels, etc.
+ dispatch_table = {
+ 'label': _add_label,
+ 'to action': _add_named_stack,
+ 'action': _add_reference_to_stack,
+ 'storeinbox': _add_named_box,
+ 'box': _add_reference_to_box
+ }
+ constants_table = {
+ 'lpos': _lpos,
+ 'tpos': _tpos,
+ 'rpos': _rpos,
+ 'bpos': _bpos,
+ 'red': _red,
+ 'orange': _orange,
+ 'yellow': _yellow,
+ 'green': _green,
+ 'cyan': _cyan,
+ 'blue': _blue,
+ 'purple': _purple,
+ 'white': _white,
+ 'black': _black,
+ 'titlex': _titlex,
+ 'titley': _titley,
+ 'leftx': _leftx,
+ 'topy': _topy,
+ 'rightx': _rightx,
+ 'bottomy': _bottomy,
+ 'width': _width,
+ 'height': _height
+ }
+
+ stacks_of_blocks = tw.just_blocks()
stack_count = 0
- show = 0
-
- # These flags are used to trigger the prepending of additional procedures.
- random = False
- fillscreen = False
- setcolor = False
- setxy = False
- setxy2 = False
- pensize = False
- setpensize = False
- arc = False
- heap = False
- write = False
- minus = False
- division = False
- image = False
+
+ logocode = ''
"""
Walk through the code, substituting UCB Logo for Turtle Art primitives.
"""
- for b in bs:
+ for stack in stacks_of_blocks:
this_stack = ''
- data = walk_stack(tw.lc, b, tw.block_list.list)
- # We need to catch several special cases: stacks, random, etc.
- stack = False
- namedstack = False
- namedbox = False
- refstack = False
- refbox = False
- myvar = ''
- for d in data:
- if type(d) == type((1, 2)):
- (d, b) = d
- if type(d) is float:
- if namedbox:
- myvar += str(d)
- myvar += ' '
- elif write:
- this_stack += 'labelsize '
- this_stack += str(d)
- write = False
- else:
- this_stack += str(d)
- elif show == 2:
- # Use title for Journal objects
- if d[0:8] == '#smedia_':
- try:
- dsobject = datastore.get(d[8:])
- this_stack += dsobject.metadata['title']
- dsobject.destroy()
- except:
- this_stack += str(d)
- else:
- this_stack += str(d)
- show = 0
+ psuedocode = _walk_stack(tw, stack)
+ if psuedocode == []:
+ continue
+
+ skip = False
+ for i in range(len(psuedocode)):
+ if skip:
+ skip = False
+ continue
+ blk = psuedocode[i]
+ if type(blk) == type((1, 2)):
+ (blk, _blk_no) = blk
+ if blk in logo_commands:
+ logo_command = logo_commands[blk]
else:
- # Translate some Turtle Art primitives into UCB Logo
- if namedstack:
- this_stack += 'to '
- this_stack += d[2:].replace(' ', '_')
- this_stack += '\r'
- stack = True
- namedstack = False
- elif namedbox:
- if d[0:2] == '#s':
- this_stack += 'make "'
- this_stack += d[2:].replace(' ', '_')
- this_stack += ' '
- this_stack += myvar
- namedbox = False
- myvar = ''
- else:
- myvar += d
- elif refstack:
- this_stack += d[2:].replace(' ', '_')
- this_stack += ' '
- refstack = False
- elif refbox:
- this_stack += ':'
- this_stack += d[2:].replace(' ', '_')
- refbox = False
- elif d == 'stack':
- refstack = True
- elif d == 'box':
- refbox = True
- elif d == 'storeinbox':
- namedbox = True
- elif d == 'storeinbox1':
- this_stack += 'make "box1'
- elif d == 'box1':
- this_stack += ':box1'
- elif d == 'storeinbox2':
- this_stack += 'make "box2'
- elif d == 'box2':
- this_stack += ':box2'
- elif d == 'shade':
- this_stack += ':shade'
- elif d == 'setshade':
- setcolor = True
- this_stack += 'tasetshade'
- elif d == 'color':
- this_stack += 'pencolor'
- elif d == 'nop':
- this_stack += ' '
- elif d == 'start':
- this_stack += 'to start\r'
- stack = True
- elif d == 'nop1':
- this_stack += 'to stack1\r'
- stack = True
- elif d == 'nop2':
- this_stack += 'to stack2\r'
- stack = True
- elif d == 'nop3':
- namedstack = True
- elif d == 'stopstack':
- this_stack += 'stop'
- elif d == 'clean':
- this_stack += 'clearscreen'
- elif d == 'setxy':
- setxy = True
- this_stack += 'tasetxypenup'
- elif d == 'setxy2':
- setxy2 = True
- this_stack += 'tasetxy'
- elif d == 'color':
- this_stack += ':color'
- elif d == 'plus':
- this_stack += 'sum'
- elif d == 'setcolor':
- setcolor = True
- this_stack += 'tasetpencolor'
- elif d == 'fillscreen':
- fillscreen = True
- setcolor = True
- this_stack += 'tasetbackground'
- elif d == 'random':
- random = True
- this_stack += 'tarandom'
- elif d == 'pensize':
- pensize = True
- this_stack += 'tapensize'
- elif d == 'setpensize':
- setpensize = True
- this_stack += 'tasetpensize'
- elif d == 'arc':
- arc = True
- this_stack += 'taarc'
- elif d == 'pop':
- heap = True
- this_stack += 'tapop'
- elif d == 'push':
- heap = True
- this_stack += 'tapush'
- elif d == 'heap':
- heap = True
- this_stack += 'taprintheap'
- elif d == 'emptyheap':
- heap = True
- this_stack += 'taclearheap'
- elif d == 'kbinput':
- this_stack += 'make "keyboard readchar'
- elif d == 'keyboard':
- this_stack += ':keyboard'
- elif d == 'insertimage':
- image = True
- elif image:
- # Skip this arg
- image = 2
- elif image == 2:
- # Skip this arg
- image = False
- elif d[0:2] == '#s':
- # output single characters as a string
- if len(d[2:]):
- this_stack += '"'
- this_stack += d[2:]
- # make a sentence out of everything else
- else:
- this_stack += 'sentence '
- this_stack += d[2:].replace('\s', ' "')
- this_stack += '\r'
- elif d == 'write':
- this_stack += 'label'
- write = True
- elif d == 'show' or d == 'showaligned':
- this_stack += 'label'
- show = 1
- elif d == 'minus2':
- this_stack += 'taminus'
- minus = True
- elif d == 'division':
- this_stack += 'quotient'
- elif d == 'lpos':
- this_stack += str(-tw.canvas.width / (tw.coord_scale * 2))
- elif d == 'rpos':
- this_stack += str(tw.canvas.width / (tw.coord_scale * 2))
- elif d == 'bpos':
- this_stack += str(-tw.canvas.height / (tw.coord_scale * 2))
- elif d == 'tpos':
- this_stack += str(tw.canvas.height / (tw.coord_scale * 2))
- elif d in IGNORE:
- this_stack += ' '
- elif show == 1 and d[0:2] == '#s':
- this_stack += d[2:]
- # We don't handle depreciated 'template' blocks
+ logo_command = None
+ if i == 0 and not logo_command in ['to stack1\r', 'to stack2\r',
+ 'to action', 'to start\r']:
+ this_stack = 'to turtleblocks_%d\r' % (stack_count)
+ stack_count += 1
+ if logo_command in dispatch_table:
+ if i + 1 < len(psuedocode):
+ this_stack += dispatch_table[logo_command](
+ psuedocode[i + 1])
+ skip = True
else:
- this_stack += d
+ print 'missing arg to %s' % (logo_command)
+ elif logo_command in constants_table:
+ this_stack += str(constants_table[logo_command](tw))
+ elif logo_command is not None:
+ this_stack += logo_command
+ else: # assume it is an argument
+ if not blk in ['nop', 'nop1', 'nop2', 'nop3']:
+ if type(blk) == str and blk[0:2] == '#s':
+ this_stack += str(blk[2:]).replace(' ', '_')
+ else:
+ this_stack += str(blk).replace(' ', '_')
this_stack += ' '
- if stack:
- stack = False
- # if it is not a stack, we need to add a 'to ta#' label
- elif len(data) > 0:
- this_stack = 'to ta' + str(stack_count) + '\r' + this_stack
- stack_count += 1
- if len(data) > 0:
- code += this_stack
- code += '\rend\r'
-
- # We need to define some additional procedures.
- if minus: # Logo minus only takes one argument.
- code = 'to taminus :y :x\routput sum :x minus :y\rend\r' + code
- if random: # to avoid negative numbers
- code = 'to tarandom :min :max\r' + \
- 'output (random (:max - :min)) + :min\rend\r' + code
- if fillscreen: # Set shade than background color
- code = 'to tasetbackground :color :shade\r' + \
- 'tasetshade :shade\rsetbackground :color\rend\r' + code
- if setcolor: # Load the Turtle Art color palette.
- code = color_processing + code
- if setpensize: # Set int of pensize
- code = 'to tasetpensize :a\rsetpensize round :a\rend\r' + code
- if pensize: # Return only the first argument.
- code = 'to tapensize\routput first round pensize\rend\r' + code
- if setxy2: # Swap and round arguments
- code = 'to tasetxy :x :y\rsetxy :x :y\rend\r' + code
- if setxy: # Swap and round arguments and add pen up/down
- code = 'to tasetxy :x :y\rpenup\rsetxy :x :y\rpendown\rend\r' + code
- if arc: # Turtle Art 'arc' needs to be redefined.
- c = (2 * math.pi) / 360
- code = 'to taarc :a :r\rrepeat round :a [right 1 forward (' + \
- str(c) + ' * :r)]\rend\r' + code
- if heap: # Add psuedo 'push' and 'pop'
- code = 'to tapush :foo\rmake "taheap fput :foo :taheap\rend\r' + \
- 'to tapop\rif emptyp :taheap [stop]\rmake \'tmp first :taheap\r' +\
- 'make "taheap butfirst :taheap\routput :tmp\rend\r' + \
- 'to taclearheap\rmake "taheap []\rend\r' + \
- 'to taprintheap \rprint :taheap\rend\r' + \
- 'make "taheap []\r' + code
- code = 'window\r' + code
- return code
-
-
-def walk_stack(lc, blk, list):
+
+ logocode += this_stack
+ logocode += '\rend\r'
+
+ # We may need to prepend some additional procedures.
+ for key in logo_functions.iterkeys():
+ if key in logocode:
+ logocode = logo_functions[key] + logocode
+
+ if 'tasetshade' in logocode or 'tasetpencolor' in logocode or \
+ 'tasetbackground' in logocode:
+ logocode = logo_functions['tacolor'] + logocode
+
+ logocode = 'window\r' + logocode
+ return logocode
+
+
+def _add_label(string):
+ if type(string) == str and string[0:8] in ['#smedia_', '#saudio_',
+ '#svideo_', '#sdescr_']:
+ string = string[8:]
+ if HAS_DATASTORE:
+ dsobject = datastore.get(string[8:])
+ if 'title' in dsobject.metadata:
+ string = dsobject.metadata['title']
+ else:
+ string = str(string)
+ if string[0:2] == '#s':
+ string = string[2:]
+ string = '"' + string
+ if string.count(' ') > 0:
+ return 'label sentence %s\r' % (string.replace(' ', ' "'))
+ else:
+ return 'label %s' % (string.replace(' ', '_'))
+
+
+def _add_named_stack(action):
+ if type(action) == str and action[0:2] == '#s':
+ return 'to %s\r' % (str(action[2:]).replace(' ', '_'))
+ else:
+ return 'to %s\r' % (str(action).replace(' ', '_'))
+
+
+def _add_reference_to_stack(action):
+ if type(action) == str and action[0:2] == '#s':
+ return '%s' % (str(action[2:]).replace(' ', '_'))
+ else:
+ return '%s' % (str(action).replace(' ', '_'))
+
+
+def _add_named_box(box_name):
+ if type(box_name) == str and box_name[0:2] == '#s':
+ return 'make "%s' % (str(box_name[2:]).replace(' ', '_'))
+ else:
+ return 'make "%s' % (str(box_name).replace(' ', '_'))
+
+
+def _add_reference_to_box(box_name):
+ if type(box_name) == str and box_name[0:2] == '#s':
+ return ':%s' % (str(box_name[2:]).replace(' ', '_'))
+ else:
+ return ':%s' % (str(box_name).replace(' ', '_'))
+
+
+def _lpos(tw):
+ return int(-tw.canvas.width / (tw.coord_scale * 2))
+
+
+def _tpos(tw):
+ return int(tw.canvas.height / (tw.coord_scale * 2))
+
+
+def _rpos(tw):
+ return int(tw.canvas.width / (tw.coord_scale * 2))
+
+
+def _bpos(tw):
+ return int(-tw.canvas.height / (tw.coord_scale * 2))
+
+
+def _width(tw):
+ return int(tw.canvas.width / tw.coord_scale)
+
+
+def _height(tw):
+ int(tw.canvas.height / tw.coord_scale)
+
+
+def _titlex(tw):
+ return int(-(tw.canvas.width * TITLEXY[0]) / (tw.coord_scale * 2))
+
+
+def _titley(tw):
+ return int((tw.canvas.height * TITLEXY[1]) / (tw.coord_scale * 2))
+
+
+def _leftx(tw):
+ return int(-(tw.canvas.width * TITLEXY[0]) / (tw.coord_scale * 2))
+
+
+def _topy(tw):
+ return int((tw.canvas.height * (TITLEXY[1] - 0.125)) / (tw.coord_scale * 2))
+
+
+def _rightx(tw):
+ return 0
+
+
+def _bottomy(tw):
+ return 0
+
+
+def _red(tw):
+ return CONSTANTS['red']
+
+
+def _orange(tw):
+ return CONSTANTS['orange']
+
+
+def _yellow(tw):
+ return CONSTANTS['yellow']
+
+
+def _green(tw):
+ return CONSTANTS['green']
+
+
+def _cyan(tw):
+ return CONSTANTS['cyan']
+
+
+def _blue(tw):
+ return CONSTANTS['blue']
+
+
+def _purple(tw):
+ return CONSTANTS['purple']
+
+
+def _white(tw):
+ return 1
+
+
+def _black(tw):
+ return 0
+
+
+def _walk_stack(tw, blk_in_stack):
""" Convert blocks to logo psuedocode. """
from tautils import find_top_block
- top = find_top_block(blk)
- if blk == top:
- code = lc.run_blocks(top, list, False)
- return code
+ top = find_top_block(blk_in_stack)
+ if blk_in_stack == top:
+ psuedocode = tw.lc.run_blocks(top, tw.block_list.list, False)
+ return psuedocode
else:
return []
diff --git a/TurtleArt/tagettext.py b/TurtleArt/tagettext.py
new file mode 100644
index 0000000..ebeebb3
--- /dev/null
+++ b/TurtleArt/tagettext.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2010-11 Walter Bender, Martin Langhoff
+# License: GPLv2
+
+# Defines the magic global _() with the right params so all modules
+# can use it.
+#
+# Plugins that want to override MUST use a different technique. See
+# the developer notes in the TA wikipage.
+#
+import gettext
+import os
+
+# In a git checkout, locale is in the root of the project
+# so one dir "up" from tagettext.py
+localedir = os.path.join(os.path.dirname(os.path.dirname(__file__)),
+ 'locale' )
+
+if os.path.exists(localedir):
+ # works from a git checkout
+ gettext.install('org.laptop.TurtleArtActivity', localedir)
+else:
+ # fallback for packaged TA (rpm, xo)
+ gettext.install('org.laptop.TurtleArtActivity')
diff --git a/TurtleArt/tajail.py b/TurtleArt/tajail.py
index 081248f..0444dc7 100644
--- a/TurtleArt/tajail.py
+++ b/TurtleArt/tajail.py
@@ -19,14 +19,14 @@
#THE SOFTWARE.
# A naive approach to running myfunc in a jail
-import logging
-_logger = logging.getLogger('turtleart-activity')
import traceback
from time import *
from math import *
+from gettext import gettext as _
def myfunc(f, args):
+ ''' Run inline Python code '''
# check to make sure no import calls are made
if len(args) == 1:
myf = 'def f(x): return ' + f.replace('import', '')
@@ -45,11 +45,16 @@ def myfunc(f, args):
return userdefined.values()[0](args[0], args[1], args[2])
-def myfunc_import(lc, f, x):
+def myfunc_import(parent, f, x):
+ ''' Run Python code imported from Journal '''
+ if 'def myblock(lc,' in f:
+ base_class = parent.tw.lc # pre-v107, we passed lc
+ else:
+ base_class = parent.tw # as of v107, we pass tw
userdefined = {}
try:
exec f in globals(), userdefined
- return userdefined['myblock'](lc, x)
+ return userdefined['myblock'](base_class, x)
except:
traceback.print_exc()
return None
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py
index e3576fa..12be92f 100644
--- a/TurtleArt/talogo.py
+++ b/TurtleArt/talogo.py
@@ -22,65 +22,22 @@
#THE SOFTWARE.
import gtk
-
from time import time
-from math import sqrt
-from numpy import append
-from numpy.fft import rfft
-from random import uniform
-from operator import isNumberType
-from fcntl import ioctl
-
-import os.path
+from operator import isNumberType
from UserDict import UserDict
-try:
- from sugar.datastore import datastore
-except ImportError:
- pass
-
-from taconstants import TAB_LAYER, BLACK, WHITE, \
- DEFAULT_SCALE, ICON_SIZE, BLOCK_NAMES, CONSTANTS, SENSOR_DC_NO_BIAS, \
- SENSOR_DC_BIAS, XO1, XO15
-from tagplay import play_audio_from_file, play_movie_from_file, stop_media, \
- media_playing
-from tacamera import Camera
-import v4l2
-from tajail import myfunc, myfunc_import
+from taconstants import TAB_LAYER, DEFAULT_SCALE, PREFIX_DICTIONARY
+from tapalette import block_names, value_blocks
from tautils import get_pixbuf_from_journal, convert, data_from_file, \
- text_media_type, round_int, chr_to_ord, strtype, get_path
-
-from RtfParser import RtfTextOnly
+ text_media_type, round_int, debug_output
-from ringbuffer import RingBuffer1d
+from util.RtfParser import RtfTextOnly
from gettext import gettext as _
-VALUE_BLOCKS = ['box1', 'box2', 'color', 'shade', 'gray', 'scale', 'pensize',
- 'heading', 'xcor', 'ycor', 'pop', 'see', 'keyboard',
- 'sound', 'volume', 'pitch', 'resistance', 'voltage',
- 'luminance']
-
-import logging
-_logger = logging.getLogger('turtleart-activity')
-
-
-def find_device():
- """ Search for RFID devices. Return a device instance or None. """
- device = None
- for i in os.listdir(os.path.join('.', 'devices')):
- if not os.path.isdir(os.path.join('.', 'devices', i)):
- try:
- _tempmod = __import__('devices.%s' % i.split('.')[0],
- globals(), locals(), ['RFIDReader'], -1)
- devtemp = _tempmod.RFIDReader()
- if devtemp.get_present() == True:
- device = devtemp
- except Exception, e:
- _logger.error('FIND_DEVICE: %s: %s' % (i, e))
- pass
- return device
+media_blocks_dictionary = {} # new media blocks get added here
+primitive_dictionary = {} # new block primitives get added here
class noKeyError(UserDict):
@@ -112,213 +69,6 @@ class logoerror(Exception):
# Utility functions
-
-def _num_type(x):
- """ Is x a number type? """
- if type(x) == int:
- return True
- if type(x) == float:
- return True
- if type(x) == ord:
- return True
- return False
-
-
-def _string_to_num(x):
- """ Try to comvert a string to a number """
- xx = convert(x.replace(self.tw.decimal_point, '.'), float)
- if type(xx) is float:
- return xx
- else:
- xx, xflag = chr_to_ord(x)
- if xflag:
- return xx
- else:
- raise logoerror("#syntaxerror")
-
-
-def _and(x, y):
- """ Logical and """
- return x & y
-
-
-def _or(x, y):
- """ Logical or """
- return x | y
-
-
-def _careful_divide(x, y):
- """ Raise error on divide by zero """
- try:
- return x / y
- except ZeroDivisionError:
- raise logoerror("#zerodivide")
- except TypeError:
- try:
- return _string_to_num(x) / _string_to_num(y)
- except ZeroDivisionError:
- raise logoerror("#zerodivide")
- except ValueError:
- raise logoerror("#syntaxerror")
- except TypeError:
- raise logoerror("#notanumber")
-
-
-def _equal(x, y):
- """ Numeric and logical equal """
- try:
- return float(x) == float(y)
- except TypeError:
- typex, typey = False, False
- if strtype(x):
- typex = True
- if strtype(y):
- typey = True
- if typex and typey:
- return x == y
- try:
- return _string_to_num(x) == _string_to_num(y)
- except ValueError:
- raise logoerror("#syntaxerror")
-
-
-def _less(x, y):
- """ Compare numbers and strings """
- try:
- return float(x) < float(y)
- except ValueError:
- typex, typey = False, False
- if strtype(x):
- typex = True
- if strtype(y):
- typey = True
- if typex and typey:
- return x < y
- try:
- return _string_to_num(x) < _string_to_num(y)
- except TypeError:
- raise logoerror("#notanumber")
-
-
-def _more(x, y):
- """ Compare numbers and strings """
- return _less(y, x)
-
-
-def _plus(x, y):
- """ Add numbers, concat strings """
- if _num_type(x) and _num_type(y):
- return(x + y)
- else:
- if _num_type(x):
- xx = str(round_int(x))
- else:
- xx = str(x)
- if _num_type(y):
- yy = str(round_int(y))
- else:
- yy = str(y)
- return(xx + yy)
-
-
-def _minus(x, y):
- """ Numerical subtraction """
- if _num_type(x) and _num_type(y):
- return(x - y)
- try:
- return _string_to_num(x) - _string_to_num(y)
- except TypeError:
- raise logoerror("#notanumber")
-
-
-def _product(x, y):
- """ Numerical multiplication """
- if _num_type(x) and _num_type(y):
- return(x * y)
- try:
- return _string_to_num(x) * _string_to_num(y)
- except TypeError:
- raise logoerror("#notanumber")
-
-
-def _mod(x, y):
- """ Numerical mod """
- if _num_type(x) and _num_type(y):
- return(x % y)
- try:
- return _string_to_num(x) % _string_to_num(y)
- except TypeError:
- raise logoerror("#notanumber")
- except ValueError:
- raise logoerror("#syntaxerror")
-
-
-def _sqrt(x):
- """ Square root """
- if _num_type(x):
- if x < 0:
- raise logoerror("#negroot")
- return sqrt(x)
- try:
- return sqrt(_string_to_num(x))
- except ValueError:
- raise logoerror("#negroot")
- except TypeError:
- raise logoerror("#notanumber")
-
-
-def _random(x, y):
- """ Random integer """
- if _num_type(x) and _num_type(y):
- return(int(round(uniform(x, y), 0)))
- xx, xflag = chr_to_ord(x)
- yy, yflag = chr_to_ord(y)
- if xflag and yflag:
- return chr(int(round(uniform(xx, yy), 0)))
- if not xflag:
- xx = _string_to_num(x)
- if not yflag:
- yy = _string_to_num(y)
- try:
- return(int(round(uniform(xx, yy), 0)))
- except TypeError:
- raise logoerror("#notanumber")
-
-
-def _identity(x):
- """ Identity function """
- return(x)
-
-
-def _avg(array, abs_value=False):
- """ Calc. the average value of an array """
- if len(array) == 0:
- return 0
- array_sum = 0
- if abs_value:
- for a in array:
- array_sum += abs(a)
- else:
- for a in array:
- array_sum += a
- return float(array_sum) / len(array)
-
-
-def stop_logo(tw):
- """ Stop logo is called from the Stop button on the toolbar """
- tw.step_time = 0
- tw.lc.step = _just_stop()
- stop_media(tw.lc)
- if tw.camera_available:
- if tw.lc._video_capture_device is not None:
- # restore AG and then close device
- tw.lc._set_ag(1)
- tw.lc._video_capture_device.close()
- tw.lc._video_capture_device = None
- tw.lc.camera.stop_camera_input()
- tw.active_turtle.show()
-
-
def _just_stop():
""" yield False to stop stack """
yield False
@@ -337,164 +87,15 @@ class LogoCode:
self.tw = tw
self.oblist = {}
- DEFPRIM = {
- '(': [1, lambda self, x: self._prim_opar(x)],
- 'and': [2, lambda self, x, y: _and(x, y)],
- 'arc': [2, lambda self, x, y: self._prim_arc(self.tw.canvas.arc, x,
- y)],
- 'audio': [1, lambda self, x: self._play_sound(x)],
- 'back': [1, lambda self, x: self._prim_move(self.tw.canvas.forward,
- -x)],
- 'black': [0, lambda self: BLACK],
- 'blue': [0, lambda self: CONSTANTS['blue']],
- 'bpos': [0, lambda self: CONSTANTS['bottompos']],
- 'boty': [0, lambda self: CONSTANTS['bottomy']],
- 'box1': [0, lambda self: self.boxes['box1']],
- 'box': [1, lambda self, x: self._box(x)],
- 'box2': [0, lambda self: self.boxes['box2']],
- 'bullet': [1, self._prim_bullet, True],
- 'bulletlist': [1, self._prim_list, True],
- 'cartesian': [0, lambda self: self.tw.set_cartesian(True)],
- 'clean': [0, lambda self: self.prim_clear()],
- 'clearheap': [0, lambda self: self._empty_heap()],
- 'color': [0, lambda self: self.tw.canvas.color],
- 'gray': [0, lambda self: self.tw.canvas.gray],
- 'comment': [1, lambda self, x: self._prim_print(x, True)],
- 'container': [1, lambda self, x: x],
- 'cyan': [0, lambda self: CONSTANTS['cyan']],
- 'define': [2, self._prim_define],
- 'division': [2, lambda self, x, y: _careful_divide(x, y)],
- 'equal?': [2, lambda self, x, y: _equal(x, y)],
- 'fillscreen': [2, lambda self, x, y: self.tw.canvas.fillscreen(x, y)],
- 'forever': [1, self._prim_forever, True],
- 'forward': [1, lambda self, x: self._prim_move(self.tw.canvas.forward,
- x)],
- 'fullscreen': [0, lambda self: self.tw.set_fullscreen()],
- 'greater?': [2, lambda self, x, y: _more(x, y)],
- 'green': [0, lambda self: CONSTANTS['green']],
- 'heading': [0, lambda self: self.tw.canvas.heading],
- 'hideblocks': [0, lambda self: self.tw.hideblocks()],
- 'hres': [0, lambda self: CONSTANTS['width']],
- 'id': [1, lambda self, x: _identity(x)],
- 'if': [2, self._prim_if, True],
- 'ifelse': [3, self._prim_ifelse, True],
- 'insertimage': [1, lambda self, x: self._insert_image(False,
- filepath=x)],
- 'kbinput': [0, lambda self: self._prim_kbinput()],
- 'keyboard': [0, lambda self: self.keyboard],
- 'left': [1, lambda self, x: self._prim_right(-x)],
- 'leftx': [0, lambda self: CONSTANTS['leftx']],
- 'lpos': [0, lambda self: CONSTANTS['leftpos']],
- 'less?': [2, lambda self, x, y: _less(x, y)],
- 'luminance': [0, lambda self: self._read_camera(True)],
- 'mediawait': [0, self._media_wait, True],
- 'minus': [2, lambda self, x, y: _minus(x, y)],
- 'mod': [2, lambda self, x, y: _mod(x, y)],
- 'myfunction': [2, lambda self, f, x: self._myfunction(f, [x])],
- 'myfunction2': [3, lambda self, f, x, y: self._myfunction(f, [x, y])],
- 'myfunction3': [4, lambda self, f, x, y, z: self._myfunction(
- f, [x, y, z])],
- 'nop': [0, lambda self: None],
- 'nop1': [0, lambda self: None],
- 'nop2': [0, lambda self: None],
- 'nop3': [1, lambda self, x: None],
- 'not': [1, lambda self, x: not x],
- 'orange': [0, lambda self: CONSTANTS['orange']],
- 'or': [2, lambda self, x, y: _or(x, y)],
- 'pendown': [0, lambda self: self.tw.canvas.setpen(True)],
- 'pensize': [0, lambda self: self.tw.canvas.pensize],
- 'penup': [0, lambda self: self.tw.canvas.setpen(False)],
- 'pitch': [0, lambda self: self._get_pitch()],
- 'plus': [2, lambda self, x, y: _plus(x, y)],
- 'polar': [0, lambda self: self.tw.set_polar(True)],
- 'pop': [0, lambda self: self._prim_pop()],
- 'print': [1, lambda self, x: self._prim_print(x, False)],
- 'printheap': [0, lambda self: self._prim_print_heap()],
- 'product': [2, lambda self, x, y: _product(x, y)],
- 'purple': [0, lambda self: CONSTANTS['purple']],
- 'push': [1, lambda self, x: self._prim_push(x)],
- 'random': [2, lambda self, x, y: _random(x, y)],
- 'readcamera': [0, lambda self: self._read_camera()],
- 'readpixel': [0, lambda self: self._read_pixel()],
- 'red': [0, lambda self: CONSTANTS['red']],
- 'repeat': [2, self._prim_repeat, True],
- 'resistance': [0, lambda self: self._get_resistance()],
- 'rfid': [0, lambda self: self.tw.rfid_idn],
- 'right': [1, lambda self, x: self._prim_right(x)],
- 'rightx': [0, lambda self: CONSTANTS['rightx']],
- 'rpos': [0, lambda self: CONSTANTS['rightpos']],
- 'savepix': [1, lambda self, x: self._save_picture(x)],
- 'savesvg': [1, lambda self, x: self._save_svg(x)],
- 'scale': [0, lambda self: self.scale],
- 'see': [0, lambda self: self.see()],
- 'setcolor': [1, lambda self, x: self._prim_set('color',
- self.tw.canvas.setcolor, x)],
- 'setgray': [1, lambda self, x: self._prim_set('gray',
- self.tw.canvas.setgray, x)],
- 'seth': [1, lambda self, x: self._prim_set('heading',
- self.tw.canvas.seth, x)],
- 'setpensize': [1, lambda self, x: self._prim_set('pensize',
- self.tw.canvas.setpensize, x)],
- 'setscale': [1, lambda self, x: self._prim_set('scale',
- self._set_scale, x)],
- 'setshade': [1, lambda self, x: self._prim_set('shade',
- self.tw.canvas.setshade, x)],
- 'settextcolor': [1, lambda self, x: self.tw.canvas.settextcolor(x)],
- 'settextsize': [1, lambda self, x: self.tw.canvas.settextsize(x)],
- 'setxy2': [2, lambda self, x, y: self._prim_move(self.tw.canvas.setxy,
- x, y)],
- 'setxy': [2, lambda self, x, y: self._prim_move(self.tw.canvas.setxy,
- x, y, pendown=False)],
- 'shade': [0, lambda self: self.tw.canvas.shade],
- 'show': [1, lambda self, x: self._show(x, True)],
- 'showaligned': [1, lambda self, x: self._show(x, False)],
- 'showblocks': [0, lambda self: self.tw.showblocks()],
- 'skin': [1, lambda self, x: self._reskin(x)],
- 'sound': [0, lambda self: self._get_sound()],
- 'sqrt': [1, lambda self, x: _sqrt(x)],
- 'stack1': [0, self._prim_stack1, True],
- 'stack': [1, self._prim_stack, True],
- 'stack2': [0, self._prim_stack2, True],
- 'start': [0, lambda self: self._prim_start()],
- 'startfill': [0, lambda self: self.tw.canvas.start_fill()],
- 'stopfill': [0, lambda self: self.tw.canvas.stop_fill()],
- 'stopstack': [0, lambda self: self._prim_stopstack()],
- 'storeinbox1': [1, lambda self, x: self._prim_setbox('box1', None, x)],
- 'storeinbox2': [1, lambda self, x: self._prim_setbox('box2', None, x)],
- 'storeinbox': [2, lambda self, x, y: self._prim_setbox('box3', x, y)],
- 't1x1': [2, lambda self, x, y: self._show_template1x1(x, y)],
- 't1x1a': [2, lambda self, x, y: self._show_template1x1a(x, y)],
- 't1x2': [3, lambda self, x, y, z: self._show_template1x2(x, y, z)],
- 't2x1': [3, lambda self, x, y, z: self._show_template2x1(x, y, z)],
- 't2x2': [5, lambda self, x, y, z, a, b: self._show_template2x2(
- x, y, z, a, b)],
- 'textcolor': [0, lambda self: self.tw.canvas.textcolor],
- 'textsize': [0, lambda self: self.tw.textsize],
- 'titlex': [0, lambda self: CONSTANTS['titlex']],
- 'titley': [0, lambda self: CONSTANTS['titley']],
- 'topy': [0, lambda self: CONSTANTS['topy']],
- 'tpos': [0, lambda self: CONSTANTS['toppos']],
- 'turtle': [1, lambda self, x: self.tw.canvas.set_turtle(x)],
- 'userdefined': [1, lambda self, x: self._prim_myblock([x])],
- 'userdefined2': [2, lambda self, x, y: self._prim_myblock([x, y])],
- 'userdefined3': [3, lambda self, x, y,
- z: self._prim_myblock([x, y, z])],
- 'video': [1, lambda self, x: self._play_video(x)],
- 'voltage': [0, lambda self: self._get_voltage()],
- 'volume': [0, lambda self: self._get_volume()],
- 'vres': [0, lambda self: CONSTANTS['height']],
- 'wait': [1, self._prim_wait, True],
- 'white': [0, lambda self: WHITE],
- 'write': [2, lambda self, x, y: self._write(self, x, y)],
- 'xcor': [0, lambda self: self.tw.canvas.xcor / self.tw.coord_scale],
- 'ycor': [0, lambda self: self.tw.canvas.ycor / self.tw.coord_scale],
- 'yellow': [0, lambda self: CONSTANTS['yellow']]}
+ DEFPRIM = {'(': [1, lambda self, x: self._prim_opar(x)],
+ 'define': [2, self._prim_define],
+ 'nop': [0, lambda self: None]}
for p in iter(DEFPRIM):
if len(DEFPRIM[p]) == 2:
- self._def_prim(p, DEFPRIM[p][0], DEFPRIM[p][1])
+ self.def_prim(p, DEFPRIM[p][0], DEFPRIM[p][1])
else:
- self._def_prim(p, DEFPRIM[p][0], DEFPRIM[p][1], DEFPRIM[p][2])
+ self.def_prim(p, DEFPRIM[p][0], DEFPRIM[p][1], DEFPRIM[p][2])
self.symtype = type(self._intern('print'))
self.listtype = type([])
@@ -520,38 +121,26 @@ class LogoCode:
self.trace = 0
self.update_values = False
self.gplay = None
- self.ag = None
self.filepath = None
self.dsobject = None
+ self.start_time = None
- # Scale factors for depreciated portfolio blocks
- self.title_height = int((self.tw.canvas.height / 20) * self.tw.scale)
self.body_height = int((self.tw.canvas.height / 40) * self.tw.scale)
- self.bullet_height = int((self.tw.canvas.height / 30) * self.tw.scale)
self.scale = DEFAULT_SCALE
- self.max_samples = 1500
- self.input_step = 1
-
- self.ringbuffer = RingBuffer1d(self.max_samples, dtype='int16')
- if self.tw.hw == XO1:
- self.voltage_gain = 0.00002225
- self.voltage_bias = 1.140
- elif self.tw.hw == XO15:
- self.voltage_gain = -0.0001471
- self.voltage_bias = 1.695
-
- if self.tw.camera_available:
- self._video_capture_device = None
- if self.tw.running_sugar:
- self.imagepath = get_path(self.tw.activity,
- 'data/turtlepic.png')
- else:
- self.imagepath = '/tmp/turtlepic.png'
- self.camera = Camera(self.imagepath)
+ def stop_logo(self):
+ """ Stop logo is called from the Stop button on the toolbar """
+ self.tw.step_time = 0
+ self.step = _just_stop()
+ for plugin in self.tw._plugins:
+ plugin.stop()
+ if self.tw.gst_available:
+ from tagplay import stop_media
+ stop_media(self)
+ self.tw.active_turtle.show()
- def _def_prim(self, name, args, fcn, rprim=False):
+ def def_prim(self, name, args, fcn, rprim=False):
""" Define the primitives associated with the blocks """
sym = self._intern(name)
sym.nargs, sym.fcn = args, fcn
@@ -573,8 +162,6 @@ class LogoCode:
self.stacks['stack2'] = None
self.tw.saving_svg = False
- self.find_value_blocks()
- self._update_audio_mode()
if self.trace > 0:
self.update_values = True
else:
@@ -592,7 +179,11 @@ class LogoCode:
if b.connections is not None and len(b.connections) > 1 and \
b.connections[1] is not None:
code = self._blocks_to_code(b)
- x = b.connections[1].values[0]
+ try:
+ x = b.connections[1].values[0]
+ except IndexError:
+ self.tw.showlabel('#nostack')
+ return None
if type(convert(x, float, False)) == float:
if int(float(x)) == x:
x = int(x)
@@ -600,7 +191,8 @@ class LogoCode:
code = self._blocks_to_code(blk)
if run_flag:
- _logger.debug("running code: %s" % (code))
+ # debug_output("running code: %s" % (code), self.tw.running_sugar)
+ self.start_time = time()
self._setup_cmd(code)
if not self.tw.hide:
self.tw.display_coordinates()
@@ -625,35 +217,22 @@ class LogoCode:
code.append(float(blk.values[0]))
except ValueError:
code.append(float(ord(blk.values[0][0])))
- elif blk.name == 'string' or blk.name == 'title':
+ elif blk.name == 'string' or \
+ blk.name == 'title': # deprecated block
if type(blk.values[0]) == float or type(blk.values[0]) == int:
if int(blk.values[0]) == blk.values[0]:
blk.values[0] = int(blk.values[0])
code.append('#s' + str(blk.values[0]))
else:
code.append('#s' + blk.values[0])
- elif blk.name == 'journal':
- if blk.values[0] is not None:
- code.append('#smedia_' + str(blk.values[0]))
- else:
- code.append('#smedia_None')
- elif blk.name == 'description':
+ elif blk.name in PREFIX_DICTIONARY:
if blk.values[0] is not None:
- code.append('#sdescr_' + str(blk.values[0]))
+ code.append(PREFIX_DICTIONARY[blk.name] + \
+ str(blk.values[0]))
else:
- code.append('#sdescr_None')
- elif blk.name == 'audio':
- if blk.values[0] is not None:
- code.append('#saudio_' + str(blk.values[0]))
- else:
- code.append('#saudio_None')
- elif blk.name == 'video':
- if blk.values[0] is not None:
- code.append('#svideo_' + str(blk.values[0]))
- else:
- code.append('#svideo_None')
- elif blk.name == 'camera':
- code.append('#smedia_CAMERA')
+ code.append(PREFIX_DICTIONARY[blk.name] + 'None')
+ elif blk.name in media_blocks_dictionary:
+ code.append('#smedia_' + blk.name.upper())
else:
return ['%nothing%']
else:
@@ -718,7 +297,7 @@ class LogoCode:
elif self.tw.interactive_mode:
self.tw.toolbar_shapes['stopiton'].set_layer(TAB_LAYER)
self.running = True
- self._icall(self._evline, blklist)
+ self.icall(self.evline, blklist)
yield True
if self.tw.running_sugar:
self.tw.activity.stop_turtle_button.set_icon("stopitoff")
@@ -727,12 +306,12 @@ class LogoCode:
yield False
self.running = False
- def _icall(self, fcn, *args):
+ def icall(self, fcn, *args):
""" Add a function and its arguments to the program stack. """
self.istack.append(self.step)
self.step = fcn(*(args))
- def _evline(self, blklist):
+ def evline(self, blklist):
""" Evaluate a line of code from the list. """
oldiline = self.iline
self.iline = blklist[:]
@@ -762,7 +341,7 @@ class LogoCode:
(token, self.bindex) = self.iline[1]
# Process the token and any arguments.
- self._icall(self._eval)
+ self.icall(self._eval)
yield True
# Time to unhighlight the current block.
@@ -778,7 +357,7 @@ class LogoCode:
self.tw.block_list.list[self.bindex].highlight()
raise logoerror(str(self.iresult))
self.iline = oldiline
- self._ireturn()
+ self.ireturn()
if not self.tw.hide and self.tw.step_time > 0:
self.tw.display_coordinates()
yield True
@@ -795,7 +374,7 @@ class LogoCode:
# We highlight blocks here in case an error occurs...
if not self.tw.hide and bindex is not None:
self.tw.block_list.list[bindex].highlight()
- self._icall(self._evalsym, token)
+ self.icall(self._evalsym, token)
yield True
# and unhighlight if everything was OK.
if not self.tw.hide and bindex is not None:
@@ -804,7 +383,7 @@ class LogoCode:
else:
res = token
- self._ireturn(res)
+ self.ireturn(res)
yield True
def _evalsym(self, token):
@@ -817,32 +396,31 @@ class LogoCode:
raise logoerror("#noinput")
for i in range(token.nargs):
self._no_args_check()
- self._icall(self._eval)
+ self.icall(self._eval)
yield True
self.arglist.append(self.iresult)
if self.cfun.rprim:
if type(self.cfun.fcn) == self.listtype:
- _logger.debug("evalsym rprim list: %s" % (str(token)))
- self._icall(self._ufuncall, self.cfun.fcn)
+ # debug_output('evalsym rprim list: %s' % (str(token)),
+ # self.tw.running_sugar)
+ self.icall(self._ufuncall, self.cfun.fcn)
yield True
else:
- # print "evalsym rprim: ", token
- self._icall(self.cfun.fcn, *self.arglist)
+ self.icall(self.cfun.fcn, *self.arglist)
yield True
result = None
else:
- # print "evalsym: ", token
result = self.cfun.fcn(self, *self.arglist)
self.cfun, self.arglist = oldcfun, oldarglist
if self.arglist is not None and result == None:
raise logoerror("%s %s %s" % \
(oldcfun.name, _("did not output to"), self.cfun.name))
- self._ireturn(result)
+ self.ireturn(result)
yield True
def _ufuncall(self, body):
""" ufuncall """
- self._ijmp(self._evline, body)
+ self.ijmp(self.evline, body)
yield True
def doevalstep(self):
@@ -869,12 +447,12 @@ class LogoCode:
return False
return True
- def _ireturn(self, res=None):
+ def ireturn(self, res=None):
""" return value """
self.step = self.istack.pop()
self.iresult = res
- def _ijmp(self, fcn, *args):
+ def ijmp(self, fcn, *args):
""" ijmp """
self.step = fcn(*(args))
@@ -898,123 +476,6 @@ class LogoCode:
# Primitives
#
- def prim_clear(self):
- """ Clear screen """
- stop_media(self)
- self.tw.canvas.clearscreen()
- self.scale = DEFAULT_SCALE
- self.tw.set_polar(False)
- self.tw.set_cartesian(False)
- self.hidden_turtle = None
- for name in VALUE_BLOCKS:
- self.update_label_value(name)
-
- def _prim_start(self):
- """ Start block: recenter """
- if self.tw.running_sugar:
- self.tw.activity.recenter()
-
- def _prim_wait(self, time):
- """ Show the turtle while we wait """
- self.tw.active_turtle.show()
- endtime = _millisecond() + time * 1000.
- while _millisecond() < endtime:
- yield True
- self.tw.active_turtle.hide()
- self._ireturn()
- yield True
-
- def _prim_repeat(self, num, blklist):
- """ Repeat list num times. """
- num = self._int(num)
- for i in range(num):
- self._icall(self._evline, blklist[:])
- yield True
- if self.procstop:
- break
- self._ireturn()
- yield True
-
- def _prim_bullet(self, blklist):
- """ Depreciated bullet-list block style """
- self._show_bullets(blklist)
- self._ireturn()
- yield True
-
- def _prim_list(self, blklist):
- """ Expandable list block """
- self._show_list(blklist)
- self._ireturn()
- yield True
-
- def _myfunction(self, f, x):
- """ Programmable block """
- try:
- y = myfunc(f, x)
- if str(y) == 'nan':
- _logger.debug("python function returned nan")
- stop_logo(self.tw)
- raise logoerror("#notanumber")
- else:
- return y
- except ZeroDivisionError:
- stop_logo(self.tw)
- raise logoerror("#zerodivide")
- except ValueError, e:
- stop_logo(self.tw)
- raise logoerror('#' + str(e))
- except SyntaxError, e:
- stop_logo(self.tw)
- raise logoerror('#' + str(e))
- except NameError, e:
- stop_logo(self.tw)
- raise logoerror('#' + str(e))
- except OverflowError:
- stop_logo(self.tw)
- raise logoerror("#overflowerror")
- except TypeError:
- stop_logo(self.tw)
- raise logoerror("#notanumber")
-
- def _prim_forever(self, blklist):
- """ Do list forever """
- while True:
- self._icall(self._evline, blklist[:])
- yield True
- if self.procstop:
- break
- self._ireturn()
- yield True
-
- '''
- def _prim_while(self, list1, list2):
- list = [self._intern('if')]
- for i in list1:
- list.append(i)
- list.append(list2)
- while self._icall(self._evline, list[:]):
- yield True
- self._ireturn()
- yield True
- '''
-
- def _prim_if(self, boolean, blklist):
- """ If bool, do list """
- if boolean:
- self._icall(self._evline, blklist[:])
- yield True
- self._ireturn()
- yield True
-
- def _prim_ifelse(self, boolean, list1, list2):
- """ If bool, do list1, else do list2 """
- if boolean:
- self._ijmp(self._evline, list1[:])
- yield True
- else:
- self._ijmp(self._evline, list2[:])
- yield True
-
def _prim_opar(self, val):
self.iline.pop(0)
return val
@@ -1026,49 +487,19 @@ class LogoCode:
name.nargs, name.fcn = 0, body
name.rprim = True
- def _prim_stack(self, x):
- """ Process a named stack """
- if type(convert(x, float, False)) == float:
- if int(float(x)) == x:
- x = int(x)
- if 'stack3' + str(x) not in self.stacks or\
- self.stacks['stack3' + str(x)] is None:
- raise logoerror("#nostack")
- self._icall(self._evline, self.stacks['stack3' + str(x)][:])
- yield True
- self.procstop = False
- self._ireturn()
- yield True
-
- def _prim_stack1(self):
- """ Process Stack 1 """
- if self.stacks['stack1'] is None:
- raise logoerror("#nostack")
- self._icall(self._evline, self.stacks['stack1'][:])
- yield True
- self.procstop = False
- self._ireturn()
- yield True
-
- def _prim_stack2(self):
- """ Process Stack 2 """
- if self.stacks['stack2'] is None:
- raise logoerror("#nostack")
- self._icall(self._evline, self.stacks['stack2'][:])
- yield True
- self.procstop = False
- self._ireturn()
- yield True
-
- def _prim_stopstack(self):
- """ Stop execution of a stack """
- self.procstop = True
-
- def _prim_print_heap(self):
- """ Display contents of heap """
- self.tw.showlabel('status', str(self.heap) + ' ')
+ def prim_clear(self):
+ """ Clear screen """
+ if self.tw.gst_available:
+ from tagplay import stop_media
+ # stop_media(self) # TODO: gplay variable
+ self.tw.canvas.clearscreen()
+ self.tw.lc.scale = DEFAULT_SCALE
+ self.tw.lc.hidden_turtle = None
+ self.tw.lc.start_time = time()
+ for name in value_blocks:
+ self.tw.lc.update_label_value(name)
- def _int(self, n):
+ def int(self, n):
""" Raise an error if n doesn't convert to int. """
if type(n) == int:
return n
@@ -1080,96 +511,20 @@ class LogoCode:
raise logoerror("%s %s %s %s" \
% (self.cfun.name, _("doesn't like"), str(n), _("as input")))
- def _box(self, x):
- """ Retrieve value from named box """
- if type(convert(x, float, False)) == float:
- if int(float(x)) == x:
- x = int(x)
- try:
- return self.boxes['box3' + str(x)]
- except KeyError:
- raise logoerror("#emptybox")
-
- def _prim_myblock(self, x):
- """ Run Python code imported from Journal """
- if self.bindex is not None and self.bindex in self.tw.myblock:
- try:
- if len(x) == 1:
- myfunc_import(self, self.tw.myblock[self.bindex], x[0])
- else:
- myfunc_import(self, self.tw.myblock[self.bindex], x)
- except:
- raise logoerror("#syntaxerror")
-
- def _prim_print(self, n, flag):
- """ Print object n """
- if flag and (self.tw.hide or self.tw.step_time == 0):
- return
- if type(n) == str or type(n) == unicode:
- if n[0:6] == 'media_' and n[6:] != 'CAMERA':
- try:
- if self.tw.running_sugar:
- try:
- dsobject = datastore.get(n[6:])
- except:
- _logger.debug("Couldn't open %s" % (n[6:]))
- self.tw.showlabel('status', dsobject.metadata['title'])
- dsobject.destroy()
- else:
- self.tw.showlabel('status', n[6:])
- except IOError:
- self.tw.showlabel('status', n)
- else:
- self.tw.showlabel('status', n)
- elif type(n) == int:
- self.tw.showlabel('status', n)
- else:
- self.tw.showlabel('status',
- str(round_int(n)).replace('.', self.tw.decimal_point))
-
- def _prim_kbinput(self):
- """ Query keyboard """
- if len(self.tw.keypress) == 1:
- self.keyboard = ord(self.tw.keypress[0])
- else:
- try:
- self.keyboard = {'Escape': 27, 'space': 32, ' ': 32,
- 'Return': 13, \
- 'KP_Up': 2, 'KP_Down': 4, 'KP_Left': 1, \
- 'KP_Right': 3}[self.tw.keypress]
- except KeyError:
- self.keyboard = 0
- self.update_label_value('keyboard', self.keyboard)
- self.tw.keypress = ''
-
def find_value_blocks(self):
""" Find any value blocks that may need label updates """
- self.value_blocks = {}
- for name in VALUE_BLOCKS:
- self.value_blocks[name] = self.tw.block_list.get_similar_blocks(
- 'block', name)
-
- def _update_audio_mode(self):
- """ If there are sensor blocks, set the appropriate audio mode """
- for name in ['sound', 'volume', 'pitch']:
- if len(self.value_blocks[name]) > 0:
- self.tw.audiograb.set_sensor_type()
- return
- if len(self.value_blocks['resistance']) > 0:
- self.tw.audiograb.set_sensor_type(SENSOR_DC_BIAS)
- return
- elif len(self.value_blocks['voltage']) > 0:
- self.tw.audiograb.set_sensor_type(SENSOR_DC_NO_BIAS)
- return
+ self.value_blocks_to_update = {}
+ for name in value_blocks:
+ self.value_blocks_to_update[name] = \
+ self.tw.block_list.get_similar_blocks('block', name)
def update_label_value(self, name, value=None):
""" Update the label of value blocks to reflect current value """
- if self.tw.hide or not self.tw.interactive_mode or \
- not hasattr(self, 'value_blocks'):
+ if self.tw.hide or not self.tw.interactive_mode:
return
if value is None:
- for block in self.value_blocks[name]:
- block.spr.set_label(BLOCK_NAMES[name][0])
+ for block in self.value_blocks_to_update[name]:
+ block.spr.set_label(block_names[name][0])
block.resize()
elif self.update_values:
if type(value) == float:
@@ -1177,70 +532,10 @@ class LogoCode:
self.tw.decimal_point)
else:
valstring = str(value)
- for block in self.value_blocks[name]:
- block.spr.set_label(BLOCK_NAMES[name][0] + ' = ' + valstring)
+ for block in self.value_blocks_to_update[name]:
+ block.spr.set_label(block_names[name][0] + ' = ' + valstring)
block.resize()
- def _prim_set(self, name, cmd, value=None):
- """ Set a value and update the associated value blocks """
- if value is not None:
- cmd(value)
- self.update_label_value(name, value)
-
- def _prim_right(self, value):
- self.tw.canvas.right(float(value))
- self.update_label_value('heading', self.tw.canvas.heading)
-
- def _prim_move(self, cmd, value1, value2=None, pendown=True):
- if value2 is None:
- cmd(value1)
- else:
- cmd(float(value1), float(value2), pendown=pendown)
- self.update_label_value('xcor',
- self.tw.canvas.xcor / self.tw.coord_scale)
- self.update_label_value('ycor',
- self.tw.canvas.ycor / self.tw.coord_scale)
- if len(self.value_blocks['see']) > 0:
- self.see()
-
- def _prim_arc(self, cmd, value1, value2):
- cmd(float(value1), float(value2))
- self.update_label_value('xcor',
- self.tw.canvas.xcor / self.tw.coord_scale)
- self.update_label_value('ycor',
- self.tw.canvas.ycor / self.tw.coord_scale)
- self.update_label_value('heading', self.tw.canvas.heading)
- if len(self.value_blocks['see']) > 0:
- self.see()
-
- def _prim_setbox(self, name, x, val):
- """ Define value of named box """
- if x is not None:
- if type(convert(x, float, False)) == float:
- if int(float(x)) == x:
- x = int(x)
- self.boxes[name + str(x)] = val
- return
-
- self.boxes[name] = val
- self.update_label_value(name, val)
-
- def _prim_push(self, val):
- """ Push value onto FILO """
- self.heap.append(val)
- self.update_label_value('pop', val)
-
- def _prim_pop(self):
- """ Pop value off of FILO """
- if len(self.heap) == 0:
- raise logoerror("#emptyheap")
- else:
- if len(self.heap) == 1:
- self.update_label_value('pop')
- else:
- self.update_label_value('pop', self.heap[-2])
- return self.heap.pop(-1)
-
def push_file_data_to_heap(self, dsobject):
""" push contents of a data store object (assuming json encoding) """
data = data_from_file(dsobject.file_path)
@@ -1249,188 +544,59 @@ class LogoCode:
self.heap.append(val)
self.update_label_value('pop', self.heap[-1])
- def _empty_heap(self):
- """ Empty FILO """
- self.heap = []
-
- def _save_picture(self, name):
- """ Save canvas to file as PNG """
- self.tw.save_as_image(name)
-
- def _save_svg(self, name):
- """ Save SVG to file """
- self.tw.canvas.svg_close()
- self.tw.save_as_image(name, True)
-
- def _show_list(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
- for s in sarray:
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(s)
- y -= int(self.tw.canvas.textsize * self.tw.lead)
-
- def _set_scale(self, x):
- """ Set scale used by media object display """
- self.scale = x
-
- def _reskin(self, media):
- """ Reskin the turtle with an image from a file """
- scale = int(ICON_SIZE * float(self.scale) / DEFAULT_SCALE)
- if scale < 1:
- return
- self.filepath = None
- dsobject = None
- if os.path.exists(media[6:]): # is it a path?
- self.filepath = media[6:]
- elif self.tw.running_sugar: # is it a datastore object?
- try:
- dsobject = datastore.get(media[6:])
- except:
- _logger.debug("Couldn't open skin %s" % (media[6:]))
- if dsobject is not None:
- self.filepath = dsobject.file_path
- if self.filepath == None:
- self.tw.showlabel('nojournal', self.filepath)
- return
- pixbuf = None
- try:
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.filepath, scale,
- scale)
- except:
- self.tw.showlabel('nojournal', self.filepath)
- _logger.debug("Couldn't open skin %s" % (self.filepath))
- if pixbuf is not None:
- self.tw.active_turtle.set_shapes([pixbuf])
- pen_state = self.tw.active_turtle.get_pen_state()
- if pen_state:
- self.tw.canvas.setpen(False)
- self.tw.canvas.forward(0)
- if pen_state:
- self.tw.canvas.setpen(True)
-
- def _x(self):
+ def x2tx(self):
""" Convert screen coordinates to turtle coordinates """
return int(self.tw.canvas.width / 2) + int(self.tw.canvas.xcor)
- def _y(self):
+ def y2ty(self):
""" Convert screen coordinates to turtle coordinates """
return int(self.tw.canvas.height / 2) - int(self.tw.canvas.ycor)
- def _w(self):
- """ Convert screen coordinates to turtle coordinates """
+ def wpercent(self):
+ """ width as a percentage of screen coordinates """
return int((self.tw.canvas.width * self.scale) / 100.)
- def _h(self):
- """ Convert screen coordinates to turtle coordinates """
+ def hpercent(self):
+ """ height as a percentage of screen coordinates """
return int((self.tw.canvas.height * self.scale) / 100.)
- def _show(self, string, center=False):
- """ Show is the general-purpose media-rendering block. """
- if type(string) == str or type(string) == unicode:
- if string in ['media_', 'descr_', 'audio_', 'video_',
- 'media_None', 'descr_None', 'audio_None',
- 'video_None']:
- pass
- elif string[0:6] in ['media_', 'descr_', 'audio_', 'video_']:
- self.filepath = None
- self.dsobject = None
- if string[6:] == 'CAMERA':
- if self.tw.camera_available:
- self.camera.save_camera_input_to_file()
- self.camera.stop_camera_input()
- self.filepath = self.imagepath
- elif os.path.exists(string[6:]): # is it a path?
- self.filepath = string[6:]
- elif self.tw.running_sugar: # is it a datastore object?
- try:
- self.dsobject = datastore.get(string[6:])
- except:
- _logger.debug("Couldn't find dsobject %s" % (
- string[6:]))
- if self.dsobject is not None:
- self.filepath = self.dsobject.file_path
- if self.filepath == None:
- if self.dsobject is not None:
- self.tw.showlabel('nojournal',
- self.dsobject.metadata['title'])
- else:
- self.tw.showlabel('nojournal', string[6:])
- _logger.debug("Couldn't open %s" % (string[6:]))
- elif string[0:6] == 'media_':
- self._insert_image(center)
- elif string[0:6] == 'descr_':
- mimetype = None
- if self.dsobject is not None and \
- 'mime_type' in self.dsobject.metadata:
- mimetype = self.dsobject.metadata['mime_type']
- description = None
- if self.dsobject is not None and \
- 'description' in self.dsobject.metadata:
- description = self.dsobject.metadata['description']
- self._insert_desc(mimetype, description)
- elif string[0:6] == 'audio_':
- self._play_sound()
- elif string[0:6] == 'video_':
- self._play_video()
- if self.dsobject is not None:
- self.dsobject.destroy()
- else: # assume it is text to display
- x = self._x()
- y = self._y()
- if center:
- y -= self.tw.canvas.textsize
- self.tw.canvas.draw_text(string, x, y,
- int(self.tw.canvas.textsize * \
- self.scale / 100.),
- self.tw.canvas.width - x)
- elif type(string) == float or type(string) == int:
- string = round_int(string)
- x = self._x()
- y = self._y()
- if center:
- y -= self.tw.canvas.textsize
- self.tw.canvas.draw_text(string, x, y,
- int(self.tw.canvas.textsize * \
- self.scale / 100.),
- self.tw.canvas.width - x)
-
- def _insert_image(self, center=False, filepath=None):
+ def insert_image(self, center=False, filepath=None):
""" Image only (at current x, y) """
if filepath is not None:
self.filepath = filepath
pixbuf = None
- w = self._w()
- h = self._h()
+ w, h = self.wpercent(), self.hpercent()
if w < 1 or h < 1:
return
- if self.filepath is not None and self.filepath != '':
+ if self.dsobject is not None:
+ try:
+ pixbuf = get_pixbuf_from_journal(self.dsobject, w, h)
+ except:
+ debug_output("Couldn't open dsobject %s" % (self.dsobject),
+ self.tw.running_sugar)
+ if pixbuf is None and \
+ self.filepath is not None and \
+ self.filepath != '':
try:
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.filepath,
w, h)
except:
self.tw.showlabel('nojournal', self.filepath)
- _logger.debug("Couldn't open filepath %s" % (self.filepath))
- elif self.dsobject is not None:
- try:
- pixbuf = get_pixbuf_from_journal(self.dsobject, w, h)
- except:
- self.tw.showlabel('nojournal', self.dsobject)
- _logger.debug("Couldn't open dsobject %s" % (self.dsobject))
+ debug_output("Couldn't open filepath %s" % (self.filepath),
+ self.tw.running_sugar)
if pixbuf is not None:
if center:
self.tw.canvas.draw_pixbuf(pixbuf, 0, 0,
- self._x() - int(w / 2),
- self._y() - int(h / 2), w, h,
+ self.x2tx() - int(w / 2),
+ self.y2ty() - int(h / 2), w, h,
self.filepath)
else:
- self.tw.canvas.draw_pixbuf(pixbuf, 0, 0, self._x(), self._y(),
- w, h, self.filepath)
+ self.tw.canvas.draw_pixbuf(pixbuf, 0, 0, self.x2tx(),
+ self.y2ty(), w, h, self.filepath)
- def _insert_desc(self, mimetype=None, description=None):
+ def insert_desc(self, mimetype=None, description=None):
""" Description text only (at current x, y) """
- w = self._w()
+ w = self.wpercent()
if w < 1:
return
text = None
@@ -1448,378 +614,38 @@ class LogoCode:
f.close()
except IOError:
self.tw.showlabel('nojournal', self.filepath)
- _logger.debug("Couldn't open filepath %s" % \
- (self.filepath))
+ debug_output("Couldn't open %s" % (self.filepath),
+ self.tw.running_sugar)
else:
if description is not None:
text = str(description)
else:
text = self.filepath
if text is not None:
- self.tw.canvas.draw_text(text, self._x(), self._y(),
+ self.tw.canvas.draw_text(text, self.x2tx(), self.y2ty(),
self.body_height, w)
- def _media_wait(self):
+ def media_wait(self):
""" Wait for media to stop playing """
- while(media_playing(self)):
- yield True
- self._ireturn()
+ if self.tw.gst_available:
+ from tagplay import media_playing
+ while(media_playing(self)):
+ yield True
+ self.ireturn()
yield True
- def _play_sound(self):
+ def play_sound(self):
""" Sound file from Journal """
- play_audio_from_file(self, self.filepath)
+ if self.tw.gst_available:
+ from tagplay import play_audio_from_file
+ play_audio_from_file(self, self.filepath)
- def _play_video(self):
+ def play_video(self):
""" Movie file from Journal """
- w = self._w()
- h = self._h()
+ w, h = self.wpercent(), self.hpercent()
if w < 1 or h < 1:
return
- play_movie_from_file(self, self.filepath, self._x(), self._y(),
- self._w(), self._h())
-
- def see(self):
- """ Read r, g, b from the canvas and return a corresponding palette
- color """
- r, g, b, a = self.tw.canvas.get_pixel()
- color_index = self.tw.canvas.get_color_index(r, g, b)
- self.update_label_value('see', color_index)
- return color_index
-
- def _read_pixel(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()
- self.heap.append(b)
- self.heap.append(g)
- self.heap.append(r)
-
- def _read_camera(self, luminance_only=False):
- """ Read average pixel from camera and push b, g, r to the stack """
-
- if not self.tw.camera_available:
- if not luminance_only:
- self.heap.append(-1)
- self.heap.append(-1)
- self.heap.append(-1)
- return -1
-
- pixbuf = None
- array = None
- w = self._w()
- if w < 1:
- w = 1
- h = self._h()
- if h < 1:
- h = 1
-
- self._video_capture_device = None
- try:
- self._video_capture_device = open('/dev/video0', 'rw')
- except:
- _logger.debug('video capture device not available')
- if self._video_capture_device is not None:
- self._set_ag(0) # disable autogain
-
- self.camera.save_camera_input_to_file()
- self.camera.stop_camera_input()
-
- if self._video_capture_device is not None:
- self._set_ag(1) # restore autogain and close device
- self._video_capture_device.close()
- self._video_capture_device = None
-
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.imagepath, w, h)
- array = pixbuf.get_pixels()
-
- array_length = len(array) / 3
- r = 0
- g = 0
- b = 0
- i = 0
- for j in range(array_length):
- r += ord(array[i])
- i += 1
- g += ord(array[i])
- i += 1
- b += ord(array[i])
- i += 1
- if luminance_only:
- lum = int((r * 0.3 + g * 0.6 + b * 0.1) / array_length)
- self.update_label_value('luminance', lum)
- return lum
- else:
- self.heap.append(int((b / array_length)))
- self.heap.append(int((g / array_length)))
- self.heap.append(int((r / array_length)))
-
- def _set_ag(self, value):
- """ set camera autogain (0==off, 1==on) """
- self._ag_control = v4l2.v4l2_control(v4l2.V4L2_CID_AUTOGAIN)
- try:
- ioctl(self._video_capture_device, v4l2.VIDIOC_G_CTRL,
- self._ag_control)
- self._ag_control.value = value
- ioctl(self._video_capture_device, v4l2.VIDIOC_S_CTRL,
- self._ag_control)
- ioctl(self._video_capture_device, v4l2.VIDIOC_G_CTRL,
- self._ag_control)
- except:
- _logger.debug('AUTOGAIN control not available')
-
- def _get_volume(self):
- """ return mic in value """
- #TODO: Adjust gain for different HW
- buf = self.ringbuffer.read(None, self.input_step)
- if len(buf) > 0:
- volume = float(_avg(buf, abs_value=True))
- self.update_label_value('volume', volume)
- return volume
- else:
- return 0
-
- def _get_sound(self):
- """ return raw mic in value """
- buf = self.ringbuffer.read(None, self.input_step)
- if len(buf) > 0:
- sound = float(buf[0])
- self.update_label_value('sound', sound)
- return sound
- else:
- return 0
-
- def _get_pitch(self):
- """ return index of max value in fft of mic in values """
- buf = []
- for i in range(4):
- buf = append(buf, self.ringbuffer.read(None, self.input_step))
- if len(buf) > 0:
- r = []
- for j in rfft(buf):
- r.append(abs(j))
- # Convert output to Hertz
- pitch = r.index(max(r)) * 48000 / len(buf)
- self.update_label_value('pitch', pitch)
- return pitch
- else:
- return 0
-
- def _get_resistance(self):
- """ return resistance sensor value """
- buf = self.ringbuffer.read(None, self.input_step)
- if len(buf) > 0:
- # See <http://bugs.sugarlabs.org/ticket/552#comment:7>
- # TODO: test this calibration on XO 1.5
- if self.tw.hw == XO1:
- resistance = 2.718 ** ((float(_avg(buf)) * 0.000045788) + \
- 8.0531)
- else:
- avg_buf = float(_avg(buf))
- if avg_buf > 0:
- resistance = (420000000 / avg_buf) - 13500
- else:
- resistance = 420000000
- self.update_label_value('resistance', resistance)
- return resistance
- else:
- return 0
-
- def _get_voltage(self):
- """ return voltage sensor value """
- buf = self.ringbuffer.read(None, self.input_step)
- if len(buf) > 0:
- # See <http://bugs.sugarlabs.org/ticket/552#comment:7>
- voltage = float(_avg(buf)) * self.voltage_gain + self.voltage_bias
- self.update_label_value('voltage', voltage)
- return voltage
- else:
- return 0
-
- # Depreciated block methods
-
- def _show_template1x1(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._show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) \
- / self.tw.canvas.height
- self._set_scale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.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._show(media)
- if self.tw.running_sugar:
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media.replace('media_', 'descr_'))
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _show_template2x1(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._show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._set_scale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.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._show(media1)
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media2)
- y = -self.title_height
- if self.tw.running_sugar:
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media2.replace('media_', 'descr_'))
- x = -(self.tw.canvas.width / 2) + xo
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media1.replace('media_', 'descr_'))
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _show_bullets(self, sarray):
- """ title and varible number of bullets """
- xo = self.tw.calc_position('bullet')[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._show(sarray[0])
- # set body text size
- self.tw.canvas.settextsize(self.bullet_height)
- # leave some space below the title
- y -= int(self.title_height * 2 * self.tw.lead)
- for s in sarray[1:]:
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(s)
- y -= int(self.bullet_height * 2 * self.tw.lead)
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _show_template1x2(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._show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._set_scale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.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._show(media1)
- if self.tw.running_sugar:
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media1.replace('media_', 'descr_'))
- y = -self.title_height
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media2.replace('media_', 'descr_'))
- x = -(self.tw.canvas.width / 2) + xo
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media2)
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _show_template2x2(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._show(title)
- # calculate and set scale for media blocks
- myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._set_scale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.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._show(media1)
- x = 0
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media2)
- y = -self.title_height
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media4)
- x = -(self.tw.canvas.width / 2) + xo
- self.tw.canvas.setxy(x, y, pendown=False)
- self._show(media3)
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _show_template1x1a(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._show(title)
- # calculate and set scale for media blocks
- myscale = 90 * (self.tw.canvas.height - self.title_height * 2) / \
- self.tw.canvas.height
- self._set_scale(myscale)
- # set body text size
- self.tw.canvas.settextsize(self.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._show(media1)
- # restore text size
- self.tw.canvas.settextsize(save_text_size)
-
- def _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)
+ if self.tw.gst_available:
+ from tagplay import play_movie_from_file
+ play_movie_from_file(self, self.filepath, self.x2tx(), self.y2ty(),
+ w, h)
diff --git a/TurtleArt/tapalette.py b/TurtleArt/tapalette.py
new file mode 100644
index 0000000..61fcb14
--- /dev/null
+++ b/TurtleArt/tapalette.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env python
+#Copyright (c) 2011 Walter Bender
+
+#Permission is hereby granted, free of charge, to any person obtaining a copy
+#of this software and associated documentation files (the "Software"), to deal
+#in the Software without restriction, including without limitation the rights
+#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#copies of the Software, and to permit persons to whom the Software is
+#furnished to do so, subject to the following conditions:
+
+#The above copyright notice and this permission notice shall be included in
+#all copies or substantial portions of the Software.
+
+#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+#THE SOFTWARE.
+
+palette_names = []
+palette_blocks = []
+block_colors = []
+expandable_blocks = []
+block_names = {}
+block_primitives = {}
+default_values = {}
+logo_commands = {}
+logo_functions = {}
+special_names = {} # Names for blocks without names for popup help
+content_blocks = ['number', 'string', 'description', 'audio', 'video',
+ 'journal']
+value_blocks = [] # blocks whose labels are updated get added here
+special_block_colors = {}
+block_styles = {'basic-style': [],
+ 'blank-style': [],
+ 'basic-style-head': [],
+ 'basic-style-head-1arg': [],
+ 'basic-style-tail': [],
+ 'basic-style-extended': [],
+ 'basic-style-extended-vertical': [],
+ 'basic-style-1arg': [],
+ 'basic-style-2arg': [],
+ 'basic-style-3arg': [],
+ 'basic-style-var-arg': [],
+ 'bullet-style': [],
+ 'invisible': [],
+ 'box-style': [],
+ 'box-style-media': [],
+ 'number-style': [],
+ 'number-style-var-arg': [],
+ 'number-style-block': [],
+ 'number-style-porch': [],
+ 'number-style-1arg': [],
+ 'number-style-1strarg': [],
+ 'compare-style': [],
+ 'compare-porch-style': [],
+ 'boolean-style': [],
+ 'not-style': [],
+ 'flow-style': [],
+ 'flow-style-tail': [],
+ 'flow-style-1arg': [],
+ 'flow-style-boolean': [],
+ 'flow-style-while': [],
+ 'flow-style-else': [],
+ 'collapsible-top': [],
+ 'collapsible-top-no-arm': [],
+ 'collapsible-top-no-label': [],
+ 'collapsible-top-no-arm-no-label': [],
+ 'collapsible-bottom': [],
+ 'portfolio-style-2x2': [],
+ 'portfolio-style-1x1': [],
+ 'portfolio-style-2x1': [],
+ 'portfolio-style-1x2': []}
+
+from taconstants import EXPANDABLE_STYLE
+from tautils import debug_output
+
+from gettext import gettext as _
+
+help_strings = {
+ 'next': _('displays next palette'),
+ 'orientation': _("changes the orientation of the palette of blocks")
+ }
+
+
+class Palette():
+ """ a class for defining new palettes """
+
+ def __init__(self, name, colors=["#00FF00", "#00A000"], position=None):
+ self._name = name
+ self._special_name = _(name)
+ self._colors = colors
+ self._help = None
+
+ def add_palette(self, position=None):
+ if self._name is None:
+ debug_output('You must specify a name for your palette')
+ return
+
+ # Insert new palette just before the trash
+ if 'trash' in palette_names:
+ i = palette_names.index('trash')
+ else:
+ i = len(palette_names)
+
+ if position is not None and type(position) is int and position < i:
+ i = position
+
+ if self._name not in palette_names:
+ palette_names.insert(i, self._name)
+ palette_blocks.insert(i, [])
+ block_colors.insert(i, self._colors)
+ else:
+ # debug_output('Palette %s already defined' % (self._name))
+ return
+
+ # Special name entry is needed for help hover mechanism
+ special_names[self._name] = self._special_name
+ if self._help is not None:
+ help_strings[self._name] = self._help
+ else:
+ help_strings[self._name] = ''
+
+ def set_help(self, help):
+ self._help = help
+
+ def set_special_name(self, name):
+ self._special_name = name
+
+ def add_block(self, block_name, style='basic-block', label=None,
+ special_name=None, default=None, prim_name=None,
+ help_string=None, value_block=False, content_block=False,
+ logo_command=None, hidden=False, colors=None):
+ """ Add a new block to the palette """
+ block = Block(block_name)
+ block.set_style(style)
+ if label is not None:
+ block.set_label(label)
+ if special_name is not None:
+ block.set_special_name(special_name)
+ if default is not None:
+ if default == 'None':
+ block.set_default(None)
+ else:
+ block.set_default(default)
+ if prim_name is not None:
+ block.set_prim_name(prim_name)
+ if logo_command is not None:
+ block.set_logo_command(logo_command)
+ if help_string is not None:
+ block.set_help(help_string)
+ if colors is not None:
+ block.set_colors(colors)
+ block.set_value_block(value_block)
+ block.set_content_block(content_block)
+ if not hidden:
+ block.set_palette(self._name)
+ block.add_block()
+
+
+def make_palette(palette_name, colors=None, help_string=None):
+ """ Palette helper function """
+ if colors is None:
+ palette = Palette(palette_name)
+ else:
+ palette = Palette(palette_name, colors)
+ if help_string is not None:
+ palette.set_help(help_string)
+ palette.add_palette()
+ return palette
+
+
+def palette_name_to_index(palette_name):
+ ''' Find the index associated with palette_name. '''
+ if palette_name in palette_names:
+ return palette_names.index(palette_name)
+ else:
+ return None
+
+def define_logo_function(key, value):
+ ''' Add a logo function to the table. '''
+ logo_functions[key] = value
+
+class Block():
+ """ a class for defining new block primitives """
+
+ def __init__(self, name):
+ self._name = name
+ self._special_name = None
+ self._palette = None
+ self._style = None
+ self._label = None
+ self._default = None
+ self._help = None
+ self._prim_name = None
+ self._logo_command = None
+ self._value_block = False
+ self._content_block = False
+ self._colors = None
+
+ def add_block(self, position=None):
+ if self._name is None:
+ debug_output('You must specify a name for your block')
+ return
+
+ if self._style is None:
+ debug_output('You must specify a style for your block')
+ return
+ else:
+ block_styles[self._style].append(self._name)
+
+ if self._label is not None:
+ block_names[self._name] = self._label
+
+ if self._palette is not None:
+ i = palette_names.index(self._palette)
+ if position is not None and type(position) is int and \
+ position < len(palette_blocks[i]):
+ palette_blocks[i].insert(position, self._name)
+ else:
+ palette_blocks[i].append(self._name)
+ if position is not None:
+ debug_output('Ignoring position (%s)' % (str(position)))
+
+ if self._help is not None:
+ help_strings[self._name] = self._help
+ else:
+ help_strings[self._name] = ''
+
+ if self._value_block:
+ value_blocks.append(self._name)
+
+ if self._content_block:
+ content_blocks.append(self._name)
+
+ if self._prim_name is not None:
+ block_primitives[self._name] = self._prim_name
+
+ if self._logo_command is not None and self._prim_name is not None:
+ logo_commands[self._prim_name] = self._logo_command
+
+ if self._default is not None:
+ default_values[self._name] = self._default
+
+ if self._special_name is not None:
+ special_names[self._name] = self._special_name
+
+ if self._style in EXPANDABLE_STYLE:
+ expandable_blocks.append(self._name)
+
+ if self._colors is not None:
+ special_block_colors[self._name] = self._colors
+
+ def set_colors(self, colors=None):
+ self._colors = colors
+
+ def set_value_block(self, value=True):
+ self._value_block = value
+
+ def set_content_block(self, value=True):
+ self._content_block = value
+
+ def set_palette(self, palette):
+ if not palette in palette_names:
+ debug_output('Could not find palette %s' % (palette))
+ else:
+ self._palette = palette
+
+ def set_help(self, help):
+ self._help = help
+
+ def set_special_name(self, name):
+ self._special_name = name
+
+ def set_label(self, label):
+ if type(label) == type([]):
+ self._label = label[:]
+ else:
+ self._label = [label]
+
+ def set_default(self, default):
+ if type(default) == type([]):
+ self._default = default[:]
+ else:
+ self._default = [default]
+
+ def set_style(self, style):
+ if style not in block_styles:
+ debug_output('Unknown style: %s' % (style))
+ else:
+ self._style = style
+
+ def set_prim_name(self, prim_name):
+ self._prim_name = prim_name
+
+ def set_logo_command(self, logo_command):
+ self._logo_command = logo_command
diff --git a/TurtleArt/tasprite_factory.py b/TurtleArt/tasprite_factory.py
index fe9166d..c9fc4c4 100755
--- a/TurtleArt/tasprite_factory.py
+++ b/TurtleArt/tasprite_factory.py
@@ -24,7 +24,6 @@ import pygtk
pygtk.require('2.0')
import gtk
import os
-from gettext import gettext as _
from taconstants import HIT_RED, HIT_GREEN, HIDE_WHITE, SHOW_WHITE
@@ -80,6 +79,15 @@ class SVG:
self._gradient = False
self.margins = [0, 0, 0, 0]
+ """
+ The block construction methods typically start on the left side of
+ a block and proceed clockwise around the block, first constructing a
+ left-side connector ("outie"), a corner (1, -1), a slot or hat on along
+ the top, a corner (1, 1), right side connectors ("innie"), possibly a
+ "porch" to suggest an order of arguments, another corner (-1, 1),
+ a tab or tail, and the fourth corner (-1, -1).
+ """
+
def basic_block(self):
self.reset_min_max()
(x, y) = self._calculate_x_y()
@@ -334,12 +342,8 @@ class SVG:
yoffset = self._radius * 2 + 2 * self._innie_y2 + \
self._innie_spacer + self._stroke_width / 2.0 + \
self._expand_y
- if self._porch is True:
- yoffset += self._porch_y
svg = self._start_boolean(self._stroke_width / 2.0, yoffset)
yoffset = -2 * self._innie_y2 - self._innie_spacer - self._stroke_width
- if self._porch is True:
- yoffset -= self._porch_y
svg += self._rline_to(0, yoffset)
self._hide_x = self._x + self._radius / 2 + self._stroke_width
@@ -353,12 +357,13 @@ class SVG:
svg += self._do_innie()
svg += self._rline_to(0, self._expand_y)
if self._porch is True:
- svg += self._do_porch()
+ svg += self._do_porch(False)
else:
svg += self._rline_to(0, 2 * self._innie_y2 + self._innie_spacer)
svg += self._do_innie()
svg += self._rline_to(0, self._radius)
svg += self.line_to(xx, self._y)
+
svg += self._rline_to(-self._expand_x, 0)
self._show_y = self._y + self._radius / 2
@@ -369,7 +374,6 @@ class SVG:
self._scale)
self.margins[1] = int(self._stroke_width * self._scale)
self.margins[2] = int(self._stroke_width * self._scale)
- self.margins[3] = int(self._stroke_width * self._scale)
return self.header() + svg
def turtle(self, colors):
@@ -591,7 +595,7 @@ class SVG:
def set_gradient(self, flag=False, color='#FFFFFF'):
self._gradient = flag
- self._gradient_color = color
+ self._gradient_color = color
def set_innie(self, innie_array=[False]):
self._innie = innie_array
diff --git a/TurtleArt/taturtle.py b/TurtleArt/taturtle.py
index a7a3205..0ca72e4 100644
--- a/TurtleArt/taturtle.py
+++ b/TurtleArt/taturtle.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-#Copyright (c) 2010 Walter Bender
+#Copyright (c) 2010,11 Walter Bender
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
@@ -19,14 +19,15 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
-from taconstants import TURTLE_LAYER
+from random import uniform
+from math import sin, cos, pi
+from gettext import gettext as _
+
+from taconstants import TURTLE_LAYER, DEFAULT_TURTLE_COLORS
from tasprite_factory import SVG, svg_str_to_pixbuf
from tacanvas import wrap100, color_table
from sprites import Sprite
-
-import logging
-_logger = logging.getLogger('turtleart-activity')
-
+from tautils import debug_output
SHAPES = 36
@@ -59,6 +60,8 @@ class Turtles:
else:
if colors == None:
Turtle(self, k)
+ elif type(colors) in [list, tuple]:
+ Turtle(self, k, colors)
else:
Turtle(self, k, colors.split(','))
return self.dict[k]
@@ -120,11 +123,25 @@ class Turtle:
self.pen_gray = 100
self.pen_size = 5
self.pen_state = True
+ self.label_block = None
self._prep_shapes(key, turtles, turtle_colors)
+ # 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])
+ 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
+ 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)]
+ 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)
@@ -149,9 +166,16 @@ class Turtle:
self.shapes = generate_turtle_pixbufs(self.colors)
else:
if turtles is not None:
- self.colors = ['#008000', '#00A000']
+ self.colors = DEFAULT_TURTLE_COLORS
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)
+
def set_shapes(self, shapes):
""" Reskin the turtle """
n = len(shapes)
@@ -159,7 +183,8 @@ class Turtle:
self.shapes = shapes[:]
else:
if n != 1:
- _logger.debug("%d images passed to set_shapes: ignoring" % (n))
+ debug_output("%d images passed to set_shapes: ignoring" % (n),
+ self.tw.running_sugar)
images = [shapes[0]]
if self.heading == 0:
for i in range(3):
@@ -213,6 +238,8 @@ class Turtle:
""" 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
def show(self):
@@ -222,14 +249,25 @@ class Turtle:
self.hidden = False
self.move((self.x, self.y))
self.set_heading(self.heading)
+ if self.label_block is not None:
+ self.label_block.spr.move((self.x + self.label_xy[0],
+ self.y + self.label_xy[1]))
+ self.label_block.spr.set_layer(TURTLE_LAYER + 1)
def move(self, pos):
""" Move the turtle. """
self.x, self.y = int(pos[0]), int(pos[1])
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((pos[0] + self.label_xy[0],
+ pos[1] + self.label_xy[1]))
return(self.x, self.y)
+ def get_name(self):
+ ''' return turtle name (key) '''
+ return self.name
+
def get_xy(self):
""" Return the turtle's x, y coordinates. """
return(self.x, self.y)
diff --git a/TurtleArt/tautils.py b/TurtleArt/tautils.py
index c66b322..0c6fe64 100644
--- a/TurtleArt/tautils.py
+++ b/TurtleArt/tautils.py
@@ -1,5 +1,5 @@
#Copyright (c) 2007-8, Playful Invention Company.
-#Copyright (c) 2008-10, Walter Bender
+#Copyright (c) 2008-11, Walter Bender
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,8 @@ import gtk
import pickle
import subprocess
import dbus
+import os.path
+from gettext import gettext as _
try:
OLD_SUGAR_SYSTEM = False
@@ -37,17 +39,31 @@ except (ImportError, AttributeError):
from simplejson import dump as jdump
except:
OLD_SUGAR_SYSTEM = True
-
-from taconstants import STRING_OR_NUMBER_ARGS, HIDE_LAYER, CONTENT_ARGS, \
- COLLAPSIBLE, BLOCK_LAYER, CONTENT_BLOCKS, HIT_HIDE, \
- HIT_SHOW, XO1, XO15, UNKNOWN
from StringIO import StringIO
-import os.path
-from gettext import gettext as _
+
+from taconstants import HIDE_LAYER, COLLAPSIBLE, BLOCK_LAYER, HIT_HIDE, \
+ HIT_SHOW, XO1, XO15, UNKNOWN
+
import logging
_logger = logging.getLogger('turtleart-activity')
+def debug_output(message_string, running_sugar=False):
+ """ unified debugging output """
+ if running_sugar:
+ _logger.debug(message_string)
+ else:
+ print(message_string)
+
+
+def error_output(message_string, running_sugar=False):
+ """ unified debugging output """
+ if running_sugar:
+ _logger.error(message_string)
+ else:
+ print(message_string)
+
+
class pythonerror(Exception):
def __init__(self, value):
@@ -105,15 +121,22 @@ def json_load(text):
if OLD_SUGAR_SYSTEM is True:
_listdata = json.read(text)
else:
- # strip out leading and trailing whitespace, nulls, and newlines
+ # Strip out leading and trailing whitespace, nulls, and newlines
clean_text = text.lstrip()
clean_text = clean_text.replace('\12', '')
clean_text = clean_text.replace('\00', '')
- _io = StringIO(clean_text.rstrip())
+ clean_text = clean_text.rstrip()
+ # Look for missing ']'s
+ left_count = clean_text.count('[')
+ right_count = clean_text.count(']')
+ while left_count > right_count:
+ clean_text += ']'
+ right_count = clean_text.count(']')
+ _io = StringIO(clean_text)
try:
_listdata = jload(_io)
except ValueError:
- # assume that text is ascii list
+ # Assume that text is ascii list
_listdata = text.split()
for i, value in enumerate(_listdata):
_listdata[i] = convert(value, float)
@@ -147,7 +170,7 @@ def json_dump(data):
def get_load_name(suffix, load_save_folder):
""" Open a load file dialog. """
- _dialog = gtk.FileChooserDialog("Load...", None,
+ _dialog = gtk.FileChooserDialog(_('Load...'), None,
gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OPEN, gtk.RESPONSE_OK))
_dialog.set_default_response(gtk.RESPONSE_OK)
@@ -156,7 +179,7 @@ def get_load_name(suffix, load_save_folder):
def get_save_name(suffix, load_save_folder, save_file_name):
""" Open a save file dialog. """
- _dialog = gtk.FileChooserDialog("Save...", None,
+ _dialog = gtk.FileChooserDialog(_('Save...'), None,
gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_SAVE, gtk.RESPONSE_OK))
_dialog.set_default_response(gtk.RESPONSE_OK)
@@ -285,24 +308,36 @@ def get_path(activity, subpath):
"org.laptop.TurtleArtActivity", subpath))
-def image_to_base64(pixbuf, activity):
- """ Convert an image to base64 """
- _file_name = os.path.join(get_path(activity, 'instance'), 'imagetmp.png')
+def image_to_base64(pixbuf, path_name):
+ """ Convert an image to base64-encoded data """
+ file_name = os.path.join(path_name, 'imagetmp.png')
if pixbuf != None:
- pixbuf.save(_file_name, "png")
- _base64 = os.path.join(get_path(activity, 'instance'), 'base64tmp')
- _cmd = "base64 <" + _file_name + " >" + _base64
- subprocess.check_call(_cmd, shell=True)
- _file_handle = open(_base64, 'r')
- _data = _file_handle.read()
- _file_handle.close()
- return _data
+ pixbuf.save(file_name, "png")
+ base64 = os.path.join(path_name, 'base64tmp')
+ cmd = "base64 <" + file_name + " >" + base64
+ subprocess.check_call(cmd, shell=True)
+ file_handle = open(base64, 'r')
+ data = file_handle.read()
+ file_handle.close()
+ return data
+
+
+def base64_to_image(data, path_name):
+ """ Convert base64-encoded data to an image """
+ base64 = os.path.join(path_name, 'base64tmp')
+ file_handle = open(base64, 'w')
+ file_handle.write(data)
+ file_handle.close()
+ file_name = os.path.join(path_name, 'imagetmp.png')
+ cmd = "base64 -d <" + base64 + ">" + file_name
+ subprocess.check_call(cmd, shell=True)
+ return file_name
def movie_media_type(name):
""" Is it movie media? """
return name.lower().endswith(('.ogv', '.vob', '.mp4', '.wmv', '.mov',
- '.mpeg', 'ogg'))
+ '.mpeg', '.ogg', '.webm'))
def audio_media_type(name):
@@ -318,7 +353,7 @@ def image_media_type(name):
def text_media_type(name):
""" Is it text media? """
- return name.lower().endswith(('.txt', '.py', '.lg', '.rtf', '.ta'))
+ return name.lower().endswith(('.txt', '.py', '.lg', '.rtf'))
def round_int(num):
@@ -326,7 +361,6 @@ def round_int(num):
try:
float(num)
except TypeError:
- _logger.debug("error trying to convert %s to number" % (str(num)))
raise pythonerror("#syntaxerror")
if int(float(num)) == num:
@@ -613,39 +647,6 @@ def neg_arg(value):
return False
-def dock_dx_dy(block1, dock1n, block2, dock2n):
- """ Find the distance between the dock points of two blocks. """
- _dock1 = block1.docks[dock1n]
- _dock2 = block2.docks[dock2n]
- _d1type, _d1dir, _d1x, _d1y = _dock1[0:4]
- _d2type, _d2dir, _d2x, _d2y = _dock2[0:4]
- if block1 == block2:
- return (100, 100)
- if _d1dir == _d2dir:
- return (100, 100)
- if (_d2type is not 'number') or (dock2n is not 0):
- if block1.connections is not None and \
- dock1n < len(block1.connections) and \
- block1.connections[dock1n] is not None:
- return (100, 100)
- if block2.connections is not None and \
- dock2n < len(block2.connections) and \
- block2.connections[dock2n] is not None:
- return (100, 100)
- if _d1type != _d2type:
- if block1.name in STRING_OR_NUMBER_ARGS:
- if _d2type == 'number' or _d2type == 'string':
- pass
- elif block1.name in CONTENT_ARGS:
- if _d2type in CONTENT_BLOCKS:
- pass
- else:
- return (100, 100)
- (_b1x, _b1y) = block1.spr.get_xy()
- (_b2x, _b2y) = block2.spr.get_xy()
- return ((_b1x + _d1x) - (_b2x + _d2x), (_b1y + _d1y) - (_b2y + _d2y))
-
-
def journal_check(blk1, blk2, dock1, dock2):
""" Dock blocks only if arg is Journal block """
if blk1 == None or blk2 == None:
@@ -796,22 +797,29 @@ def find_blk_below(blk, name):
def get_hardware():
""" Determine whether we are using XO 1.0, 1.5, or "unknown" hardware """
- bus = dbus.SystemBus()
-
- comp_obj = bus.get_object('org.freedesktop.Hal',
- '/org/freedesktop/Hal/devices/computer')
- dev = dbus.Interface(comp_obj, 'org.freedesktop.Hal.Device')
- if dev.PropertyExists('system.hardware.vendor') and \
- dev.PropertyExists('system.hardware.version'):
- if dev.GetProperty('system.hardware.vendor') == 'OLPC':
- if dev.GetProperty('system.hardware.version') == '1.5':
- return XO15
- else:
- return XO1
+ product = _get_dmi('product_name')
+ if product is None:
+ if os.path.exists('/etc/olpc-release') or \
+ os.path.exists('/sys/power/olpc-pm'):
+ return XO1
else:
return UNKNOWN
- elif os.path.exists('/etc/olpc-release') or \
- os.path.exists('/sys/power/olpc-pm'):
+ if product != 'XO':
+ return UNKNOWN
+ version = _get_dmi('product_version')
+ if version == '1':
return XO1
+ elif version == '1.5':
+ return XO15
else:
return UNKNOWN
+
+
+def _get_dmi(node):
+ ''' The desktop management interface should be a reliable source
+ for product and version information. '''
+ path = os.path.join('/sys/class/dmi/id', node)
+ try:
+ return open(path).readline().strip()
+ except:
+ return None
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py
index ad830d9..64a32fd 100644
--- a/TurtleArt/tawindow.py
+++ b/TurtleArt/tawindow.py
@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
#Copyright (c) 2007, Playful Invention Company
-#Copyright (c) 2008-10, Walter Bender
-#Copyright (c) 2009-10 Raúl Gutiérrez Segalés
-#Copyright (C) 2010 Emiliano Pastorino <epastorino@plan.ceibal.edu.uy>
+#Copyright (c) 2008-11, Walter Bender
+#Copyright (c) 2009-11 Raúl Gutiérrez Segalés
#Copyright (c) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
#Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -27,7 +26,15 @@ import pygtk
pygtk.require('2.0')
import gtk
import gobject
-import gst
+from gettext import gettext as _
+
+try:
+ import gst
+ GST_AVAILABLE = True
+except ImportError:
+ # Turtle Art should not fail if gst is not available
+ GST_AVAILABLE = False
+
import os
import os.path
import dbus
@@ -36,7 +43,6 @@ from math import atan2, pi
DEGTOR = 2 * pi / 360
import locale
-from gettext import gettext as _
try:
from sugar.datastore import datastore
@@ -45,84 +51,74 @@ except ImportError:
pass
from taconstants import HORIZONTAL_PALETTE, VERTICAL_PALETTE, BLOCK_SCALE, \
- PALETTE_NAMES, TITLEXY, MEDIA_SHAPES, STATUS_SHAPES, \
- OVERLAY_SHAPES, TOOLBAR_SHAPES, TAB_LAYER, RETURN, \
- OVERLAY_LAYER, CATEGORY_LAYER, BLOCKS_WITH_SKIN, \
- ICON_SIZE, PALETTES, PALETTE_SCALE, BOX_STYLE_MEDIA, \
- PALETTE_WIDTH, MACROS, TOP_LAYER, BLOCK_LAYER, \
- CONTENT_BLOCKS, DEFAULTS, SPECIAL_NAMES, \
- HELP_STRINGS, CURSOR, EXPANDABLE, COLLAPSIBLE, \
- DEAD_DICTS, DEAD_KEYS, TEMPLATES, PYTHON_SKIN, \
- PALETTE_HEIGHT, STATUS_LAYER, OLD_DOCK, OLD_NAMES, \
- BOOLEAN_STYLE, BLOCK_NAMES, DEFAULT_TURTLE, \
- TURTLE_LAYER, EXPANDABLE_BLOCKS, COMPARE_STYLE, \
- BOOLEAN_STYLE, EXPANDABLE_ARGS, NUMBER_STYLE, \
- NUMBER_STYLE_PORCH, NUMBER_STYLE_BLOCK, \
- NUMBER_STYLE_VAR_ARG, CONSTANTS, XO1, XO15, UNKNOWN, \
- BASIC_STYLE_VAR_ARG
-from talogo import LogoCode, stop_logo
+ MEDIA_SHAPES, STATUS_SHAPES, OVERLAY_SHAPES, STRING_OR_NUMBER_ARGS, \
+ TOOLBAR_SHAPES, TAB_LAYER, RETURN, OVERLAY_LAYER, CATEGORY_LAYER, \
+ BLOCKS_WITH_SKIN, ICON_SIZE, PALETTE_SCALE, PALETTE_WIDTH, \
+ MACROS, TOP_LAYER, BLOCK_LAYER, OLD_NAMES, DEFAULT_TURTLE, TURTLE_LAYER, \
+ CURSOR, EXPANDABLE, COLLAPSIBLE, DEAD_DICTS, DEAD_KEYS, \
+ TEMPLATES, PYTHON_SKIN, PALETTE_HEIGHT, STATUS_LAYER, OLD_DOCK, \
+ EXPANDABLE_ARGS, XO1, XO15, UNKNOWN, TITLEXY, CONTENT_ARGS, CONSTANTS
+from tapalette import palette_names, palette_blocks, expandable_blocks, \
+ block_names, content_blocks, default_values, special_names, block_styles, \
+ help_strings
+from talogo import LogoCode
from tacanvas import TurtleGraphics
from tablock import Blocks, Block
from taturtle import Turtles, Turtle
from tautils import magnitude, get_load_name, get_save_name, data_from_file, \
- data_to_file, round_int, get_id, get_pixbuf_from_journal, \
- movie_media_type, audio_media_type, image_media_type, \
- save_picture, save_svg, calc_image_size, get_path, \
- reset_stack_arm, grow_stack_arm, find_sandwich_top, \
- find_sandwich_bottom, restore_stack, collapse_stack, \
- collapsed, collapsible, hide_button_hit, show_button_hit, \
- arithmetic_check, xy, find_block_to_run, find_top_block, \
- find_start_stack, find_group, find_blk_below, \
- dock_dx_dy, data_to_string, journal_check, chooser, \
- get_hardware
+ data_to_file, round_int, get_id, get_pixbuf_from_journal, \
+ movie_media_type, audio_media_type, image_media_type, save_picture, \
+ save_svg, calc_image_size, get_path, reset_stack_arm, grow_stack_arm, \
+ find_sandwich_top, find_sandwich_bottom, restore_stack, collapse_stack, \
+ collapsed, collapsible, hide_button_hit, show_button_hit, chooser, \
+ arithmetic_check, xy, find_block_to_run, find_top_block, journal_check, \
+ find_group, find_blk_below, data_to_string, find_start_stack, \
+ get_hardware, debug_output, error_output
from tasprite_factory import SVG, svg_str_to_pixbuf, svg_from_file
-from tagplay import stop_media
from sprites import Sprites, Sprite
-from audiograb import AudioGrab_Unknown, AudioGrab_XO1, AudioGrab_XO15
-from rfidutils import strhex2bin, strbin2dec, find_device
from dbus.mainloop.glib import DBusGMainLoop
-HAL_SERVICE = 'org.freedesktop.Hal'
-HAL_MGR_PATH = '/org/freedesktop/Hal/Manager'
-HAL_MGR_IFACE = 'org.freedesktop.Hal.Manager'
-HAL_DEV_IFACE = 'org.freedesktop.Hal.Device'
-REGEXP_SERUSB = '\/org\/freedesktop\/Hal\/devices\/usb_device['\
- 'a-z,A-Z,0-9,_]*serial_usb_[0-9]'
-
-import logging
-_logger = logging.getLogger('turtleart-activity')
+if GST_AVAILABLE:
+ from tagplay import stop_media
class TurtleArtWindow():
""" TurtleArt Window class abstraction """
timeout_tag = [0]
+ _PLUGIN_SUBPATH = 'plugins'
def __init__(self, win, path, parent=None, mycolors=None, mynick=None):
self._loaded_project = ''
- self.win = None
self._sharing = False
self.parent = parent
- self.send_event = None # method to send events over the network
+ self.send_event = None # method to send events over the network
+ self.gst_available = GST_AVAILABLE
if type(win) == gtk.DrawingArea:
self.interactive_mode = True
self.window = win
self.window.set_flags(gtk.CAN_FOCUS)
+ self.window.show_all()
if self.parent is not None:
self.parent.show_all()
self.running_sugar = True
else:
- self.window.show_all()
self.running_sugar = False
self.area = self.window.window
- self.gc = self.area.new_gc()
+ if self.area is not None:
+ self.gc = self.area.new_gc()
+ else:
+ # We lose...
+ debug_output('drawable area is None... punting')
+ exit()
self._setup_events()
elif type(win) == gtk.gdk.Pixmap:
self.interactive_mode = False
self.window = win
self.running_sugar = False
- self.gc = self.window.new_gc()
+ if self.window is not None:
+ self.gc = self.window.new_gc()
else:
- _logger.debug("bad win type %s" % (type(win)))
+ debug_output("bad win type %s" % (type(win)), False)
if self.running_sugar:
self.activity = parent
@@ -147,7 +143,10 @@ class TurtleArtWindow():
self.mouse_x = 0
self.mouse_y = 0
- locale.setlocale(locale.LC_NUMERIC, '')
+ try:
+ locale.setlocale(locale.LC_NUMERIC, '')
+ except locale.Error:
+ debug_output('unsupported locale', self.running_sugar)
self.decimal_point = locale.localeconv()['decimal_point']
if self.decimal_point == '' or self.decimal_point is None:
self.decimal_point = '.'
@@ -155,7 +154,6 @@ class TurtleArtWindow():
self.orientation = HORIZONTAL_PALETTE
self.hw = get_hardware()
- _logger.debug('running on %s hardware' % (self.hw))
if self.hw in (XO1, XO15):
self.lead = 1.0
self.scale = 0.67
@@ -163,14 +161,14 @@ class TurtleArtWindow():
self.color_mode = '565'
else:
self.color_mode = '888'
- if self.running_sugar and not self.activity.new_sugar_system:
+ if self.running_sugar and not self.activity.has_toolbarbox:
self.orientation = VERTICAL_PALETTE
else:
self.lead = 1.0
self.scale = 1.0
self.color_mode = '888' # TODO: Read visual mode from gtk image
- self.block_scale = BLOCK_SCALE
+ self.block_scale = BLOCK_SCALE[3]
self.trash_scale = 0.5
self.myblock = {}
self.python_code = None
@@ -187,6 +185,7 @@ class TurtleArtWindow():
self.media_shapes = {}
self.cartesian = False
self.polar = False
+ self.metric = False
self.overlay_shapes = {}
self.toolbar_shapes = {}
self.toolbar_offset = 0
@@ -196,7 +195,6 @@ class TurtleArtWindow():
self.palette_sprs = []
self.palettes = []
self.palette_button = []
- self.trash_index = PALETTE_NAMES.index('trash')
self.trash_stack = []
self.selected_palette = None
self.previous_palette = None
@@ -219,10 +217,10 @@ class TurtleArtWindow():
self.sprite_list = None
self.turtles = Turtles(self.sprite_list)
- if mynick is None:
+ if self.nick is None:
self.default_turtle_name = DEFAULT_TURTLE
else:
- self.default_turtle_name = mynick
+ self.default_turtle_name = self.nick
if mycolors is None:
Turtle(self.turtles, self.default_turtle_name)
else:
@@ -252,99 +250,100 @@ class TurtleArtWindow():
CONSTANTS['width'] = int(self.canvas.width / self.coord_scale)
CONSTANTS['height'] = int(self.canvas.height / self.coord_scale)
- if self.interactive_mode:
- self._setup_misc()
- self._show_toolbar_palette(0, False)
-
- # setup sound/sensor grab
- if self.hw in [XO1, XO15]:
- PALETTES[PALETTE_NAMES.index('sensor')].append('resistance')
- PALETTES[PALETTE_NAMES.index('sensor')].append('voltage')
- self.audio_started = False
-
- self.camera_available = False
- v4l2src = gst.element_factory_make('v4l2src')
- if v4l2src.props.device_name is not None:
- PALETTES[PALETTE_NAMES.index('sensor')].append('readcamera')
- PALETTES[PALETTE_NAMES.index('sensor')].append('luminance')
- PALETTES[PALETTE_NAMES.index('sensor')].append('camera')
- self.camera_available = True
+ self._icon_paths = [os.path.join(self.path, 'icons')]
+ self._plugins = []
+ self._init_plugins()
self.lc = LogoCode(self)
- self.saved_pictures = []
-
- self.block_operation = ''
- """
- The following code will initialize a USB RFID reader. Please note that
- in order to make this initialization function work, it is necessary to
- set the permission for the ttyUSB device to 0666. You can do this by
- adding a rule to /etc/udev/rules.d
-
- As root (using sudo or su), copy the following text into a new file in
- /etc/udev/rules.d/94-ttyUSB-rules
-
- KERNEL=="ttyUSB[0-9]",MODE="0666"
-
- You only have to do this once.
- """
-
- self.rfid_connected = False
- self.rfid_device = find_device()
- self.rfid_idn = ''
-
- if self.rfid_device is not None:
- _logger.info("RFID device found")
- self.rfid_connected = self.rfid_device.do_connect()
- if self.rfid_connected:
- self.rfid_device.connect("tag-read", self._tag_read_cb)
- self.rfid_device.connect("disconnected", self._disconnected_cb)
-
- loop = DBusGMainLoop()
- bus = dbus.SystemBus(mainloop=loop)
- hmgr_iface = dbus.Interface(bus.get_object(HAL_SERVICE,
- HAL_MGR_PATH), HAL_MGR_IFACE)
+ from tabasics import Palettes
+ p = Palettes(self)
+ self._setup_plugins()
- hmgr_iface.connect_to_signal('DeviceAdded', self._device_added_cb)
+ if self.interactive_mode:
+ self._setup_misc()
+ self.show_toolbar_palette(0, False)
- PALETTES[PALETTE_NAMES.index('sensor')].append('rfid')
+ self.saved_pictures = []
+ self.block_operation = ''
- def _device_added_cb(self, path):
- """
- Called from hal connection when a new device is plugged.
- """
- if not self.rfid_connected:
- self.rfid_device = find_device()
- _logger.debug("DEVICE_ADDED: %s"%self.rfid_device)
- if self.rfid_device is not None:
- _logger.debug("DEVICE_ADDED: RFID device is not None!")
- self.rfid_connected = self._device.do_connect()
- if self.rfid_connected:
- _logger.debug("DEVICE_ADDED: Connected!")
- self.rfid_device.connect("tag-read", self._tag_read_cb)
- self.rfid_device.connect("disconnected", self._disconnected_cb)
-
- def _disconnected_cb(self, device, text):
- """
- Called when the device is disconnected.
- """
- self.rfid_connected = False
- self.rfid_device = None
+ def _get_plugin_home(self):
+ """ Look in the execution directory """
+ path = os.path.join(self.path, self._PLUGIN_SUBPATH)
+ if os.path.exists(path):
+ return path
+ else:
+ return None
- def _tag_read_cb(self, device, tagid):
- """
- Callback for "tag-read" signal. Receives the read tag id.
- """
- idbin = strhex2bin(tagid)
- self.rfid_idn = strbin2dec(idbin[26:64])
- while self.rfid_idn.__len__() < 9:
- self.rfid_idn = '0' + self.rfid_idn
- print tagid, idbin, self.rfid_idn
-
- def new_buffer(self, buf):
- """ Append a new buffer to the ringbuffer """
- self.lc.ringbuffer.append(buf)
- return True
+ def _get_plugins_from_plugins_dir(self, path):
+ """ Look for plugin files in plugin dir. """
+ plugin_files = []
+ if path is not None:
+ candidates = os.listdir(path)
+ for dirname in candidates:
+ if os.path.exists(
+ os.path.join(path, dirname, dirname + '.py')):
+ plugin_files.append(dirname)
+ return plugin_files
+
+ def _init_plugins(self):
+ """ Try importing plugin files from the plugin dir. """
+ for plugin_dir in self._get_plugins_from_plugins_dir(
+ self._get_plugin_home()):
+ plugin_class = plugin_dir.capitalize()
+ f = "def f(self): from plugins.%s.%s import %s; return %s(self)" \
+ % (plugin_dir, plugin_dir, plugin_class, plugin_class)
+ plugins = {}
+ try:
+ exec f in globals(), plugins
+ self._plugins.append(plugins.values()[0](self))
+ # debug_output('successfully importing %s' % (plugin_class))
+ except ImportError:
+ debug_output('failed to import %s' % (plugin_class))
+
+ # Add the icon dir for each plugin to the icon_theme search path
+ for plugin_dir in self._get_plugins_from_plugins_dir(
+ self._get_plugin_home()):
+ self._add_plugin_icon_dir(os.path.join(self._get_plugin_home(),
+ plugin_dir))
+
+ def _add_plugin_icon_dir(self, dirname):
+ ''' If there is an icon subdir, add it to the search path. '''
+ icon_theme = gtk.icon_theme_get_default()
+ icon_path = os.path.join(dirname, 'icons')
+ if os.path.exists(icon_path):
+ icon_theme.append_search_path(icon_path)
+ self._icon_paths.append(icon_path)
+
+ def _setup_plugins(self):
+ """ Initial setup -- call just once. """
+ for plugin in self._plugins:
+ plugin.setup()
+
+ def _start_plugins(self):
+ """ Start is called everytime we execute blocks. """
+ for plugin in self._plugins:
+ plugin.start()
+
+ def _stop_plugins(self):
+ """ Stop is called whenever we stop execution. """
+ for plugin in self._plugins:
+ plugin.stop()
+
+ def background_plugins(self):
+ """ Background is called when we are pushed to the background. """
+ for plugin in self._plugins:
+ plugin.goto_background()
+
+ def foreground_plugins(self):
+ """ Foreground is called when we are return from the background. """
+ for plugin in self._plugins:
+ plugin.return_to_foreground()
+
+ def _quit_plugins(self):
+ """ Quit is called upon program exit. """
+ for plugin in self._plugins:
+ plugin.quit()
def _setup_events(self):
""" Register the events we listen to. """
@@ -361,41 +360,41 @@ class TurtleArtWindow():
def _setup_misc(self):
""" Misc. sprites for status, overlays, etc. """
# media blocks get positioned into other blocks
- for _name in MEDIA_SHAPES:
- if _name[0:7] == 'journal' and not self.running_sugar:
- file_name = 'file' + _name[7:]
+ for name in MEDIA_SHAPES:
+ if name[0:7] == 'journal' and not self.running_sugar:
+ filename = 'file' + name[7:]
else:
- file_name = _name
- self.media_shapes[_name] = svg_str_to_pixbuf(svg_from_file(
- "%s/images/%s.svg" % (self.path, file_name)))
+ filename = name
+ self.media_shapes[name] = svg_str_to_pixbuf(svg_from_file(
+ "%s/images/%s.svg" % (self.path, filename)))
- for i, _name in enumerate(STATUS_SHAPES):
- self.status_shapes[_name] = svg_str_to_pixbuf(svg_from_file(
- "%s/images/%s.svg" % (self.path, _name)))
+ for i, name in enumerate(STATUS_SHAPES):
+ self.status_shapes[name] = svg_str_to_pixbuf(svg_from_file(
+ "%s/images/%s.svg" % (self.path, name)))
self.status_spr = Sprite(self.sprite_list, 0, self.height - 200,
self.status_shapes['status'])
self.status_spr.hide()
self.status_spr.type = 'status'
- for _name in OVERLAY_SHAPES:
- self.overlay_shapes[_name] = Sprite(self.sprite_list,
+ for name in OVERLAY_SHAPES:
+ self.overlay_shapes[name] = Sprite(self.sprite_list,
int(self.width / 2 - 600),
int(self.height / 2 - 450),
svg_str_to_pixbuf(
- svg_from_file("%s/images/%s.svg" % (self.path, _name))))
- self.overlay_shapes[_name].hide()
- self.overlay_shapes[_name].type = 'overlay'
+ svg_from_file("%s/images/%s.svg" % (self.path, name))))
+ self.overlay_shapes[name].hide()
+ self.overlay_shapes[name].type = 'overlay'
if not self.running_sugar:
offset = self.width - 55 * len(TOOLBAR_SHAPES)
- for i, _name in enumerate(TOOLBAR_SHAPES):
- self.toolbar_shapes[_name] = Sprite(self.sprite_list,
- i * 55 + offset, 0,
- svg_str_to_pixbuf(
- svg_from_file("%s/icons/%s.svg" % (self.path, _name))))
- self.toolbar_shapes[_name].set_layer(TAB_LAYER)
- self.toolbar_shapes[_name].name = _name
- self.toolbar_shapes[_name].type = 'toolbar'
+ for i, name in enumerate(TOOLBAR_SHAPES):
+ self.toolbar_shapes[name] = Sprite(
+ self.sprite_list, i * 55 + offset, 0,
+ svg_str_to_pixbuf(svg_from_file(os.path.join(
+ self.path, 'icons', '%s.svg' % (name)))))
+ self.toolbar_shapes[name].set_layer(TAB_LAYER)
+ self.toolbar_shapes[name].name = name
+ self.toolbar_shapes[name].type = 'toolbar'
self.toolbar_shapes['stopiton'].hide()
def set_sharing(self, shared):
@@ -420,35 +419,17 @@ class TurtleArtWindow():
self.lc.prim_clear()
self.display_coordinates()
- def _start_audiograb(self):
- """ Start grabbing audio if there is an audio block in use """
- if len(self.block_list.get_similar_blocks('block',
- ['volume', 'sound', 'pitch', 'resistance', 'voltage'])) > 0:
- if self.audio_started:
- self.audiograb.resume_grabbing()
- else:
- if self.hw == XO15:
- self.audiograb = AudioGrab_XO15(self.new_buffer, self)
- elif self.hw == XO1:
- self.audiograb = AudioGrab_XO1(self.new_buffer, self)
- else:
- self.audiograb = AudioGrab_Unknown(self.new_buffer, self)
- self.audiograb.start_grabbing()
- self.audio_started = True
-
def run_button(self, time):
""" Run turtle! """
if self.running_sugar:
self.activity.recenter()
- if self.interactive_mode:
- self._start_audiograb()
-
# Look for a 'start' block
for blk in self.just_blocks():
if find_start_stack(blk):
self.step_time = time
- _logger.debug("running stack starting from %s" % (blk.name))
+ debug_output("running stack starting from %s" % (blk.name),
+ self.running_sugar)
self._run_stack(blk)
return
@@ -456,15 +437,15 @@ class TurtleArtWindow():
for blk in self.just_blocks():
if find_block_to_run(blk):
self.step_time = time
- _logger.debug("running stack starting from %s" % (blk.name))
+ debug_output("running stack starting from %s" % (blk.name),
+ self.running_sugar)
self._run_stack(blk)
return
def stop_button(self):
""" Stop button """
- stop_logo(self)
- if self.audio_started:
- self.audiograb.pause_grabbing()
+ self.lc.stop_logo()
+ self._stop_plugins()
def set_userdefined(self, blk=None):
""" Change icon for user-defined blocks after loading Python code. """
@@ -505,28 +486,38 @@ class TurtleArtWindow():
self.overlay_shapes['polar'].hide()
self.polar = False
+ def set_metric(self, flag):
+ """ Turn on/off metric coordinates """
+ if flag:
+ self.overlay_shapes['metric'].set_layer(OVERLAY_LAYER)
+ self.metric = True
+ else:
+ self.overlay_shapes['metric'].hide()
+ self.metric = False
+
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:
- shape = self.overlay_shapes[_name]
+ for name in OVERLAY_SHAPES:
+ shape = self.overlay_shapes[name]
showing = False
if shape in shape._sprites.list:
shape.hide()
showing = True
- self.overlay_shapes[_name] = Sprite(self.sprite_list,
+ self.overlay_shapes[name] = Sprite(self.sprite_list,
int(self.width / 2 - 600),
int(self.height / 2 - 450),
svg_str_to_pixbuf(
- svg_from_file("%s/images/%s.svg" % (self.path, _name))))
+ svg_from_file("%s/images/%s.svg" % (self.path, name))))
if showing:
- self.overlay_shapes[_name].set_layer(OVERLAY_LAYER)
+ self.overlay_shapes[name].set_layer(OVERLAY_LAYER)
else:
- self.overlay_shapes[_name].hide()
- self.overlay_shapes[_name].type = 'overlay'
+ self.overlay_shapes[name].hide()
+ self.overlay_shapes[name].type = 'overlay'
self.cartesian = False
self.polar = False
+ self.metric = False
self.canvas.width = self.width
self.canvas.height = self.height
self.canvas.move_turtle()
@@ -543,9 +534,9 @@ class TurtleArtWindow():
if blk.status != 'collapsed':
blk.spr.set_layer(BLOCK_LAYER)
self.show_palette()
- if self.activity is not None and self.activity.new_sugar_system:
+ if self.activity is not None and self.activity.has_toolbarbox:
self.activity.palette_buttons[0].set_icon(
- PALETTE_NAMES[0] + 'on')
+ palette_names[0] + 'on')
self.hide = False
if self.running_sugar:
self.activity.recenter()
@@ -568,10 +559,10 @@ class TurtleArtWindow():
def show_palette(self, n=0):
""" Show palette """
- self._show_toolbar_palette(n)
+ self.show_toolbar_palette(n)
self.palette_button[self.orientation].set_layer(TAB_LAYER)
self.palette_button[2].set_layer(TAB_LAYER)
- if self.activity is None or not self.activity.new_sugar_system:
+ if self.activity is None or not self.activity.has_toolbarbox:
self.toolbar_spr.set_layer(CATEGORY_LAYER)
self.palette = True
@@ -580,7 +571,7 @@ class TurtleArtWindow():
self._hide_toolbar_palette()
self.palette_button[self.orientation].hide()
self.palette_button[2].hide()
- if self.activity is None or not self.activity.new_sugar_system:
+ if self.activity is None or not self.activity.has_toolbarbox:
self.toolbar_spr.hide()
self.palette = False
@@ -591,7 +582,7 @@ class TurtleArtWindow():
self.hide = False
self.hideshow_button()
if self.running_sugar:
- self.activity.do_hide()
+ self.activity.do_hide_blocks()
def showblocks(self):
""" Callback from 'show blocks' block """
@@ -600,7 +591,7 @@ class TurtleArtWindow():
self.hide = True
self.hideshow_button()
if self.running_sugar:
- self.activity.do_show()
+ self.activity.do_show_blocks()
def resize_blocks(self, blocks=None):
""" Resize blocks or if blocks is None, all of the blocks """
@@ -635,65 +626,21 @@ class TurtleArtWindow():
if blk.name in BLOCKS_WITH_SKIN:
self._resize_skin(blk)
- def _show_toolbar_palette(self, n, init_only=False):
+ def show_toolbar_palette(self, n, init_only=False, regenerate=False):
""" Show the toolbar palettes, creating them on init_only """
- if (self.activity is None or not self.activity.new_sugar_system) and\
+ # If we are running the 0.86+ toolbar, the selectors are already
+ # created, as toolbar buttons. Otherwise, we need to create them.
+ if (self.activity is None or not self.activity.has_toolbarbox) and \
self.selectors == []:
- # Create the selectors
- svg = SVG()
- x, y = 50, 0
- for i, name in enumerate(PALETTE_NAMES):
- a = svg_str_to_pixbuf(svg_from_file("%s/icons/%soff.svg" % (
- self.path, name)))
- b = svg_str_to_pixbuf(svg_from_file("%s/icons/%son.svg" % (
- self.path, name)))
- self.selector_shapes.append([a, b])
- self.selectors.append(Sprite(self.sprite_list, x, y, a))
- self.selectors[i].type = 'selector'
- self.selectors[i].name = name
- self.selectors[i].set_layer(TAB_LAYER)
- w = self.selectors[i].get_dimensions()[0]
- x += int(w)
-
- # Create the toolbar background
- self.toolbar_offset = ICON_SIZE
- self.toolbar_spr = Sprite(self.sprite_list, 0, 0,
- svg_str_to_pixbuf(svg.toolbar(self.width, ICON_SIZE)))
- self.toolbar_spr.type = 'toolbar'
- self.toolbar_spr.set_layer(CATEGORY_LAYER)
+ # First, create the selector buttons
+ self._create_the_selectors()
+ # Create the empty palettes that we'll then populate with prototypes.
if self.palette_sprs == []:
- # Create the empty palettes
- if len(self.palettes) == 0:
- for i in range(len(PALETTES)):
- self.palettes.append([])
-
- # Create empty palette backgrounds
- for i in PALETTE_NAMES:
- self.palette_sprs.append([None, None])
-
- # Create the palette orientation button
- self.palette_button.append(Sprite(self.sprite_list, 0,
- self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
- "%s/images/palettehorizontal.svg" % (self.path)))))
- self.palette_button.append(Sprite(self.sprite_list, 0,
- self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
- "%s/images/palettevertical.svg" % (self.path)))))
- self.palette_button[0].name = _('orientation')
- self.palette_button[1].name = _('orientation')
- self.palette_button[0].type = 'palette'
- self.palette_button[1].type = 'palette'
- self.palette_button[self.orientation].set_layer(TAB_LAYER)
- self.palette_button[1 - self.orientation].hide()
-
- # Create the palette next button
- self.palette_button.append(Sprite(self.sprite_list, 16,
- self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
- "%s/images/palettenext.svg" % (self.path)))))
- self.palette_button[2].name = _('next')
- self.palette_button[2].type = 'palette'
- self.palette_button[2].set_layer(TAB_LAYER)
+ self._create_the_empty_palettes()
+ # At initialization of the program, we don't actually populate
+ # the palettes.
if init_only:
return
@@ -703,27 +650,121 @@ class TurtleArtWindow():
self.selected_palette = n
self.previous_palette = self.selected_palette
- if self.activity is None or not self.activity.new_sugar_system:
+ # Make sure all of the selectors are visible. (We don't need to do
+ # this for 0.86+ toolbars since the selectors are toolbar buttons.)
+ if self.activity is None or not self.activity.has_toolbarbox:
self.selected_selector = self.selectors[n]
- # Make sure all of the selectors are visible.
self.selectors[n].set_shape(self.selector_shapes[n][1])
- for i in range(len(PALETTES)):
+ for i in range(len(palette_blocks)):
self.selectors[i].set_layer(TAB_LAYER)
# Show the palette with the current orientation.
if self.palette_sprs[n][self.orientation] is not None:
self.palette_sprs[n][self.orientation].set_layer(CATEGORY_LAYER)
+ # Create 'proto' blocks for each palette entry
+ self._create_proto_blocks(n, regenerate=regenerate)
+
+ self._layout_palette(n, regenerate=regenerate)
+ for blk in self.palettes[n]:
+ blk.spr.set_layer(TAB_LAYER)
+ if n == palette_names.index('trash'):
+ for blk in self.trash_stack:
+ for gblk in find_group(blk):
+ if gblk.status != 'collapsed':
+ gblk.spr.set_layer(TAB_LAYER)
+
+ def _create_the_selectors(self):
+ ''' Create the palette selector buttons. '''
+ svg = SVG()
+ x, y = 50, 0 # positioned at the left, top
+ for i, name in enumerate(palette_names):
+ for path in self._icon_paths:
+ if os.path.exists(os.path.join(path, '%soff.svg' % (name))):
+ icon_pathname = os.path.join(path, '%soff.svg' % (name))
+ break
+ if icon_pathname is not None:
+ off_shape = svg_str_to_pixbuf(svg_from_file(icon_pathname))
+ else:
+ off_shape = svg_str_to_pixbuf(svg_from_file(os.path.join(
+ self._icon_paths[0], 'extrasoff.svg')))
+ error_output('Unable to open %soff.svg' % (name),
+ self.running_sugar)
+ for path in self._icon_paths:
+ if os.path.exists(os.path.join(path, '%son.svg' % (name))):
+ icon_pathname = os.path.join(path, '%son.svg' % (name))
+ break
+ if icon_pathname is not None:
+ on_shape = svg_str_to_pixbuf(svg_from_file(icon_pathname))
+ else:
+ on_shape = svg_str_to_pixbuf(svg_from_file(os.path.join(
+ self._icon_paths[0], 'extrason.svg')))
+ error_output('Unable to open %son.svg' % (name),
+ self.running_sugar)
+
+ self.selector_shapes.append([off_shape, on_shape])
+ self.selectors.append(Sprite(self.sprite_list, x, y, off_shape))
+ self.selectors[i].type = 'selector'
+ self.selectors[i].name = name
+ self.selectors[i].set_layer(TAB_LAYER)
+ w = self.selectors[i].get_dimensions()[0]
+ x += int(w) # running from left to right
+
+ # Create the toolbar background for the selectors
+ self.toolbar_offset = ICON_SIZE
+ self.toolbar_spr = Sprite(self.sprite_list, 0, 0,
+ svg_str_to_pixbuf(svg.toolbar(self.width, ICON_SIZE)))
+ self.toolbar_spr.type = 'toolbar'
+ self.toolbar_spr.set_layer(CATEGORY_LAYER)
+
+ def _create_the_empty_palettes(self):
+ ''' Create the empty palettes to be populated by prototype blocks. '''
+ if len(self.palettes) == 0:
+ for i in range(len(palette_blocks)):
+ self.palettes.append([])
+
+ # Create empty palette backgrounds
+ for i in palette_names:
+ self.palette_sprs.append([None, None])
+
+ # Create the palette orientation button
+ self.palette_button.append(Sprite(self.sprite_list, 0,
+ self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
+ "%s/images/palettehorizontal.svg" % (self.path)))))
+ self.palette_button.append(Sprite(self.sprite_list, 0,
+ self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
+ "%s/images/palettevertical.svg" % (self.path)))))
+ self.palette_button[0].name = _('orientation')
+ self.palette_button[1].name = _('orientation')
+ self.palette_button[0].type = 'palette'
+ self.palette_button[1].type = 'palette'
+ self.palette_button[self.orientation].set_layer(TAB_LAYER)
+ self.palette_button[1 - self.orientation].hide()
+
+ # Create the palette next button
+ self.palette_button.append(Sprite(self.sprite_list, 16,
+ self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
+ "%s/images/palettenext.svg" % (self.path)))))
+ self.palette_button[2].name = _('next')
+ self.palette_button[2].type = 'palette'
+ self.palette_button[2].set_layer(TAB_LAYER)
+
+ def _create_proto_blocks(self, n, regenerate=False):
+ ''' Create the protoblocks that will populate a palette. '''
+ if regenerate:
+ for blk in self.palettes[n]:
+ blk.type = 'trash'
+ self.palettes[n] = []
+
if self.palettes[n] == []:
- # Create 'proto' blocks for each palette entry
- for i, name in enumerate(PALETTES[n]):
+ for i, name in enumerate(palette_blocks[n]):
self.palettes[n].append(Block(self.block_list,
self.sprite_list, name, 0, 0, 'proto', [], PALETTE_SCALE))
self.palettes[n][i].spr.set_layer(TAB_LAYER)
self.palettes[n][i].unhighlight()
# Some proto blocks get a skin.
- if name in BOX_STYLE_MEDIA:
+ if name in block_styles['box-style-media']:
self._proto_skin(name + 'small', n, i)
elif name[:8] == 'template':
self._proto_skin(name[8:], n, i)
@@ -732,25 +773,16 @@ class TurtleArtWindow():
elif name in PYTHON_SKIN:
self._proto_skin('pythonsmall', n, i)
- self._layout_palette(n)
- for blk in self.palettes[n]:
- blk.spr.set_layer(TAB_LAYER)
- if n == self.trash_index:
- for blk in self.trash_stack:
- for gblk in find_group(blk):
- if gblk.status != 'collapsed':
- gblk.spr.set_layer(TAB_LAYER)
-
def _hide_toolbar_palette(self):
""" Hide the toolbar palettes """
self._hide_previous_palette()
- if self.activity is None or not self.activity.new_sugar_system:
+ if self.activity is None or not self.activity.has_toolbarbox:
# Hide the selectors
- for i in range(len(PALETTES)):
+ for i in range(len(palette_blocks)):
self.selectors[i].hide()
elif self.selected_palette is not None:
self.activity.palette_buttons[self.selected_palette].set_icon(
- PALETTE_NAMES[self.selected_palette] + 'off')
+ palette_names[self.selected_palette] + 'off')
self.selected_palette = None
self.previous_palette = None
@@ -758,119 +790,117 @@ class TurtleArtWindow():
""" Hide just the previously viewed toolbar palette """
# Hide previous palette
if self.previous_palette is not None:
- for i in range(len(PALETTES[self.previous_palette])):
- self.palettes[self.previous_palette][i].spr.hide()
- self.palette_sprs[self.previous_palette][
- self.orientation].hide()
- if self.activity is None or not self.activity.new_sugar_system:
+ for proto in self.palettes[self.previous_palette]:
+ proto.spr.hide()
+ self.palette_sprs[self.previous_palette][self.orientation].hide()
+ if self.activity is None or not self.activity.has_toolbarbox:
self.selectors[self.previous_palette].set_shape(
self.selector_shapes[self.previous_palette][0])
elif self.previous_palette is not None and \
self.previous_palette != self.selected_palette:
self.activity.palette_buttons[self.previous_palette].set_icon(
- PALETTE_NAMES[self.previous_palette] + 'off')
- if self.previous_palette == self.trash_index:
+ palette_names[self.previous_palette] + 'off')
+ if self.previous_palette == palette_names.index('trash'):
for blk in self.trash_stack:
for gblk in find_group(blk):
gblk.spr.hide()
def _horizontal_layout(self, x, y, blocks):
""" Position prototypes in a horizontal palette. """
- _max_w = 0
+ max_w = 0
for blk in blocks:
- _w, _h = self._width_and_height(blk)
- if y + _h > PALETTE_HEIGHT + self.toolbar_offset:
- x += int(_max_w + 3)
+ w, h = self._width_and_height(blk)
+ if y + h > PALETTE_HEIGHT + self.toolbar_offset:
+ x += int(max_w + 3)
y = self.toolbar_offset + 3
- _max_w = 0
- (_bx, _by) = blk.spr.get_xy()
- _dx = x - _bx
- _dy = y - _by
+ max_w = 0
+ (bx, by) = blk.spr.get_xy()
+ dx = x - bx
+ dy = y - by
for g in find_group(blk):
- g.spr.move_relative((int(_dx), int(_dy)))
- y += int(_h + 3)
- if _w > _max_w:
- _max_w = _w
- return x, y, _max_w
+ g.spr.move_relative((int(dx), int(dy)))
+ y += int(h + 3)
+ if w > max_w:
+ max_w = w
+ return x, y, max_w
def _vertical_layout(self, x, y, blocks):
""" Position prototypes in a vertical palette. """
- _row = []
- _row_w = 0
- _max_h = 0
- for _b in blocks:
- _w, _h = self._width_and_height(_b)
- if x + _w > PALETTE_WIDTH:
+ row = []
+ row_w = 0
+ max_h = 0
+ for b in blocks:
+ w, h = self._width_and_height(b)
+ if x + w > PALETTE_WIDTH:
# Recenter row.
- _dx = int((PALETTE_WIDTH - _row_w) / 2)
- for _r in _row:
- for _g in find_group(_r):
- _g.spr.move_relative((_dx, 0))
- _row = []
- _row_w = 0
+ dx = int((PALETTE_WIDTH - row_w) / 2)
+ for r in row:
+ for g in find_group(r):
+ g.spr.move_relative((dx, 0))
+ row = []
+ row_w = 0
x = 4
- y += int(_max_h + 3)
- _max_h = 0
- _row.append(_b)
- _row_w += (4 + _w)
- (_bx, _by) = _b.spr.get_xy()
- _dx = int(x - _bx)
- _dy = int(y - _by)
- for _g in find_group(_b):
- _g.spr.move_relative((_dx, _dy))
- x += int(_w + 4)
- if _h > _max_h:
- _max_h = _h
+ y += int(max_h + 3)
+ max_h = 0
+ row.append(b)
+ row_w += (4 + w)
+ (bx, by) = b.spr.get_xy()
+ dx = int(x - bx)
+ dy = int(y - by)
+ for g in find_group(b):
+ g.spr.move_relative((dx, dy))
+ x += int(w + 4)
+ if h > max_h:
+ max_h = h
# Recenter last row.
- _dx = int((PALETTE_WIDTH - _row_w) / 2)
- for _r in _row:
- for _g in find_group(_r):
- _g.spr.move_relative((_dx, 0))
- return x, y, _max_h
+ dx = int((PALETTE_WIDTH - row_w) / 2)
+ for r in row:
+ for g in find_group(r):
+ g.spr.move_relative((dx, 0))
+ return x, y, max_h
- def _layout_palette(self, n):
+ def _layout_palette(self, n, regenerate=False):
""" Layout prototypes in a palette. """
if n is not None:
if self.orientation == HORIZONTAL_PALETTE:
- _x, _y = 20, self.toolbar_offset + 5
- _x, _y, _max = self._horizontal_layout(_x, _y,
- self.palettes[n])
- if n == self.trash_index:
- _x, _y, _max = self._horizontal_layout(_x + _max, _y,
- self.trash_stack)
- _w = _x + _max + 25
- if self.palette_sprs[n][self.orientation] is None:
- svg = SVG()
- self.palette_sprs[n][self.orientation] = Sprite(
- self.sprite_list, 0, self.toolbar_offset,
- svg_str_to_pixbuf(svg.palette(_w, PALETTE_HEIGHT)))
- self.palette_sprs[n][self.orientation].type = 'category'
- if n == PALETTE_NAMES.index('trash'):
- svg = SVG()
- self.palette_sprs[n][self.orientation].set_shape(
- svg_str_to_pixbuf(svg.palette(_w, PALETTE_HEIGHT)))
- self.palette_button[2].move((_w - 20, self.toolbar_offset))
+ x, y = 20, self.toolbar_offset + 5
+ x, y, max_w = self._horizontal_layout(x, y, self.palettes[n])
+ if n == palette_names.index('trash'):
+ x, y, max_w = self._horizontal_layout(x + max_w, y,
+ self.trash_stack)
+ w = x + max_w + 25
+ self._make_palette_spr(n, 0, self.toolbar_offset,
+ w, PALETTE_HEIGHT, regenerate)
+ self.palette_button[2].move((w - 20, self.toolbar_offset))
else:
- _x, _y = 5, self.toolbar_offset + 15
- _x, _y, _max = self._vertical_layout(_x, _y, self.palettes[n])
- if n == PALETTE_NAMES.index('trash'):
- _x, _y, _max = self._vertical_layout(_x, _y + _max,
- self.trash_stack)
- _h = _y + _max + 25 - self.toolbar_offset
- if self.palette_sprs[n][self.orientation] is None:
- svg = SVG()
- self.palette_sprs[n][self.orientation] = \
- Sprite(self.sprite_list, 0, self.toolbar_offset,
- svg_str_to_pixbuf(svg.palette(PALETTE_WIDTH, _h)))
- self.palette_sprs[n][self.orientation].type = 'category'
- if n == PALETTE_NAMES.index('trash'):
- svg = SVG()
- self.palette_sprs[n][self.orientation].set_shape(
- svg_str_to_pixbuf(svg.palette(PALETTE_WIDTH, _h)))
+ x, y = 5, self.toolbar_offset + 15
+ x, y, max_h = self._vertical_layout(x, y, self.palettes[n])
+ if n == palette_names.index('trash'):
+ x, y, max_h = self._vertical_layout(x, y + max_h,
+ self.trash_stack)
+ h = y + max_h + 25 - self.toolbar_offset
+ self._make_palette_spr(n, 0, self.toolbar_offset,
+ PALETTE_WIDTH, h, regenerate)
self.palette_button[2].move((PALETTE_WIDTH - 20,
self.toolbar_offset))
self.palette_sprs[n][self.orientation].set_layer(CATEGORY_LAYER)
+ def _make_palette_spr(self, n, x, y, w, h, regenerate=False):
+ ''' Make the background for the palette. '''
+ if regenerate and not self.palette_sprs[n][self.orientation] is None:
+ self.palette_sprs[n][self.orientation].hide()
+ self.palette_sprs[n][self.orientation] = None
+ if self.palette_sprs[n][self.orientation] is None:
+ svg = SVG()
+ self.palette_sprs[n][self.orientation] = \
+ Sprite(self.sprite_list, x, y, svg_str_to_pixbuf(
+ svg.palette(w, h)))
+ self.palette_sprs[n][self.orientation].type = 'category'
+ if n == palette_names.index('trash'):
+ svg = SVG()
+ self.palette_sprs[n][self.orientation].set_shape(
+ svg_str_to_pixbuf(svg.palette(w, h)))
+
def _buttonpress_cb(self, win, event):
""" Button press """
self.window.grab_focus()
@@ -916,6 +946,10 @@ class TurtleArtWindow():
self._restore_latest_from_trash()
elif blk.name == 'empty':
self._empty_trash()
+ elif blk.name == 'trashall':
+ for b in self.just_blocks():
+ if b.type != 'trash':
+ self._put_in_trash(find_top_block(b))
elif blk.name in MACROS:
self._new_macro(blk.name, x + 20, y + 20)
else:
@@ -925,7 +959,7 @@ class TurtleArtWindow():
'block', blk.name)) > 0:
self.showlabel('dupstack')
return True
- # You cannot miz and match sensor blocks
+ # You cannot mix and match sensor blocks
elif blk.name in ['sound', 'volume', 'pitch']:
if len(self.block_list.get_similar_blocks(
'block', ['resistance', 'voltage'])) > 0:
@@ -954,6 +988,9 @@ class TurtleArtWindow():
# Next, look for a turtle
t = self.turtles.spr_to_turtle(spr)
if t is not None:
+ # If turtle is shared, ignore click
+ if self.remote_turtle(t.get_name()):
+ return True
self.selected_turtle = t
self.canvas.set_turtle(self.turtles.get_turtle_key(t))
self._turtle_pressed(x, y)
@@ -972,18 +1009,18 @@ class TurtleArtWindow():
elif spr.type == 'palette':
if spr.name == _('next'):
i = self.selected_palette + 1
- if i == len(PALETTE_NAMES):
+ if i == len(palette_names):
i = 0
if self.activity is None or \
- not self.activity.new_sugar_system:
+ not self.activity.has_toolbarbox:
self._select_category(self.selectors[i])
else:
if self.selected_palette is not None:
self.activity.palette_buttons[
self.selected_palette].set_icon(
- PALETTE_NAMES[self.selected_palette] + 'off')
+ palette_names[self.selected_palette] + 'off')
self.activity.palette_buttons[i].set_icon(
- PALETTE_NAMES[i] + 'on')
+ palette_names[i] + 'on')
self.show_palette(i)
else:
self.orientation = 1 - self.orientation
@@ -1018,7 +1055,7 @@ class TurtleArtWindow():
self.lc.trace = 0
self.run_button(0)
elif spr.name == 'run-slowoff':
- self.lc.trace = 0
+ self.lc.trace = 1
self.run_button(3)
elif spr.name == 'debugoff':
self.lc.trace = 1
@@ -1060,8 +1097,8 @@ class TurtleArtWindow():
if gblk.name in BLOCKS_WITH_SKIN:
self._resize_skin(gblk)
- # self.show_palette(self.trash_index)
- if self.selected_palette != self.trash_index:
+ # self.show_palette(palette_names.index('trash'))
+ if self.selected_palette != palette_names.index('trash'):
for gblk in group:
gblk.spr.hide()
@@ -1113,8 +1150,8 @@ class TurtleArtWindow():
def _in_the_trash(self, x, y):
""" Is x, y over the trash can? """
"""
- if self.selected_palette == self.trash_index and \
- self.palette_sprs[self.trash_index][self.orientation].hit((x, y)):
+ if self.selected_palette == palette_names.index('trash') and \
+ self.palette_sprs[palette_names.index('trash')][self.orientation].hit((x, y)):
return True
"""
if self.selected_palette is not None and \
@@ -1146,14 +1183,18 @@ class TurtleArtWindow():
self.selected_blk.unhighlight()
self.selected_blk = None
- def _new_block(self, name, x, y):
+ def _new_block(self, name, x, y, defaults=None):
""" Make a new block. """
- if name in CONTENT_BLOCKS:
- newblk = Block(self.block_list, self.sprite_list, name, x - 20,
- y - 20, 'block', DEFAULTS[name], self.block_scale)
+ x_pos = x - 20
+ y_pos = y - 20
+ if name in content_blocks:
+ if defaults == None:
+ defaults = default_values[name]
+ newblk = Block(self.block_list, self.sprite_list, name, x_pos,
+ y_pos, 'block', defaults, self.block_scale)
else:
- newblk = Block(self.block_list, self.sprite_list, name, x - 20,
- y - 20, 'block', [], self.block_scale)
+ newblk = Block(self.block_list, self.sprite_list, name, x_pos,
+ y_pos, 'block', [], self.block_scale)
# Add a 'skin' to some blocks
if name in PYTHON_SKIN:
@@ -1161,15 +1202,17 @@ class TurtleArtWindow():
self._block_skin('pythonon', newblk)
else:
self._block_skin('pythonoff', newblk)
- elif name in BOX_STYLE_MEDIA:
+ elif name in block_styles['box-style-media']:
self._block_skin(name + 'off', newblk)
newspr = newblk.spr
newspr.set_layer(TOP_LAYER)
self.drag_pos = 20, 20
newblk.connections = [None] * len(newblk.docks)
- if newblk.name in DEFAULTS:
- for i, argvalue in enumerate(DEFAULTS[newblk.name]):
+ if newblk.name in default_values:
+ if defaults == None:
+ defaults = default_values[newblk.name]
+ for i, argvalue in enumerate(defaults):
# skip the first dock position since it is always a connector
dock = newblk.docks[i + 1]
argname = dock[0]
@@ -1186,7 +1229,7 @@ class TurtleArtWindow():
argname = argvalue
(sx, sy) = newspr.get_xy()
if argname is not None:
- if argname in CONTENT_BLOCKS:
+ if argname in content_blocks:
argblk = Block(self.block_list, self.sprite_list,
argname, 0, 0, 'block', [argvalue],
self.block_scale)
@@ -1218,8 +1261,7 @@ class TurtleArtWindow():
def process_data(self, block_data, offset=0):
""" Process block_data (from a macro, a file, or the clipboard). """
- if offset != 0:
- _logger.debug("offset is %d" % (offset))
+
# Create the blocks (or turtle).
blocks = []
for blk in block_data:
@@ -1238,7 +1280,8 @@ class TurtleArtWindow():
else:
cons.append(blocks[c])
else:
- _logger.debug("connection error %s" % (str(block_data[i])))
+ debug_output("connection error %s" % (str(block_data[i])),
+ self.running_sugar)
cons.append(None)
elif blocks[i].connections == 'check':
# Convert old-style boolean and arithmetic blocks
@@ -1249,7 +1292,7 @@ class TurtleArtWindow():
else:
cons.append(blocks[c])
# If the boolean op was connected, readjust the plumbing.
- if blocks[i].name in BOOLEAN_STYLE:
+ if blocks[i].name in block_styles['boolean-style']:
if block_data[i][4][0] is not None:
c = block_data[i][4][0]
cons[0] = blocks[block_data[c][4][0]]
@@ -1262,7 +1305,8 @@ class TurtleArtWindow():
blocks[c].connections[3] = None
else:
# Connection was to a block we haven't seen yet.
- _logger.debug("Warning: dock to the future")
+ debug_output("Warning: dock to the future",
+ self.running_sugar)
else:
if block_data[i][4][0] is not None:
c = block_data[i][4][0]
@@ -1276,10 +1320,12 @@ class TurtleArtWindow():
blocks[c].connections[1] = None
else:
# Connection was to a block we haven't seen yet.
- _logger.debug("Warning: dock to the future")
+ debug_output("Warning: dock to the future",
+ self.running_sugar)
else:
- _logger.debug("Warning: unknown connection state %s" % \
- (str(blocks[i].connections)))
+ debug_output("Warning: unknown connection state %s" % \
+ (str(blocks[i].connections)),
+ self.running_sugar)
blocks[i].connections = cons[:]
# Block sizes and shapes may have changed.
@@ -1310,7 +1356,7 @@ class TurtleArtWindow():
return
(sx, sy) = blk.spr.get_xy()
for i, c in enumerate(blk.connections):
- if i > 0 and c is not None:
+ if i > 0 and c is not None and i < len(blk.docks):
bdock = blk.docks[i]
for j in range(len(c.docks)):
if j < len(c.connections) and c.connections[j] == blk:
@@ -1322,8 +1368,8 @@ class TurtleArtWindow():
def _turtle_pressed(self, x, y):
(tx, ty) = self.selected_turtle.get_xy()
- w = self.active_turtle.spr.rect.width / 2
- h = self.active_turtle.spr.rect.height / 2
+ 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
@@ -1349,17 +1395,29 @@ class TurtleArtWindow():
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())
if dtype == 'move':
- dx = x - dragx - sx
- dy = y - dragy - sy
+ dx = x - dragx - sx + self.selected_turtle.spr.rect.width / 2
+ dy = y - dragy - sy + self.selected_turtle.spr.rect.width / 2
self.selected_turtle.spr.set_layer(TOP_LAYER)
- self.selected_turtle.move((sx + dx, sy + dy))
+ 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)
+ self.canvas.setpen(True)
+ else:
+ self.canvas.setxy(tx, ty)
else:
- dx = x - sx - self.active_turtle.spr.rect.width / 2
- dy = y - sy - self.active_turtle.spr.rect.height / 2
+ 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)
self.lc.update_label_value('heading', self.canvas.heading)
+ if self.sharing(): # share turtle rotation
+ self.send_event("r|%s" % (
+ data_to_string([self.selected_turtle.get_name(),
+ round_int(self.canvas.heading)])))
# If we are hoving, show popup help.
elif self.drag_group is None:
@@ -1468,27 +1526,27 @@ class TurtleArtWindow():
def _do_show_popup(self, block_name):
""" Fetch the help text and display it. """
- if block_name in SPECIAL_NAMES:
- block_name_s = SPECIAL_NAMES[block_name]
- elif block_name in BLOCK_NAMES:
- block_name_s = BLOCK_NAMES[block_name][0]
+ if block_name in special_names:
+ special_block_name = special_names[block_name]
+ elif block_name in block_names:
+ special_block_name = block_names[block_name][0]
elif block_name in TOOLBAR_SHAPES:
- block_name_s = ''
+ special_block_name = ''
else:
- block_name_s = _(block_name)
- if block_name in HELP_STRINGS:
- if block_name_s == '':
- label = HELP_STRINGS[block_name]
+ special_block_name = _(block_name)
+ if block_name in help_strings:
+ if special_block_name == '':
+ label = help_strings[block_name]
else:
- label = block_name_s + ": " + HELP_STRINGS[block_name]
+ label = special_block_name + ": " + help_strings[block_name]
else:
- label = block_name_s
+ label = special_block_name
if self.running_sugar:
self.activity.hover_help_label.set_text(label)
self.activity.hover_help_label.show()
else:
if self.interactive_mode:
- self.win.set_title(_("Turtle Art") + " — " + label)
+ self.parent.set_title(_("Turtle Art") + " — " + label)
return 0
def _buttonrelease_cb(self, win, event):
@@ -1514,14 +1572,15 @@ class TurtleArtWindow():
else:
self.selected_turtle.hide()
self.turtles.remove_from_dict(k)
+ self.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.selected_turtle = None
- self.active_turtle = self.turtles.get_turtle(
- self.default_turtle_name)
+ if self.active_turtle is None:
+ self.canvas.set_turtle(self.default_turtle_name)
return
# If we don't have a group of blocks, then there is nothing to do.
@@ -1557,6 +1616,30 @@ class TurtleArtWindow():
if self.block_operation == 'click':
self._click_block(x, y)
+ def remote_turtle(self, name):
+ ''' Is this a remote turtle? '''
+ if name == self.nick:
+ return False
+ if hasattr(self, 'remote_turtle_dictionary') and \
+ name in self.remote_turtle_dictionary:
+ return True
+ return False
+
+ def label_remote_turtle(self, name, colors=['#A0A0A0', '#C0C0C0']):
+ ''' Add a label to remote turtles '''
+ turtle = self.turtles.get_turtle(name)
+ if turtle is not None:
+ turtle.label_block = Block(self.block_list,
+ self.sprite_list, 'turtle-label', 0, 0,
+ 'label', [], 1.0 / self.scale,
+ colors)
+ turtle.label_block.spr.set_label_attributes(6.0 / self.scale)
+ if len(name) > 6:
+ turtle.label_block.spr.set_label(name[0:4] + '…')
+ else:
+ turtle.label_block.spr.set_label(name)
+ turtle.show()
+
def _move_turtle(self, x, y):
""" Move the selected turtle to (x, y). """
(cx, cy) = self.canvas.canvas.get_xy()
@@ -1570,8 +1653,6 @@ class TurtleArtWindow():
self.canvas.xcor / self.coord_scale)
self.lc.update_label_value('ycor',
self.canvas.ycor / self.coord_scale)
- if len(self.lc.value_blocks['see']) > 0:
- self.lc.see()
def _click_block(self, x, y):
""" Click block: lots of special cases to handle... """
@@ -1584,7 +1665,9 @@ class TurtleArtWindow():
self.saved_string = blk.spr.labels[0]
blk.spr.labels[0] += CURSOR
- elif blk.name in BOX_STYLE_MEDIA and blk.name != 'camera':
+ elif blk.name in block_styles['box-style-media'] and \
+ blk.name != 'camera':
+ # TODO: isolate reference to camera
self._import_from_journal(self.selected_blk)
if blk.name == 'journal' and self.running_sugar:
self._load_description_block(blk)
@@ -1597,7 +1680,8 @@ class TurtleArtWindow():
dx = 20
blk.expand_in_x(dx)
else:
- dx = 0
+ self._run_stack(blk)
+ return
for gblk in group:
if gblk != blk:
gblk.spr.move_relative((dx * blk.scale, 0))
@@ -1610,13 +1694,14 @@ class TurtleArtWindow():
dy = 20
blk.expand_in_y(dy)
else:
- dy = 0
+ self._run_stack(blk)
+ return
for gblk in group:
if gblk != blk:
gblk.spr.move_relative((0, dy * blk.scale))
grow_stack_arm(find_sandwich_top(blk))
- elif blk.name in EXPANDABLE_BLOCKS:
+ elif blk.name in expandable_blocks:
# Connection may be lost during expansion, so store it...
blk0 = blk.connections[0]
if blk0 is not None:
@@ -1628,11 +1713,10 @@ class TurtleArtWindow():
dy = 20
blk.expand_in_y(dy)
else:
- self._start_audiograb()
self._run_stack(blk)
return
- if blk.name in BOOLEAN_STYLE:
+ if blk.name in block_styles['boolean-style']:
self._expand_boolean(blk, blk.connections[1], dy)
else:
self._expand_expandable(blk, blk.connections[1], dy)
@@ -1664,17 +1748,20 @@ class TurtleArtWindow():
dy = blk.add_arg()
blk.primitive = 'userdefined2'
blk.name = 'userdefined2args'
+ self._resize_skin(blk)
elif blk.name == 'userdefined2args':
dy = blk.add_arg(False)
blk.primitive = 'userdefined3'
blk.name = 'userdefined3args'
+ self._resize_skin(blk)
else:
dy = blk.add_arg()
for gblk in group:
gblk.spr.move_relative((0, dy))
blk.connections.append(blk.connections[n - 1])
argname = blk.docks[n - 1][0]
- argvalue = DEFAULTS[blk.name][len(DEFAULTS[blk.name]) - 1]
+ argvalue = default_values[blk.name][len(
+ default_values[blk.name]) - 1]
argblk = Block(self.block_list, self.sprite_list, argname,
0, 0, 'block', [argvalue], self.block_scale)
argdock = argblk.docks[0]
@@ -1685,28 +1772,26 @@ class TurtleArtWindow():
argblk.spr.set_layer(TOP_LAYER)
argblk.connections = [blk, None]
blk.connections[n - 1] = argblk
- if blk.name in NUMBER_STYLE_VAR_ARG:
+ if blk.name in block_styles['number-style-var-arg']:
self._cascade_expandable(blk)
grow_stack_arm(find_sandwich_top(blk))
elif blk.name in PYTHON_SKIN:
self._import_py()
else:
- self._start_audiograb()
self._run_stack(blk)
- elif blk.name in ['sandwichtop_no_arm_no_label',
+ elif blk.name in ['sandwichtop_no_arm_no_label',
'sandwichtop_no_arm']:
restore_stack(blk)
elif blk.name in COLLAPSIBLE:
top = find_sandwich_top(blk)
if collapsed(blk):
- restore_stack(top) # depreciated (bottom block is invisible)
+ restore_stack(top) # deprecated (bottom block is invisible)
elif top is not None:
collapse_stack(top)
else:
- self._start_audiograb()
self._run_stack(blk)
def _expand_boolean(self, blk, blk2, dy):
@@ -1726,19 +1811,27 @@ class TurtleArtWindow():
for gblk in find_group(blk):
if gblk not in group:
gblk.spr.move_relative((0, dy * blk.scale))
- if blk.name in COMPARE_STYLE:
+ if blk.name in block_styles['compare-style']:
for gblk in find_group(blk):
gblk.spr.move_relative((0, -dy * blk.scale))
+ def _number_style(self, name):
+ if name in block_styles['number-style']:
+ return True
+ if name in block_styles['number-style-porch']:
+ return True
+ if name in block_styles['number-style-block']:
+ return True
+ if name in block_styles['number-style-var-arg']:
+ return True
+ return False
+
def _cascade_expandable(self, blk):
""" If expanding/shrinking a block, cascade. """
- while blk.name in NUMBER_STYLE or \
- blk.name in NUMBER_STYLE_PORCH or \
- blk.name in NUMBER_STYLE_BLOCK or \
- blk.name in NUMBER_STYLE_VAR_ARG:
+ while self._number_style(blk.name):
if blk.connections[0] is None:
break
- if blk.connections[0].name in EXPANDABLE_BLOCKS:
+ if blk.connections[0].name in expandable_blocks:
if blk.connections[0].connections.index(blk) != 1:
break
blk = blk.connections[0]
@@ -1755,7 +1848,7 @@ class TurtleArtWindow():
for gblk in find_group(blk):
if gblk not in group:
gblk.spr.move_relative((0, dy * blk.scale))
- if blk.name in COMPARE_STYLE:
+ if blk.name in block_styles['compare-style']:
for gblk in find_group(blk):
gblk.spr.move_relative((0, -dy * blk.scale))
else:
@@ -1790,7 +1883,8 @@ class TurtleArtWindow():
""" Run a stack of blocks. """
if blk is None:
return
- self.lc.ag = None
+ self.lc.find_value_blocks() # Are there blocks to update?
+ self._start_plugins() # Let the plugins know we are running.
top = find_top_block(blk)
self.lc.run_blocks(top, self.just_blocks(), True)
if self.interactive_mode:
@@ -1848,17 +1942,18 @@ class TurtleArtWindow():
selected_block.connections[best_selected_block_dockn] = \
best_destination
- if best_destination.name in BOOLEAN_STYLE:
+ if best_destination.name in block_styles['boolean-style']:
if best_destination_dockn == 2 and \
- selected_block.name in COMPARE_STYLE:
+ selected_block.name in block_styles['compare-style']:
dy = selected_block.ey - best_destination.ey
best_destination.expand_in_y(dy)
self._expand_boolean(best_destination, selected_block, dy)
- elif best_destination.name in EXPANDABLE_BLOCKS and \
+ elif best_destination.name in expandable_blocks and \
best_destination_dockn == 1:
dy = 0
- if (selected_block.name in EXPANDABLE_BLOCKS or
- selected_block.name in NUMBER_STYLE_VAR_ARG):
+ if (selected_block.name in expandable_blocks or
+ selected_block.name in block_styles[
+ 'number-style-var-arg']):
if selected_block.name == 'myfunc2arg':
dy = 40 + selected_block.ey - best_destination.ey
elif selected_block.name == 'myfunc3arg':
@@ -1877,6 +1972,8 @@ class TurtleArtWindow():
def _disconnect(self, blk):
""" Disconnect block from stack above it. """
+ if blk is None:
+ return
if blk.connections[0] is None:
return
if collapsed(blk):
@@ -1886,12 +1983,12 @@ class TurtleArtWindow():
c = blk2.connections.index(blk)
blk2.connections[c] = None
- if blk2.name in BOOLEAN_STYLE:
+ if blk2.name in block_styles['boolean-style']:
if c == 2 and blk2.ey > 0:
dy = -blk2.ey
blk2.expand_in_y(dy)
self._expand_boolean(blk2, blk, dy)
- elif blk2.name in EXPANDABLE_BLOCKS and c == 1:
+ elif blk2.name in expandable_blocks and c == 1:
if blk2.ey > 0:
dy = blk2.reset_y()
if dy != 0:
@@ -1976,7 +2073,6 @@ class TurtleArtWindow():
""" Keyboard """
keyname = gtk.gdk.keyval_name(event.keyval)
keyunicode = gtk.gdk.keyval_to_unicode(event.keyval)
-
if event.get_state() & gtk.gdk.MOD1_MASK:
alt_mask = True
alt_flag = 'T'
@@ -1996,9 +2092,9 @@ class TurtleArtWindow():
if keyname == "p":
self.hideshow_button()
elif keyname == 'q':
- if self.audio_started:
- self.audiograb.stop_grabbing()
- stop_media(self.lc)
+ self._plugins_quit()
+ if self.gst_available:
+ stop_media(self.lc)
exit()
elif keyname == 'g':
self._align_to_grid()
@@ -2077,7 +2173,8 @@ class TurtleArtWindow():
oldleft, oldright = \
self.selected_blk.spr.labels[0].split(CURSOR)
except ValueError:
- _logger.debug("[%s]" % self.selected_blk.spr.labels[0])
+ debug_output("[%s]" % self.selected_blk.spr.labels[0],
+ self.running_sugar)
oldleft = self.selected_blk.spr.labels[0]
oldright = ''
else:
@@ -2286,7 +2383,8 @@ class TurtleArtWindow():
f.close()
id = fname
except IOError:
- _logger.error("Unable to read Python code from %s" % (fname))
+ error_output("Unable to read Python code from %s" % (fname),
+ self.running_sugar)
return id
# if we are running Sugar, copy the file into the Journal
@@ -2302,7 +2400,8 @@ class TurtleArtWindow():
datastore.write(dsobject)
id = dsobject.object_id
except IOError:
- _logger.error("Error copying %s to the datastore" % (fname))
+ error_output("Error copying %s to the datastore" % (fname),
+ self.running_sugar)
id = None
dsobject.destroy()
@@ -2327,12 +2426,14 @@ class TurtleArtWindow():
""" Read the Python code from the Journal object """
self.python_code = None
try:
- _logger.debug("opening %s " % dsobject.file_path)
+ debug_output("opening %s " % dsobject.file_path,
+ self.running_sugar)
file_handle = open(dsobject.file_path, "r")
self.python_code = file_handle.read()
file_handle.close()
except IOError:
- _logger.debug("couldn't open %s" % dsobject.file_path)
+ debug_output("couldn't open %s" % dsobject.file_path,
+ self.running_sugar)
if blk is None:
blk = self.selected_blk
if blk is not None:
@@ -2356,7 +2457,7 @@ class TurtleArtWindow():
def new_project(self):
""" Start a new project """
- stop_logo(self)
+ self.lc.stop_logo()
self._loaded_project = ""
# Put current project in the trash.
while len(self.just_blocks()) > 0:
@@ -2377,8 +2478,9 @@ class TurtleArtWindow():
saved_project_data = f.read()
f.close()
except:
- _logger.debug("problem loading saved project data from %s" % \
- (self._loaded_project))
+ debug_output("problem loading saved project data from %s" % \
+ (self._loaded_project),
+ self.running_sugar)
saved_project_data = ""
current_project_data = data_to_string(self.assemble_data_to_save())
@@ -2409,14 +2511,13 @@ class TurtleArtWindow():
if blk[1] == 'turtle':
self.load_turtle(blk)
return True
- elif type(blk[1]) == list and blk[1][0] == 'turtle':
- self.load_turtle(blk, blk[1][1])
+ elif type(blk[1]) in [list, tuple] and blk[1][0] == 'turtle':
+ if blk[1][1] == DEFAULT_TURTLE:
+ if self.nick is not None and self.nick is not '':
+ self.load_turtle(blk, self.nick)
+ else:
+ self.load_turtle(blk, blk[1][1])
return True
- elif type(blk[1]) == tuple:
- _btype, _key = blk[1]
- if _btype == 'turtle':
- self.load_turtle(blk, _key)
- return True
return False
def load_turtle(self, blk, key=1):
@@ -2438,7 +2539,7 @@ class TurtleArtWindow():
btype, value = btype
elif type(btype) == list:
btype, value = btype[0], btype[1]
- if btype in CONTENT_BLOCKS or btype in COLLAPSIBLE:
+ if btype in content_blocks or btype in COLLAPSIBLE:
if btype == 'number':
try:
values = [round_int(value)]
@@ -2467,16 +2568,17 @@ class TurtleArtWindow():
'block', values, self.block_scale)
# Some blocks get transformed.
- if btype in BASIC_STYLE_VAR_ARG and value is not None:
+ if btype in block_styles['basic-style-var-arg'] and value is not None:
# Is there code stored in this userdefined block?
- if value > 0: # catch depreciated format (#2501)
+ if value > 0: # catch deprecated format (#2501)
self.python_code = None
if self.running_sugar:
try:
dsobject = datastore.get(value)
- except: # Should be IOError, but dbus error is raised
+ except: # Should be IOError, but dbus error is raised
dsobject = None
- _logger.debug("couldn't get dsobject %s" % value)
+ debug_output("couldn't get dsobject %s" % value,
+ self.running_sugar)
if dsobject is not None:
self.load_python_code_from_journal(dsobject, blk)
else:
@@ -2493,9 +2595,9 @@ class TurtleArtWindow():
elif btype == 'start': # block size is saved in start block
if value is not None:
self.block_scale = value
- elif btype in EXPANDABLE or btype in EXPANDABLE_BLOCKS or \
+ elif btype in EXPANDABLE or btype in expandable_blocks or \
btype in EXPANDABLE_ARGS or btype == 'nop':
- if btype == 'vspace' or btype in EXPANDABLE_BLOCKS:
+ if btype == 'vspace' or btype in expandable_blocks:
if value is not None:
blk.expand_in_y(value)
elif btype == 'hspace' or btype == 'identity2':
@@ -2514,7 +2616,8 @@ class TurtleArtWindow():
self._block_skin('pythonon', blk)
else:
self._block_skin('pythonoff', blk)
- elif btype in BOX_STYLE_MEDIA and blk.spr is not None:
+ elif btype in block_styles['box-style-media'] and blk.spr is not None:
+ # TODO: isolate reference to camera
if len(blk.values) == 0 or blk.values[0] == 'None' or \
blk.values[0] is None or btype == 'camera':
self._block_skin(btype + 'off', blk)
@@ -2541,8 +2644,8 @@ class TurtleArtWindow():
x, y = self._calc_image_offset('', blk.spr)
blk.set_image(pixbuf, x, y)
except:
- _logger.debug("Couldn't open dsobject (%s)" % \
- (blk.values[0]))
+ debug_output("Couldn't open dsobject (%s)" % \
+ (blk.values[0]), self.running_sugar)
self._block_skin('journaloff', blk)
else:
if not movie_media_type(blk.values[0][-4:]):
@@ -2605,14 +2708,15 @@ class TurtleArtWindow():
for _i, _blk in enumerate(_blks):
_blk.id = _i
for _blk in _blks:
- if _blk.name in CONTENT_BLOCKS or _blk.name in COLLAPSIBLE:
+ if _blk.name in content_blocks or _blk.name in COLLAPSIBLE:
if len(_blk.values) > 0:
_name = (_blk.name, _blk.values[0])
else:
_name = (_blk.name)
- elif _blk.name in BASIC_STYLE_VAR_ARG and len(_blk.values) > 0:
+ elif _blk.name in block_styles['basic-style-var-arg'] and \
+ len(_blk.values) > 0:
_name = (_blk.name, _blk.values[0])
- elif _blk.name in EXPANDABLE or _blk.name in EXPANDABLE_BLOCKS or\
+ elif _blk.name in EXPANDABLE or _blk.name in expandable_blocks or\
_blk.name in EXPANDABLE_ARGS:
_ex, _ey = _blk.get_expand_x_y()
if _ex > 0:
@@ -2637,12 +2741,16 @@ class TurtleArtWindow():
_data.append((_blk.id, _name, _sx - self.canvas.cx,
_sy - self.canvas.cy, connections))
if save_turtle:
- for _turtle in iter(self.turtles.dict):
- self.canvas.set_turtle(_turtle)
- _data.append((-1, ['turtle', _turtle],
- self.canvas.xcor, self.canvas.ycor,
- self.canvas.heading, self.canvas.color,
- self.canvas.shade, self.canvas.pensize))
+ for turtle in iter(self.turtles.dict):
+ # Don't save remote turtles
+ if not self.remote_turtle(turtle):
+ # Save default turtle as 'Yertle'
+ if turtle == self.nick:
+ turtle = DEFAULT_TURTLE
+ _data.append((-1, ['turtle', turtle],
+ self.canvas.xcor, self.canvas.ycor,
+ self.canvas.heading, self.canvas.color,
+ self.canvas.shade, self.canvas.pensize))
return _data
def display_coordinates(self):
@@ -2655,13 +2763,13 @@ class TurtleArtWindow():
(_("xcor"), x, _("ycor"), y, _("heading"), h))
self.activity.coordinates_label.show()
elif self.interactive_mode:
- self.win.set_title("%s — %s: %d %s: %d %s: %d" % \
+ self.parent.set_title("%s — %s: %d %s: %d %s: %d" % \
(_("Turtle Art"), _("xcor"), x, _("ycor"), y, _("heading"), h))
def showlabel(self, shp, label=''):
""" Display a message on a status block """
if not self.interactive_mode:
- _logger.debug(label)
+ debug_output(label, self.running_sugar)
return
if shp == 'syntaxerror' and str(label) != '':
if str(label)[1:] in self.status_shapes:
@@ -2683,7 +2791,7 @@ class TurtleArtWindow():
self.status_spr.move((PALETTE_WIDTH, self.height - 200))
def calc_position(self, template):
- """ Relative placement of portfolio objects (depreciated) """
+ """ Relative placement of portfolio objects (deprecated) """
w, h, x, y, dx, dy = TEMPLATES[template]
x *= self.canvas.width
y *= self.canvas.height
@@ -2705,49 +2813,30 @@ class TurtleArtWindow():
def save_as_image(self, name="", svg=False, pixbuf=None):
""" Grab the current canvas and save it. """
+ if svg:
+ suffix = '.svg'
+ else:
+ suffix = '.png'
if not self.interactive_mode:
- save_picture(self.canvas, name[:-3] + ".png")
+ save_picture(self.canvas, name[:-3] + suffix)
return
- """
- self.color_map = self.window.get_colormap()
- new_pix = pixbuf.get_from_drawable(self.window, self.color_map,
- 0, 0, 0, 0,
- self.width, self.height)
- new_pix.save(name[:-3] + ".png", "png")
- """
-
if self.running_sugar:
- if svg:
- if len(name) == 0:
- filename = "ta.svg"
- else:
- filename = name + ".svg"
+ if len(name) == 0:
+ filename = 'ta' + suffix
else:
- if len(name) == 0:
- filename = "ta.png"
- else:
- filename = name + ".png"
+ filename = name + suffix
datapath = get_path(self.activity, 'instance')
elif len(name) == 0:
- name = "ta"
+ name = 'ta'
if self.save_folder is not None:
self.load_save_folder = self.save_folder
- if svg:
- filename, self.load_save_folder = get_save_name('.svg',
- self.load_save_folder,
- name)
- else:
- filename, self.load_save_folder = get_save_name('.png',
- self.load_save_folder,
- name)
+ filename, self.load_save_folder = get_save_name(
+ suffix, self.load_save_folder, name)
datapath = self.load_save_folder
else:
datapath = os.getcwd()
- if svg:
- filename = name + ".svg"
- else:
- filename = name + ".png"
+ filename = name + suffix
if filename is None:
return
@@ -2864,3 +2953,36 @@ class TurtleArtWindow():
w, h = self._calc_w_h('descriptionoff', blk.spr)
x, y = self._calc_image_offset('descriptionoff', blk.spr, w, h)
blk.scale_image(x, y, w, h)
+
+
+def dock_dx_dy(block1, dock1n, block2, dock2n):
+ """ Find the distance between the dock points of two blocks. """
+ _dock1 = block1.docks[dock1n]
+ _dock2 = block2.docks[dock2n]
+ _d1type, _d1dir, _d1x, _d1y = _dock1[0:4]
+ _d2type, _d2dir, _d2x, _d2y = _dock2[0:4]
+ if block1 == block2:
+ return (100, 100)
+ if _d1dir == _d2dir:
+ return (100, 100)
+ if (_d2type is not 'number') or (dock2n is not 0):
+ if block1.connections is not None and \
+ dock1n < len(block1.connections) and \
+ block1.connections[dock1n] is not None:
+ return (100, 100)
+ if block2.connections is not None and \
+ dock2n < len(block2.connections) and \
+ block2.connections[dock2n] is not None:
+ return (100, 100)
+ if _d1type != _d2type:
+ if block1.name in STRING_OR_NUMBER_ARGS:
+ if _d2type == 'number' or _d2type == 'string':
+ pass
+ elif block1.name in CONTENT_ARGS:
+ if _d2type in content_blocks:
+ pass
+ else:
+ return (100, 100)
+ (_b1x, _b1y) = block1.spr.get_xy()
+ (_b2x, _b2y) = block2.spr.get_xy()
+ return ((_b1x + _d1x) - (_b2x + _d2x), (_b1y + _d1y) - (_b2y + _d2y))
diff --git a/TurtleArt/v4l2.py b/TurtleArt/v4l2.py
deleted file mode 100644
index 9c052fd..0000000
--- a/TurtleArt/v4l2.py
+++ /dev/null
@@ -1,1914 +0,0 @@
-# Python bindings for the v4l2 userspace api
-
-# Copyright (C) 1999-2009 the contributors
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# Alternatively you can redistribute this file under the terms of the
-# BSD license as stated below:
-
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# 3. The names of its contributors may not be used to endorse or promote
-# products derived from this software without specific prior written
-# permission.
-
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""
-Python bindings for the v4l2 userspace api in Linux 2.6.34
-"""
-
-# see linux/videodev2.h
-
-import ctypes
-
-
-_IOC_NRBITS = 8
-_IOC_TYPEBITS = 8
-_IOC_SIZEBITS = 14
-_IOC_DIRBITS = 2
-
-_IOC_NRSHIFT = 0
-_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
-_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
-_IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
-
-_IOC_NONE = 0
-_IOC_WRITE = 1
-_IOC_READ = 2
-
-
-def _IOC(dir_, type_, nr, size):
- return (
- ctypes.c_int32(dir_ << _IOC_DIRSHIFT).value |
- ctypes.c_int32(ord(type_) << _IOC_TYPESHIFT).value |
- ctypes.c_int32(nr << _IOC_NRSHIFT).value |
- ctypes.c_int32(size << _IOC_SIZESHIFT).value)
-
-
-def _IOC_TYPECHECK(t):
- return ctypes.sizeof(t)
-
-
-def _IO(type_, nr):
- return _IOC(_IOC_NONE, type_, nr, 0)
-
-
-def _IOW(type_, nr, size):
- return _IOC(_IOC_WRITE, type_, nr, _IOC_TYPECHECK(size))
-
-
-def _IOR(type_, nr, size):
- return _IOC(_IOC_READ, type_, nr, _IOC_TYPECHECK(size))
-
-
-def _IOWR(type_, nr, size):
- return _IOC(_IOC_READ | _IOC_WRITE, type_, nr, _IOC_TYPECHECK(size))
-
-
-#
-# type alias
-#
-
-enum = ctypes.c_uint
-c_int = ctypes.c_int
-
-
-#
-# time
-#
-
-class timeval(ctypes.Structure):
- _fields_ = [
- ('secs', ctypes.c_long),
- ('usecs', ctypes.c_long),
- ]
-
-
-#
-# v4l2
-#
-
-
-VIDEO_MAX_FRAME = 32
-
-
-VID_TYPE_CAPTURE = 1
-VID_TYPE_TUNER = 2
-VID_TYPE_TELETEXT = 4
-VID_TYPE_OVERLAY = 8
-VID_TYPE_CHROMAKEY = 16
-VID_TYPE_CLIPPING = 32
-VID_TYPE_FRAMERAM = 64
-VID_TYPE_SCALES = 128
-VID_TYPE_MONOCHROME = 256
-VID_TYPE_SUBCAPTURE = 512
-VID_TYPE_MPEG_DECODER = 1024
-VID_TYPE_MPEG_ENCODER = 2048
-VID_TYPE_MJPEG_DECODER = 4096
-VID_TYPE_MJPEG_ENCODER = 8192
-
-
-def v4l2_fourcc(a, b, c, d):
- return ord(a) | (ord(b) << 8) | (ord(c) << 16) | (ord(d) << 24)
-
-
-v4l2_field = enum
-(
- V4L2_FIELD_ANY,
- V4L2_FIELD_NONE,
- V4L2_FIELD_TOP,
- V4L2_FIELD_BOTTOM,
- V4L2_FIELD_INTERLACED,
- V4L2_FIELD_SEQ_TB,
- V4L2_FIELD_SEQ_BT,
- V4L2_FIELD_ALTERNATE,
- V4L2_FIELD_INTERLACED_TB,
- V4L2_FIELD_INTERLACED_BT,
-) = range(10)
-
-
-def V4L2_FIELD_HAS_TOP(field):
- return (
- field == V4L2_FIELD_TOP or
- field == V4L2_FIELD_INTERLACED or
- field == V4L2_FIELD_INTERLACED_TB or
- field == V4L2_FIELD_INTERLACED_BT or
- field == V4L2_FIELD_SEQ_TB or
- field == V4L2_FIELD_SEQ_BT)
-
-
-def V4L2_FIELD_HAS_BOTTOM(field):
- return (
- field == V4L2_FIELD_BOTTOM or
- field == V4L2_FIELD_INTERLACED or
- field == V4L2_FIELD_INTERLACED_TB or
- field == V4L2_FIELD_INTERLACED_BT or
- field == V4L2_FIELD_SEQ_TB or
- field == V4L2_FIELD_SEQ_BT)
-
-
-def V4L2_FIELD_HAS_BOTH(field):
- return (
- field == V4L2_FIELD_INTERLACED or
- field == V4L2_FIELD_INTERLACED_TB or
- field == V4L2_FIELD_INTERLACED_BT or
- field == V4L2_FIELD_SEQ_TB or
- field == V4L2_FIELD_SEQ_BT)
-
-
-v4l2_buf_type = enum
-(
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_BUF_TYPE_VIDEO_OUTPUT,
- V4L2_BUF_TYPE_VIDEO_OVERLAY,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_BUF_TYPE_VBI_OUTPUT,
- V4L2_BUF_TYPE_SLICED_VBI_CAPTURE,
- V4L2_BUF_TYPE_SLICED_VBI_OUTPUT,
- V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
- V4L2_BUF_TYPE_PRIVATE,
-) = range(1, 9) + [0x80]
-
-
-v4l2_ctrl_type = enum
-(
- V4L2_CTRL_TYPE_INTEGER,
- V4L2_CTRL_TYPE_BOOLEAN,
- V4L2_CTRL_TYPE_MENU,
- V4L2_CTRL_TYPE_BUTTON,
- V4L2_CTRL_TYPE_INTEGER64,
- V4L2_CTRL_TYPE_CTRL_CLASS,
- V4L2_CTRL_TYPE_STRING,
-) = range(1, 8)
-
-
-v4l2_tuner_type = enum
-(
- V4L2_TUNER_RADIO,
- V4L2_TUNER_ANALOG_TV,
- V4L2_TUNER_DIGITAL_TV,
-) = range(1, 4)
-
-
-v4l2_memory = enum
-(
- V4L2_MEMORY_MMAP,
- V4L2_MEMORY_USERPTR,
- V4L2_MEMORY_OVERLAY,
-) = range(1, 4)
-
-
-v4l2_colorspace = enum
-(
- V4L2_COLORSPACE_SMPTE170M,
- V4L2_COLORSPACE_SMPTE240M,
- V4L2_COLORSPACE_REC709,
- V4L2_COLORSPACE_BT878,
- V4L2_COLORSPACE_470_SYSTEM_M,
- V4L2_COLORSPACE_470_SYSTEM_BG,
- V4L2_COLORSPACE_JPEG,
- V4L2_COLORSPACE_SRGB,
-) = range(1, 9)
-
-
-v4l2_priority = enum
-(
- V4L2_PRIORITY_UNSET,
- V4L2_PRIORITY_BACKGROUND,
- V4L2_PRIORITY_INTERACTIVE,
- V4L2_PRIORITY_RECORD,
- V4L2_PRIORITY_DEFAULT,
-) = range(0, 4) + [2]
-
-
-class v4l2_rect(ctypes.Structure):
- _fields_ = [
- ('left', ctypes.c_int32),
- ('top', ctypes.c_int32),
- ('width', ctypes.c_int32),
- ('height', ctypes.c_int32),
- ]
-
-
-class v4l2_fract(ctypes.Structure):
- _fields_ = [
- ('numerator', ctypes.c_uint32),
- ('denominator', ctypes.c_uint32),
- ]
-
-
-#
-# Driver capabilities
-#
-
-class v4l2_capability(ctypes.Structure):
- _fields_ = [
- ('driver', ctypes.c_char * 16),
- ('card', ctypes.c_char * 32),
- ('bus_info', ctypes.c_char * 32),
- ('version', ctypes.c_uint32),
- ('capabilities', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-#
-# Values for 'capabilities' field
-#
-
-V4L2_CAP_VIDEO_CAPTURE = 0x00000001
-V4L2_CAP_VIDEO_OUTPUT = 0x00000002
-V4L2_CAP_VIDEO_OVERLAY = 0x00000004
-V4L2_CAP_VBI_CAPTURE = 0x00000010
-V4L2_CAP_VBI_OUTPUT = 0x00000020
-V4L2_CAP_SLICED_VBI_CAPTURE = 0x00000040
-V4L2_CAP_SLICED_VBI_OUTPUT = 0x00000080
-V4L2_CAP_RDS_CAPTURE = 0x00000100
-V4L2_CAP_VIDEO_OUTPUT_OVERLAY = 0x00000200
-V4L2_CAP_HW_FREQ_SEEK = 0x00000400
-V4L2_CAP_RDS_OUTPUT = 0x00000800
-
-V4L2_CAP_TUNER = 0x00010000
-V4L2_CAP_AUDIO = 0x00020000
-V4L2_CAP_RADIO = 0x00040000
-V4L2_CAP_MODULATOR = 0x00080000
-
-V4L2_CAP_READWRITE = 0x01000000
-V4L2_CAP_ASYNCIO = 0x02000000
-V4L2_CAP_STREAMING = 0x04000000
-
-
-#
-# Video image format
-#
-
-class v4l2_pix_format(ctypes.Structure):
- _fields_ = [
- ('width', ctypes.c_uint32),
- ('height', ctypes.c_uint32),
- ('pixelformat', ctypes.c_uint32),
- ('field', v4l2_field),
- ('bytesperline', ctypes.c_uint32),
- ('sizeimage', ctypes.c_uint32),
- ('colorspace', v4l2_colorspace),
- ('priv', ctypes.c_uint32),
- ]
-
-# RGB formats
-V4L2_PIX_FMT_RGB332 = v4l2_fourcc('R', 'G', 'B', '1')
-V4L2_PIX_FMT_RGB444 = v4l2_fourcc('R', '4', '4', '4')
-V4L2_PIX_FMT_RGB555 = v4l2_fourcc('R', 'G', 'B', 'O')
-V4L2_PIX_FMT_RGB565 = v4l2_fourcc('R', 'G', 'B', 'P')
-V4L2_PIX_FMT_RGB555X = v4l2_fourcc('R', 'G', 'B', 'Q')
-V4L2_PIX_FMT_RGB565X = v4l2_fourcc('R', 'G', 'B', 'R')
-V4L2_PIX_FMT_BGR24 = v4l2_fourcc('B', 'G', 'R', '3')
-V4L2_PIX_FMT_RGB24 = v4l2_fourcc('R', 'G', 'B', '3')
-V4L2_PIX_FMT_BGR32 = v4l2_fourcc('B', 'G', 'R', '4')
-V4L2_PIX_FMT_RGB32 = v4l2_fourcc('R', 'G', 'B', '4')
-
-# Grey formats
-V4L2_PIX_FMT_GREY = v4l2_fourcc('G', 'R', 'E', 'Y')
-V4L2_PIX_FMT_Y10 = v4l2_fourcc('Y', '1', '0', ' ')
-V4L2_PIX_FMT_Y16 = v4l2_fourcc('Y', '1', '6', ' ')
-
-# Palette formats
-V4L2_PIX_FMT_PAL8 = v4l2_fourcc('P', 'A', 'L', '8')
-
-# Luminance+Chrominance formats
-V4L2_PIX_FMT_YVU410 = v4l2_fourcc('Y', 'V', 'U', '9')
-V4L2_PIX_FMT_YVU420 = v4l2_fourcc('Y', 'V', '1', '2')
-V4L2_PIX_FMT_YUYV = v4l2_fourcc('Y', 'U', 'Y', 'V')
-V4L2_PIX_FMT_YYUV = v4l2_fourcc('Y', 'Y', 'U', 'V')
-V4L2_PIX_FMT_YVYU = v4l2_fourcc('Y', 'V', 'Y', 'U')
-V4L2_PIX_FMT_UYVY = v4l2_fourcc('U', 'Y', 'V', 'Y')
-V4L2_PIX_FMT_VYUY = v4l2_fourcc('V', 'Y', 'U', 'Y')
-V4L2_PIX_FMT_YUV422P = v4l2_fourcc('4', '2', '2', 'P')
-V4L2_PIX_FMT_YUV411P = v4l2_fourcc('4', '1', '1', 'P')
-V4L2_PIX_FMT_Y41P = v4l2_fourcc('Y', '4', '1', 'P')
-V4L2_PIX_FMT_YUV444 = v4l2_fourcc('Y', '4', '4', '4')
-V4L2_PIX_FMT_YUV555 = v4l2_fourcc('Y', 'U', 'V', 'O')
-V4L2_PIX_FMT_YUV565 = v4l2_fourcc('Y', 'U', 'V', 'P')
-V4L2_PIX_FMT_YUV32 = v4l2_fourcc('Y', 'U', 'V', '4')
-V4L2_PIX_FMT_YUV410 = v4l2_fourcc('Y', 'U', 'V', '9')
-V4L2_PIX_FMT_YUV420 = v4l2_fourcc('Y', 'U', '1', '2')
-V4L2_PIX_FMT_HI240 = v4l2_fourcc('H', 'I', '2', '4')
-V4L2_PIX_FMT_HM12 = v4l2_fourcc('H', 'M', '1', '2')
-
-# two planes -- one Y, one Cr + Cb interleaved
-V4L2_PIX_FMT_NV12 = v4l2_fourcc('N', 'V', '1', '2')
-V4L2_PIX_FMT_NV21 = v4l2_fourcc('N', 'V', '2', '1')
-V4L2_PIX_FMT_NV16 = v4l2_fourcc('N', 'V', '1', '6')
-V4L2_PIX_FMT_NV61 = v4l2_fourcc('N', 'V', '6', '1')
-
-# Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm
-V4L2_PIX_FMT_SBGGR8 = v4l2_fourcc('B', 'A', '8', '1')
-V4L2_PIX_FMT_SGBRG8 = v4l2_fourcc('G', 'B', 'R', 'G')
-V4L2_PIX_FMT_SGRBG8 = v4l2_fourcc('G', 'R', 'B', 'G')
-V4L2_PIX_FMT_SRGGB8 = v4l2_fourcc('R', 'G', 'G', 'B')
-V4L2_PIX_FMT_SBGGR10 = v4l2_fourcc('B', 'G', '1', '0')
-V4L2_PIX_FMT_SGBRG10 = v4l2_fourcc('G', 'B', '1', '0')
-V4L2_PIX_FMT_SGRBG10 = v4l2_fourcc('B', 'A', '1', '0')
-V4L2_PIX_FMT_SRGGB10 = v4l2_fourcc('R', 'G', '1', '0')
-V4L2_PIX_FMT_SGRBG10DPCM8 = v4l2_fourcc('B', 'D', '1', '0')
-V4L2_PIX_FMT_SBGGR16 = v4l2_fourcc('B', 'Y', 'R', '2')
-
-# compressed formats
-V4L2_PIX_FMT_MJPEG = v4l2_fourcc('M', 'J', 'P', 'G')
-V4L2_PIX_FMT_JPEG = v4l2_fourcc('J', 'P', 'E', 'G')
-V4L2_PIX_FMT_DV = v4l2_fourcc('d', 'v', 's', 'd')
-V4L2_PIX_FMT_MPEG = v4l2_fourcc('M', 'P', 'E', 'G')
-
-# Vendor-specific formats
-V4L2_PIX_FMT_CPIA1 = v4l2_fourcc('C', 'P', 'I', 'A')
-V4L2_PIX_FMT_WNVA = v4l2_fourcc('W', 'N', 'V', 'A')
-V4L2_PIX_FMT_SN9C10X = v4l2_fourcc('S', '9', '1', '0')
-V4L2_PIX_FMT_SN9C20X_I420 = v4l2_fourcc('S', '9', '2', '0')
-V4L2_PIX_FMT_PWC1 = v4l2_fourcc('P', 'W', 'C', '1')
-V4L2_PIX_FMT_PWC2 = v4l2_fourcc('P', 'W', 'C', '2')
-V4L2_PIX_FMT_ET61X251 = v4l2_fourcc('E', '6', '2', '5')
-V4L2_PIX_FMT_SPCA501 = v4l2_fourcc('S', '5', '0', '1')
-V4L2_PIX_FMT_SPCA505 = v4l2_fourcc('S', '5', '0', '5')
-V4L2_PIX_FMT_SPCA508 = v4l2_fourcc('S', '5', '0', '8')
-V4L2_PIX_FMT_SPCA561 = v4l2_fourcc('S', '5', '6', '1')
-V4L2_PIX_FMT_PAC207 = v4l2_fourcc('P', '2', '0', '7')
-V4L2_PIX_FMT_MR97310A = v4l2_fourcc('M', '3', '1', '0')
-V4L2_PIX_FMT_SN9C2028 = v4l2_fourcc('S', 'O', 'N', 'X')
-V4L2_PIX_FMT_SQ905C = v4l2_fourcc('9', '0', '5', 'C')
-V4L2_PIX_FMT_PJPG = v4l2_fourcc('P', 'J', 'P', 'G')
-V4L2_PIX_FMT_OV511 = v4l2_fourcc('O', '5', '1', '1')
-V4L2_PIX_FMT_OV518 = v4l2_fourcc('O', '5', '1', '8')
-V4L2_PIX_FMT_STV0680 = v4l2_fourcc('S', '6', '8', '0')
-
-
-#
-# Format enumeration
-#
-
-class v4l2_fmtdesc(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('type', ctypes.c_int),
- ('flags', ctypes.c_uint32),
- ('description', ctypes.c_char * 32),
- ('pixelformat', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-V4L2_FMT_FLAG_COMPRESSED = 0x0001
-V4L2_FMT_FLAG_EMULATED = 0x0002
-
-
-#
-# Experimental frame size and frame rate enumeration
-#
-
-v4l2_frmsizetypes = enum
-(
- V4L2_FRMSIZE_TYPE_DISCRETE,
- V4L2_FRMSIZE_TYPE_CONTINUOUS,
- V4L2_FRMSIZE_TYPE_STEPWISE,
-) = range(1, 4)
-
-
-class v4l2_frmsize_discrete(ctypes.Structure):
- _fields_ = [
- ('width', ctypes.c_uint32),
- ('height', ctypes.c_uint32),
- ]
-
-
-class v4l2_frmsize_stepwise(ctypes.Structure):
- _fields_ = [
- ('min_width', ctypes.c_uint32),
- ('min_height', ctypes.c_uint32),
- ('step_width', ctypes.c_uint32),
- ('min_height', ctypes.c_uint32),
- ('max_height', ctypes.c_uint32),
- ('step_height', ctypes.c_uint32),
- ]
-
-
-class v4l2_frmsizeenum(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('discrete', v4l2_frmsize_discrete),
- ('stepwise', v4l2_frmsize_stepwise),
- ]
-
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('pixel_format', ctypes.c_uint32),
- ('type', ctypes.c_uint32),
- ('_u', _u),
- ('reserved', ctypes.c_uint32 * 2)
- ]
-
- _anonymous_ = ('_u',)
-
-
-#
-# Frame rate enumeration
-#
-
-v4l2_frmivaltypes = enum
-(
- V4L2_FRMIVAL_TYPE_DISCRETE,
- V4L2_FRMIVAL_TYPE_CONTINUOUS,
- V4L2_FRMIVAL_TYPE_STEPWISE,
-) = range(1, 4)
-
-
-class v4l2_frmival_stepwise(ctypes.Structure):
- _fields_ = [
- ('min', v4l2_fract),
- ('max', v4l2_fract),
- ('step', v4l2_fract),
- ]
-
-
-class v4l2_frmivalenum(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('discrete', v4l2_fract),
- ('stepwise', v4l2_frmival_stepwise),
- ]
-
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('pixel_format', ctypes.c_uint32),
- ('width', ctypes.c_uint32),
- ('height', ctypes.c_uint32),
- ('type', ctypes.c_uint32),
- ('_u', _u),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
- _anonymous_ = ('_u',)
-
-
-#
-# Timecode
-#
-
-class v4l2_timecode(ctypes.Structure):
- _fields_ = [
- ('type', ctypes.c_uint32),
- ('flags', ctypes.c_uint32),
- ('frames', ctypes.c_uint8),
- ('seconds', ctypes.c_uint8),
- ('minutes', ctypes.c_uint8),
- ('hours', ctypes.c_uint8),
- ('userbits', ctypes.c_uint8 * 4),
- ]
-
-
-V4L2_TC_TYPE_24FPS = 1
-V4L2_TC_TYPE_25FPS = 2
-V4L2_TC_TYPE_30FPS = 3
-V4L2_TC_TYPE_50FPS = 4
-V4L2_TC_TYPE_60FPS = 5
-
-V4L2_TC_FLAG_DROPFRAME = 0x0001
-V4L2_TC_FLAG_COLORFRAME = 0x0002
-V4L2_TC_USERBITS_field = 0x000C
-V4L2_TC_USERBITS_USERDEFINED = 0x0000
-V4L2_TC_USERBITS_8BITCHARS = 0x0008
-
-
-class v4l2_jpegcompression(ctypes.Structure):
- _fields_ = [
- ('quality', ctypes.c_int),
- ('APPn', ctypes.c_int),
- ('APP_len', ctypes.c_int),
- ('APP_data', ctypes.c_char * 60),
- ('COM_len', ctypes.c_int),
- ('COM_data', ctypes.c_char * 60),
- ('jpeg_markers', ctypes.c_uint32),
- ]
-
-
-V4L2_JPEG_MARKER_DHT = 1 << 3
-V4L2_JPEG_MARKER_DQT = 1 << 4
-V4L2_JPEG_MARKER_DRI = 1 << 5
-V4L2_JPEG_MARKER_COM = 1 << 6
-V4L2_JPEG_MARKER_APP = 1 << 7
-
-
-#
-# Memory-mapping buffers
-#
-
-class v4l2_requestbuffers(ctypes.Structure):
- _fields_ = [
- ('count', ctypes.c_uint32),
- ('type', v4l2_buf_type),
- ('memory', v4l2_memory),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
-
-class v4l2_buffer(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('offset', ctypes.c_uint32),
- ('userptr', ctypes.c_ulong),
- ]
-
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('type', v4l2_buf_type),
- ('bytesused', ctypes.c_uint32),
- ('flags', ctypes.c_uint32),
- ('field', v4l2_field),
- ('timestamp', timeval),
- ('timecode', v4l2_timecode),
- ('sequence', ctypes.c_uint32),
- ('memory', v4l2_memory),
- ('m', _u),
- ('length', ctypes.c_uint32),
- ('input', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32),
- ]
-
-
-V4L2_BUF_FLAG_MAPPED = 0x0001
-V4L2_BUF_FLAG_QUEUED = 0x0002
-V4L2_BUF_FLAG_DONE = 0x0004
-V4L2_BUF_FLAG_KEYFRAME = 0x0008
-V4L2_BUF_FLAG_PFRAME = 0x0010
-V4L2_BUF_FLAG_BFRAME = 0x0020
-V4L2_BUF_FLAG_TIMECODE = 0x0100
-V4L2_BUF_FLAG_INPUT = 0x0200
-
-
-#
-# Overlay preview
-#
-
-class v4l2_framebuffer(ctypes.Structure):
- _fields_ = [
- ('capability', ctypes.c_uint32),
- ('flags', ctypes.c_uint32),
- ('base', ctypes.c_void_p),
- ('fmt', v4l2_pix_format),
- ]
-
-V4L2_FBUF_CAP_EXTERNOVERLAY = 0x0001
-V4L2_FBUF_CAP_CHROMAKEY = 0x0002
-V4L2_FBUF_CAP_LIST_CLIPPING = 0x0004
-V4L2_FBUF_CAP_BITMAP_CLIPPING = 0x0008
-V4L2_FBUF_CAP_LOCAL_ALPHA = 0x0010
-V4L2_FBUF_CAP_GLOBAL_ALPHA = 0x0020
-V4L2_FBUF_CAP_LOCAL_INV_ALPHA = 0x0040
-V4L2_FBUF_CAP_SRC_CHROMAKEY = 0x0080
-
-V4L2_FBUF_FLAG_PRIMARY = 0x0001
-V4L2_FBUF_FLAG_OVERLAY = 0x0002
-V4L2_FBUF_FLAG_CHROMAKEY = 0x0004
-V4L2_FBUF_FLAG_LOCAL_ALPHA = 0x0008
-V4L2_FBUF_FLAG_GLOBAL_ALPHA = 0x0010
-V4L2_FBUF_FLAG_LOCAL_INV_ALPHA = 0x0020
-V4L2_FBUF_FLAG_SRC_CHROMAKEY = 0x0040
-
-
-class v4l2_clip(ctypes.Structure):
- pass
-v4l2_clip._fields_ = [
- ('c', v4l2_rect),
- ('next', ctypes.POINTER(v4l2_clip)),
-]
-
-
-class v4l2_window(ctypes.Structure):
- _fields_ = [
- ('w', v4l2_rect),
- ('field', v4l2_field),
- ('chromakey', ctypes.c_uint32),
- ('clips', ctypes.POINTER(v4l2_clip)),
- ('clipcount', ctypes.c_uint32),
- ('bitmap', ctypes.c_void_p),
- ('global_alpha', ctypes.c_uint8),
- ]
-
-
-#
-# Capture parameters
-#
-
-class v4l2_captureparm(ctypes.Structure):
- _fields_ = [
- ('capability', ctypes.c_uint32),
- ('capturemode', ctypes.c_uint32),
- ('timeperframe', v4l2_fract),
- ('extendedmode', ctypes.c_uint32),
- ('readbuffers', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-V4L2_MODE_HIGHQUALITY = 0x0001
-V4L2_CAP_TIMEPERFRAME = 0x1000
-
-
-class v4l2_outputparm(ctypes.Structure):
- _fields_ = [
- ('capability', ctypes.c_uint32),
- ('outputmode', ctypes.c_uint32),
- ('timeperframe', v4l2_fract),
- ('extendedmode', ctypes.c_uint32),
- ('writebuffers', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-#
-# Input image cropping
-#
-
-class v4l2_cropcap(ctypes.Structure):
- _fields_ = [
- ('type', v4l2_buf_type),
- ('bounds', v4l2_rect),
- ('defrect', v4l2_rect),
- ('pixelaspect', v4l2_fract),
- ]
-
-
-class v4l2_crop(ctypes.Structure):
- _fields_ = [
- ('type', ctypes.c_int),
- ('c', v4l2_rect),
- ]
-
-
-#
-# Analog video standard
-#
-
-v4l2_std_id = ctypes.c_uint64
-
-
-V4L2_STD_PAL_B = 0x00000001
-V4L2_STD_PAL_B1 = 0x00000002
-V4L2_STD_PAL_G = 0x00000004
-V4L2_STD_PAL_H = 0x00000008
-V4L2_STD_PAL_I = 0x00000010
-V4L2_STD_PAL_D = 0x00000020
-V4L2_STD_PAL_D1 = 0x00000040
-V4L2_STD_PAL_K = 0x00000080
-
-V4L2_STD_PAL_M = 0x00000100
-V4L2_STD_PAL_N = 0x00000200
-V4L2_STD_PAL_Nc = 0x00000400
-V4L2_STD_PAL_60 = 0x00000800
-
-V4L2_STD_NTSC_M = 0x00001000
-V4L2_STD_NTSC_M_JP = 0x00002000
-V4L2_STD_NTSC_443 = 0x00004000
-V4L2_STD_NTSC_M_KR = 0x00008000
-
-V4L2_STD_SECAM_B = 0x00010000
-V4L2_STD_SECAM_D = 0x00020000
-V4L2_STD_SECAM_G = 0x00040000
-V4L2_STD_SECAM_H = 0x00080000
-V4L2_STD_SECAM_K = 0x00100000
-V4L2_STD_SECAM_K1 = 0x00200000
-V4L2_STD_SECAM_L = 0x00400000
-V4L2_STD_SECAM_LC = 0x00800000
-
-V4L2_STD_ATSC_8_VSB = 0x01000000
-V4L2_STD_ATSC_16_VSB = 0x02000000
-
-
-# some common needed stuff
-V4L2_STD_PAL_BG = (V4L2_STD_PAL_B | V4L2_STD_PAL_B1 | V4L2_STD_PAL_G)
-V4L2_STD_PAL_DK = (V4L2_STD_PAL_D | V4L2_STD_PAL_D1 | V4L2_STD_PAL_K)
-V4L2_STD_PAL = (V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_H | V4L2_STD_PAL_I)
-V4L2_STD_NTSC = (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR)
-V4L2_STD_SECAM_DK = (V4L2_STD_SECAM_D | V4L2_STD_SECAM_K | V4L2_STD_SECAM_K1)
-V4L2_STD_SECAM = (V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H | V4L2_STD_SECAM_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)
-
-V4L2_STD_525_60 = (V4L2_STD_PAL_M | V4L2_STD_PAL_60 | V4L2_STD_NTSC | V4L2_STD_NTSC_443)
-V4L2_STD_625_50 = (V4L2_STD_PAL | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | V4L2_STD_SECAM)
-V4L2_STD_ATSC = (V4L2_STD_ATSC_8_VSB | V4L2_STD_ATSC_16_VSB)
-
-V4L2_STD_UNKNOWN = 0
-V4L2_STD_ALL = (V4L2_STD_525_60 | V4L2_STD_625_50)
-
-# some merged standards
-V4L2_STD_MN = (V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | V4L2_STD_NTSC)
-V4L2_STD_B = (V4L2_STD_PAL_B | V4L2_STD_PAL_B1 | V4L2_STD_SECAM_B)
-V4L2_STD_GH = (V4L2_STD_PAL_G | V4L2_STD_PAL_H|V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)
-V4L2_STD_DK = (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK)
-
-
-class v4l2_standard(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('id', v4l2_std_id),
- ('name', ctypes.c_char * 24),
- ('frameperiod', v4l2_fract),
- ('framelines', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-#
-# Video timings dv preset
-#
-
-class v4l2_dv_preset(ctypes.Structure):
- _fields_ = [
- ('preset', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4)
- ]
-
-
-#
-# DV preset enumeration
-#
-
-class v4l2_dv_enum_preset(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('preset', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('width', ctypes.c_uint32),
- ('height', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-#
-# DV preset values
-#
-
-V4L2_DV_INVALID = 0
-V4L2_DV_480P59_94 = 1
-V4L2_DV_576P50 = 2
-V4L2_DV_720P24 = 3
-V4L2_DV_720P25 = 4
-V4L2_DV_720P30 = 5
-V4L2_DV_720P50 = 6
-V4L2_DV_720P59_94 = 7
-V4L2_DV_720P60 = 8
-V4L2_DV_1080I29_97 = 9
-V4L2_DV_1080I30 = 10
-V4L2_DV_1080I25 = 11
-V4L2_DV_1080I50 = 12
-V4L2_DV_1080I60 = 13
-V4L2_DV_1080P24 = 14
-V4L2_DV_1080P25 = 15
-V4L2_DV_1080P30 = 16
-V4L2_DV_1080P50 = 17
-V4L2_DV_1080P60 = 18
-
-
-#
-# DV BT timings
-#
-
-class v4l2_bt_timings(ctypes.Structure):
- _fields_ = [
- ('width', ctypes.c_uint32),
- ('height', ctypes.c_uint32),
- ('interlaced', ctypes.c_uint32),
- ('polarities', ctypes.c_uint32),
- ('pixelclock', ctypes.c_uint64),
- ('hfrontporch', ctypes.c_uint32),
- ('hsync', ctypes.c_uint32),
- ('hbackporch', ctypes.c_uint32),
- ('vfrontporch', ctypes.c_uint32),
- ('vsync', ctypes.c_uint32),
- ('vbackporch', ctypes.c_uint32),
- ('il_vfrontporch', ctypes.c_uint32),
- ('il_vsync', ctypes.c_uint32),
- ('il_vbackporch', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 16),
- ]
-
- _pack_ = True
-
-# Interlaced or progressive format
-V4L2_DV_PROGRESSIVE = 0
-V4L2_DV_INTERLACED = 1
-
-# Polarities. If bit is not set, it is assumed to be negative polarity
-V4L2_DV_VSYNC_POS_POL = 0x00000001
-V4L2_DV_HSYNC_POS_POL = 0x00000002
-
-
-class v4l2_dv_timings(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('bt', v4l2_bt_timings),
- ('reserved', ctypes.c_uint32 * 32),
- ]
-
- _fields_ = [
- ('type', ctypes.c_uint32),
- ('_u', _u),
- ]
-
- _anonymous_ = ('_u',)
- _pack_ = True
-
-
-# Values for the type field
-V4L2_DV_BT_656_1120 = 0
-
-
-#
-# Video inputs
-#
-
-class v4l2_input(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('type', ctypes.c_uint32),
- ('audioset', ctypes.c_uint32),
- ('tuner', ctypes.c_uint32),
- ('std', v4l2_std_id),
- ('status', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-V4L2_INPUT_TYPE_TUNER = 1
-V4L2_INPUT_TYPE_CAMERA = 2
-
-V4L2_IN_ST_NO_POWER = 0x00000001
-V4L2_IN_ST_NO_SIGNAL = 0x00000002
-V4L2_IN_ST_NO_COLOR = 0x00000004
-
-V4L2_IN_ST_HFLIP = 0x00000010
-V4L2_IN_ST_VFLIP = 0x00000020
-
-V4L2_IN_ST_NO_H_LOCK = 0x00000100
-V4L2_IN_ST_COLOR_KILL = 0x00000200
-
-V4L2_IN_ST_NO_SYNC = 0x00010000
-V4L2_IN_ST_NO_EQU = 0x00020000
-V4L2_IN_ST_NO_CARRIER = 0x00040000
-
-V4L2_IN_ST_MACROVISION = 0x01000000
-V4L2_IN_ST_NO_ACCESS = 0x02000000
-V4L2_IN_ST_VTR = 0x04000000
-
-V4L2_IN_CAP_PRESETS = 0x00000001
-V4L2_IN_CAP_CUSTOM_TIMINGS = 0x00000002
-V4L2_IN_CAP_STD = 0x00000004
-
-#
-# Video outputs
-#
-
-class v4l2_output(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('type', ctypes.c_uint32),
- ('audioset', ctypes.c_uint32),
- ('modulator', ctypes.c_uint32),
- ('std', v4l2_std_id),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-V4L2_OUTPUT_TYPE_MODULATOR = 1
-V4L2_OUTPUT_TYPE_ANALOG = 2
-V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY = 3
-
-V4L2_OUT_CAP_PRESETS = 0x00000001
-V4L2_OUT_CAP_CUSTOM_TIMINGS = 0x00000002
-V4L2_OUT_CAP_STD = 0x00000004
-
-#
-# Controls
-#
-
-class v4l2_control(ctypes.Structure):
- _fields_ = [
- ('id', ctypes.c_uint32),
- ('value', ctypes.c_int32),
- ]
-
-
-class v4l2_ext_control(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('value', ctypes.c_int32),
- ('value64', ctypes.c_int64),
- ('reserved', ctypes.c_void_p),
- ]
-
- _fields_ = [
- ('id', ctypes.c_uint32),
- ('reserved2', ctypes.c_uint32 * 2),
- ('_u', _u)
- ]
-
- _anonymous_ = ('_u',)
- _pack_ = True
-
-
-class v4l2_ext_controls(ctypes.Structure):
- _fields_ = [
- ('ctrl_class', ctypes.c_uint32),
- ('count', ctypes.c_uint32),
- ('error_idx', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 2),
- ('controls', ctypes.POINTER(v4l2_ext_control)),
- ]
-
-
-V4L2_CTRL_CLASS_USER = 0x00980000
-V4L2_CTRL_CLASS_MPEG = 0x00990000
-V4L2_CTRL_CLASS_CAMERA = 0x009a0000
-V4L2_CTRL_CLASS_FM_TX = 0x009b0000
-
-
-def V4L2_CTRL_ID_MASK():
- return 0x0fffffff
-
-
-def V4L2_CTRL_ID2CLASS(id_):
- return id_ & 0x0fff0000 # unsigned long
-
-
-def V4L2_CTRL_DRIVER_PRIV(id_):
- return (id_ & 0xffff) >= 0x1000
-
-
-class v4l2_queryctrl(ctypes.Structure):
- _fields_ = [
- ('id', ctypes.c_uint32),
- ('type', v4l2_ctrl_type),
- ('name', ctypes.c_char * 32),
- ('minimum', ctypes.c_int32),
- ('maximum', ctypes.c_int32),
- ('step', ctypes.c_int32),
- ('default', ctypes.c_int32),
- ('flags', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
-
-class v4l2_querymenu(ctypes.Structure):
- _fields_ = [
- ('id', ctypes.c_uint32),
- ('index', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('reserved', ctypes.c_uint32),
- ]
-
-
-V4L2_CTRL_FLAG_DISABLED = 0x0001
-V4L2_CTRL_FLAG_GRABBED = 0x0002
-V4L2_CTRL_FLAG_READ_ONLY = 0x0004
-V4L2_CTRL_FLAG_UPDATE = 0x0008
-V4L2_CTRL_FLAG_INACTIVE = 0x0010
-V4L2_CTRL_FLAG_SLIDER = 0x0020
-V4L2_CTRL_FLAG_WRITE_ONLY = 0x0040
-
-V4L2_CTRL_FLAG_NEXT_CTRL = 0x80000000
-
-V4L2_CID_BASE = V4L2_CTRL_CLASS_USER | 0x900
-V4L2_CID_USER_BASE = V4L2_CID_BASE
-V4L2_CID_PRIVATE_BASE = 0x08000000
-
-V4L2_CID_USER_CLASS = V4L2_CTRL_CLASS_USER | 1
-V4L2_CID_BRIGHTNESS = V4L2_CID_BASE + 0
-V4L2_CID_CONTRAST = V4L2_CID_BASE + 1
-V4L2_CID_SATURATION = V4L2_CID_BASE + 2
-V4L2_CID_HUE = V4L2_CID_BASE + 3
-V4L2_CID_AUDIO_VOLUME = V4L2_CID_BASE + 5
-V4L2_CID_AUDIO_BALANCE = V4L2_CID_BASE + 6
-V4L2_CID_AUDIO_BASS = V4L2_CID_BASE + 7
-V4L2_CID_AUDIO_TREBLE = V4L2_CID_BASE + 8
-V4L2_CID_AUDIO_MUTE = V4L2_CID_BASE + 9
-V4L2_CID_AUDIO_LOUDNESS = V4L2_CID_BASE + 10
-V4L2_CID_BLACK_LEVEL = V4L2_CID_BASE + 11 # Deprecated
-V4L2_CID_AUTO_WHITE_BALANCE = V4L2_CID_BASE + 12
-V4L2_CID_DO_WHITE_BALANCE = V4L2_CID_BASE + 13
-V4L2_CID_RED_BALANCE = V4L2_CID_BASE + 14
-V4L2_CID_BLUE_BALANCE = V4L2_CID_BASE + 15
-V4L2_CID_GAMMA = V4L2_CID_BASE + 16
-V4L2_CID_WHITENESS = V4L2_CID_GAMMA # Deprecated
-V4L2_CID_EXPOSURE = V4L2_CID_BASE + 17
-V4L2_CID_AUTOGAIN = V4L2_CID_BASE + 18
-V4L2_CID_GAIN = V4L2_CID_BASE + 19
-V4L2_CID_HFLIP = V4L2_CID_BASE + 20
-V4L2_CID_VFLIP = V4L2_CID_BASE + 21
-
-# Deprecated; use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET
-V4L2_CID_HCENTER = V4L2_CID_BASE + 22
-V4L2_CID_VCENTER = V4L2_CID_BASE + 23
-
-V4L2_CID_POWER_LINE_FREQUENCY = V4L2_CID_BASE + 24
-
-v4l2_power_line_frequency = enum
-(
- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
- V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
- V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
-) = range(3)
-
-V4L2_CID_HUE_AUTO = V4L2_CID_BASE + 25
-V4L2_CID_WHITE_BALANCE_TEMPERATURE = V4L2_CID_BASE + 26
-V4L2_CID_SHARPNESS = V4L2_CID_BASE + 27
-V4L2_CID_BACKLIGHT_COMPENSATION = V4L2_CID_BASE + 28
-V4L2_CID_CHROMA_AGC = V4L2_CID_BASE + 29
-V4L2_CID_COLOR_KILLER = V4L2_CID_BASE + 30
-V4L2_CID_COLORFX = V4L2_CID_BASE + 31
-
-v4l2_colorfx = enum
-(
- V4L2_COLORFX_NONE,
- V4L2_COLORFX_BW,
- V4L2_COLORFX_SEPIA,
-) = range(3)
-
-V4L2_CID_AUTOBRIGHTNESS = V4L2_CID_BASE + 32
-V4L2_CID_BAND_STOP_FILTER = V4L2_CID_BASE + 33
-
-V4L2_CID_ROTATE = V4L2_CID_BASE + 34
-V4L2_CID_BG_COLOR = V4L2_CID_BASE + 35
-V4L2_CID_LASTP1 = V4L2_CID_BASE + 36
-
-V4L2_CID_MPEG_BASE = V4L2_CTRL_CLASS_MPEG | 0x900
-V4L2_CID_MPEG_CLASS = V4L2_CTRL_CLASS_MPEG | 1
-
-# MPEG streams
-V4L2_CID_MPEG_STREAM_TYPE = V4L2_CID_MPEG_BASE + 0
-
-v4l2_mpeg_stream_type = enum
-(
- V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
- V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
- V4L2_MPEG_STREAM_TYPE_MPEG1_SS,
- V4L2_MPEG_STREAM_TYPE_MPEG2_DVD,
- V4L2_MPEG_STREAM_TYPE_MPEG1_VCD,
- V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD,
-) = range(6)
-
-V4L2_CID_MPEG_STREAM_PID_PMT = V4L2_CID_MPEG_BASE + 1
-V4L2_CID_MPEG_STREAM_PID_AUDIO = V4L2_CID_MPEG_BASE + 2
-V4L2_CID_MPEG_STREAM_PID_VIDEO = V4L2_CID_MPEG_BASE + 3
-V4L2_CID_MPEG_STREAM_PID_PCR = V4L2_CID_MPEG_BASE + 4
-V4L2_CID_MPEG_STREAM_PES_ID_AUDIO = V4L2_CID_MPEG_BASE + 5
-V4L2_CID_MPEG_STREAM_PES_ID_VIDEO = V4L2_CID_MPEG_BASE + 6
-V4L2_CID_MPEG_STREAM_VBI_FMT = V4L2_CID_MPEG_BASE + 7
-
-v4l2_mpeg_stream_vbi_fmt = enum
-(
- V4L2_MPEG_STREAM_VBI_FMT_NONE,
- V4L2_MPEG_STREAM_VBI_FMT_IVTV,
-) = range(2)
-
-V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ = V4L2_CID_MPEG_BASE + 100
-
-v4l2_mpeg_audio_sampling_freq = enum
-(
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000,
-) = range(3)
-
-V4L2_CID_MPEG_AUDIO_ENCODING = V4L2_CID_MPEG_BASE + 101
-
-v4l2_mpeg_audio_encoding = enum
-(
- V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_3,
- V4L2_MPEG_AUDIO_ENCODING_AAC,
- V4L2_MPEG_AUDIO_ENCODING_AC3,
-) = range(5)
-
-V4L2_CID_MPEG_AUDIO_L1_BITRATE = V4L2_CID_MPEG_BASE + 102
-
-v4l2_mpeg_audio_l1_bitrate = enum
-(
- V4L2_MPEG_AUDIO_L1_BITRATE_32K,
- V4L2_MPEG_AUDIO_L1_BITRATE_64K,
- V4L2_MPEG_AUDIO_L1_BITRATE_96K,
- V4L2_MPEG_AUDIO_L1_BITRATE_128K,
- V4L2_MPEG_AUDIO_L1_BITRATE_160K,
- V4L2_MPEG_AUDIO_L1_BITRATE_192K,
- V4L2_MPEG_AUDIO_L1_BITRATE_224K,
- V4L2_MPEG_AUDIO_L1_BITRATE_256K,
- V4L2_MPEG_AUDIO_L1_BITRATE_288K,
- V4L2_MPEG_AUDIO_L1_BITRATE_320K,
- V4L2_MPEG_AUDIO_L1_BITRATE_352K,
- V4L2_MPEG_AUDIO_L1_BITRATE_384K,
- V4L2_MPEG_AUDIO_L1_BITRATE_416K,
- V4L2_MPEG_AUDIO_L1_BITRATE_448K,
-) = range(14)
-
-V4L2_CID_MPEG_AUDIO_L2_BITRATE = V4L2_CID_MPEG_BASE + 103
-
-v4l2_mpeg_audio_l2_bitrate = enum
-(
- V4L2_MPEG_AUDIO_L2_BITRATE_32K,
- V4L2_MPEG_AUDIO_L2_BITRATE_48K,
- V4L2_MPEG_AUDIO_L2_BITRATE_56K,
- V4L2_MPEG_AUDIO_L2_BITRATE_64K,
- V4L2_MPEG_AUDIO_L2_BITRATE_80K,
- V4L2_MPEG_AUDIO_L2_BITRATE_96K,
- V4L2_MPEG_AUDIO_L2_BITRATE_112K,
- V4L2_MPEG_AUDIO_L2_BITRATE_128K,
- V4L2_MPEG_AUDIO_L2_BITRATE_160K,
- V4L2_MPEG_AUDIO_L2_BITRATE_192K,
- V4L2_MPEG_AUDIO_L2_BITRATE_224K,
- V4L2_MPEG_AUDIO_L2_BITRATE_256K,
- V4L2_MPEG_AUDIO_L2_BITRATE_320K,
- V4L2_MPEG_AUDIO_L2_BITRATE_384K,
-) = range(14)
-
-V4L2_CID_MPEG_AUDIO_L3_BITRATE = V4L2_CID_MPEG_BASE + 104
-
-v4l2_mpeg_audio_l3_bitrate = enum
-(
- V4L2_MPEG_AUDIO_L3_BITRATE_32K,
- V4L2_MPEG_AUDIO_L3_BITRATE_40K,
- V4L2_MPEG_AUDIO_L3_BITRATE_48K,
- V4L2_MPEG_AUDIO_L3_BITRATE_56K,
- V4L2_MPEG_AUDIO_L3_BITRATE_64K,
- V4L2_MPEG_AUDIO_L3_BITRATE_80K,
- V4L2_MPEG_AUDIO_L3_BITRATE_96K,
- V4L2_MPEG_AUDIO_L3_BITRATE_112K,
- V4L2_MPEG_AUDIO_L3_BITRATE_128K,
- V4L2_MPEG_AUDIO_L3_BITRATE_160K,
- V4L2_MPEG_AUDIO_L3_BITRATE_192K,
- V4L2_MPEG_AUDIO_L3_BITRATE_224K,
- V4L2_MPEG_AUDIO_L3_BITRATE_256K,
- V4L2_MPEG_AUDIO_L3_BITRATE_320K,
-) = range(14)
-
-V4L2_CID_MPEG_AUDIO_MODE = V4L2_CID_MPEG_BASE + 105
-
-v4l2_mpeg_audio_mode = enum
-(
- V4L2_MPEG_AUDIO_MODE_STEREO,
- V4L2_MPEG_AUDIO_MODE_JOINT_STEREO,
- V4L2_MPEG_AUDIO_MODE_DUAL,
- V4L2_MPEG_AUDIO_MODE_MONO,
-) = range(4)
-
-V4L2_CID_MPEG_AUDIO_MODE_EXTENSION = V4L2_CID_MPEG_BASE + 106
-
-v4l2_mpeg_audio_mode_extension = enum
-(
- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8,
- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12,
- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16,
-) = range(4)
-
-V4L2_CID_MPEG_AUDIO_EMPHASIS = V4L2_CID_MPEG_BASE + 107
-
-v4l2_mpeg_audio_emphasis = enum
-(
- V4L2_MPEG_AUDIO_EMPHASIS_NONE,
- V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS,
- V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17,
-) = range(3)
-
-V4L2_CID_MPEG_AUDIO_CRC = V4L2_CID_MPEG_BASE + 108
-
-v4l2_mpeg_audio_crc = enum
-(
- V4L2_MPEG_AUDIO_CRC_NONE,
- V4L2_MPEG_AUDIO_CRC_CRC16,
-) = range(2)
-
-V4L2_CID_MPEG_AUDIO_MUTE = V4L2_CID_MPEG_BASE + 109
-V4L2_CID_MPEG_AUDIO_AAC_BITRATE = V4L2_CID_MPEG_BASE + 110
-V4L2_CID_MPEG_AUDIO_AC3_BITRATE = V4L2_CID_MPEG_BASE + 111
-
-v4l2_mpeg_audio_ac3_bitrate = enum
-(
- V4L2_MPEG_AUDIO_AC3_BITRATE_32K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_40K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_48K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_56K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_64K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_80K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_96K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_112K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_128K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_160K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_192K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_224K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_320K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_448K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_512K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_576K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_640K,
-) = range(19)
-
-V4L2_CID_MPEG_VIDEO_ENCODING = V4L2_CID_MPEG_BASE + 200
-
-v4l2_mpeg_video_encoding = enum
-(
- V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
-) = range(3)
-
-V4L2_CID_MPEG_VIDEO_ASPECT = V4L2_CID_MPEG_BASE + 201
-
-v4l2_mpeg_video_aspect = enum
-(
- V4L2_MPEG_VIDEO_ASPECT_1x1,
- V4L2_MPEG_VIDEO_ASPECT_4x3,
- V4L2_MPEG_VIDEO_ASPECT_16x9,
- V4L2_MPEG_VIDEO_ASPECT_221x100,
-) = range(4)
-
-V4L2_CID_MPEG_VIDEO_B_FRAMES = V4L2_CID_MPEG_BASE + 202
-V4L2_CID_MPEG_VIDEO_GOP_SIZE = V4L2_CID_MPEG_BASE + 203
-V4L2_CID_MPEG_VIDEO_GOP_CLOSURE = V4L2_CID_MPEG_BASE + 204
-V4L2_CID_MPEG_VIDEO_PULLDOWN = V4L2_CID_MPEG_BASE + 205
-V4L2_CID_MPEG_VIDEO_BITRATE_MODE = V4L2_CID_MPEG_BASE + 206
-
-v4l2_mpeg_video_bitrate_mode = enum
-(
- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
-) = range(2)
-
-V4L2_CID_MPEG_VIDEO_BITRATE = V4L2_CID_MPEG_BASE + 207
-V4L2_CID_MPEG_VIDEO_BITRATE_PEAK = V4L2_CID_MPEG_BASE + 208
-V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION = V4L2_CID_MPEG_BASE + 209
-V4L2_CID_MPEG_VIDEO_MUTE = V4L2_CID_MPEG_BASE + 210
-V4L2_CID_MPEG_VIDEO_MUTE_YUV = V4L2_CID_MPEG_BASE + 211
-
-V4L2_CID_MPEG_CX2341X_BASE = V4L2_CTRL_CLASS_MPEG | 0x1000
-V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE = V4L2_CID_MPEG_CX2341X_BASE + 0
-
-v4l2_mpeg_cx2341x_video_spatial_filter_mode = enum
-(
- V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
- V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO,
-) = range(2)
-
-V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER = V4L2_CID_MPEG_CX2341X_BASE + 1
-V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE = V4L2_CID_MPEG_CX2341X_BASE + 2
-
-v4l2_mpeg_cx2341x_video_luma_spatial_filter_type = enum
-(
- V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
- V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
- V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT,
- V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE,
- V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
-) = range(5)
-
-V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE = V4L2_CID_MPEG_CX2341X_BASE + 3
-
-v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type = enum
-(
- V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
- V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
-) = range(2)
-
-V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE = V4L2_CID_MPEG_CX2341X_BASE + 4
-
-v4l2_mpeg_cx2341x_video_temporal_filter_mode = enum
-(
- V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
- V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO,
-) = range(2)
-
-V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER = V4L2_CID_MPEG_CX2341X_BASE + 5
-V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE = V4L2_CID_MPEG_CX2341X_BASE + 6
-
-v4l2_mpeg_cx2341x_video_median_filter_type = enum
-(
- V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
- V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR,
- V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT,
- V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT,
- V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG,
-) = range(5)
-
-V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM = V4L2_CID_MPEG_CX2341X_BASE + 7
-V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP = V4L2_CID_MPEG_CX2341X_BASE + 8
-V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM = V4L2_CID_MPEG_CX2341X_BASE + 9
-V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP = V4L2_CID_MPEG_CX2341X_BASE + 10
-V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS = V4L2_CID_MPEG_CX2341X_BASE + 11
-
-V4L2_CID_CAMERA_CLASS_BASE = V4L2_CTRL_CLASS_CAMERA | 0x900
-V4L2_CID_CAMERA_CLASS = V4L2_CTRL_CLASS_CAMERA | 1
-
-V4L2_CID_EXPOSURE_AUTO = V4L2_CID_CAMERA_CLASS_BASE + 1
-
-v4l2_exposure_auto_type = enum
-(
- V4L2_EXPOSURE_AUTO,
- V4L2_EXPOSURE_MANUAL,
- V4L2_EXPOSURE_SHUTTER_PRIORITY,
- V4L2_EXPOSURE_APERTURE_PRIORITY,
-) = range(4)
-
-V4L2_CID_EXPOSURE_ABSOLUTE = V4L2_CID_CAMERA_CLASS_BASE + 2
-V4L2_CID_EXPOSURE_AUTO_PRIORITY = V4L2_CID_CAMERA_CLASS_BASE + 3
-
-V4L2_CID_PAN_RELATIVE = V4L2_CID_CAMERA_CLASS_BASE + 4
-V4L2_CID_TILT_RELATIVE = V4L2_CID_CAMERA_CLASS_BASE + 5
-V4L2_CID_PAN_RESET = V4L2_CID_CAMERA_CLASS_BASE + 6
-V4L2_CID_TILT_RESET = V4L2_CID_CAMERA_CLASS_BASE + 7
-
-V4L2_CID_PAN_ABSOLUTE = V4L2_CID_CAMERA_CLASS_BASE + 8
-V4L2_CID_TILT_ABSOLUTE = V4L2_CID_CAMERA_CLASS_BASE + 9
-
-V4L2_CID_FOCUS_ABSOLUTE = V4L2_CID_CAMERA_CLASS_BASE + 10
-V4L2_CID_FOCUS_RELATIVE = V4L2_CID_CAMERA_CLASS_BASE + 11
-V4L2_CID_FOCUS_AUTO = V4L2_CID_CAMERA_CLASS_BASE + 12
-
-V4L2_CID_ZOOM_ABSOLUTE = V4L2_CID_CAMERA_CLASS_BASE + 13
-V4L2_CID_ZOOM_RELATIVE = V4L2_CID_CAMERA_CLASS_BASE + 14
-V4L2_CID_ZOOM_CONTINUOUS = V4L2_CID_CAMERA_CLASS_BASE + 15
-
-V4L2_CID_PRIVACY = V4L2_CID_CAMERA_CLASS_BASE + 16
-
-V4L2_CID_FM_TX_CLASS_BASE = V4L2_CTRL_CLASS_FM_TX | 0x900
-V4L2_CID_FM_TX_CLASS = V4L2_CTRL_CLASS_FM_TX | 1
-
-V4L2_CID_RDS_TX_DEVIATION = V4L2_CID_FM_TX_CLASS_BASE + 1
-V4L2_CID_RDS_TX_PI = V4L2_CID_FM_TX_CLASS_BASE + 2
-V4L2_CID_RDS_TX_PTY = V4L2_CID_FM_TX_CLASS_BASE + 3
-V4L2_CID_RDS_TX_PS_NAME = V4L2_CID_FM_TX_CLASS_BASE + 5
-V4L2_CID_RDS_TX_RADIO_TEXT = V4L2_CID_FM_TX_CLASS_BASE + 6
-
-V4L2_CID_AUDIO_LIMITER_ENABLED = V4L2_CID_FM_TX_CLASS_BASE + 64
-V4L2_CID_AUDIO_LIMITER_RELEASE_TIME = V4L2_CID_FM_TX_CLASS_BASE + 65
-V4L2_CID_AUDIO_LIMITER_DEVIATION = V4L2_CID_FM_TX_CLASS_BASE + 66
-
-V4L2_CID_AUDIO_COMPRESSION_ENABLED = V4L2_CID_FM_TX_CLASS_BASE + 80
-V4L2_CID_AUDIO_COMPRESSION_GAIN = V4L2_CID_FM_TX_CLASS_BASE + 81
-V4L2_CID_AUDIO_COMPRESSION_THRESHOLD = V4L2_CID_FM_TX_CLASS_BASE + 82
-V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME = V4L2_CID_FM_TX_CLASS_BASE + 83
-V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME = V4L2_CID_FM_TX_CLASS_BASE + 84
-
-V4L2_CID_PILOT_TONE_ENABLED = V4L2_CID_FM_TX_CLASS_BASE + 96
-V4L2_CID_PILOT_TONE_DEVIATION = V4L2_CID_FM_TX_CLASS_BASE + 97
-V4L2_CID_PILOT_TONE_FREQUENCY = V4L2_CID_FM_TX_CLASS_BASE + 98
-
-V4L2_CID_TUNE_PREEMPHASIS = V4L2_CID_FM_TX_CLASS_BASE + 112
-
-v4l2_preemphasis = enum
-(
- V4L2_PREEMPHASIS_DISABLED,
- V4L2_PREEMPHASIS_50_uS,
- V4L2_PREEMPHASIS_75_uS,
-) = range(3)
-
-V4L2_CID_TUNE_POWER_LEVEL = V4L2_CID_FM_TX_CLASS_BASE + 113
-V4L2_CID_TUNE_ANTENNA_CAPACITOR = V4L2_CID_FM_TX_CLASS_BASE + 114
-
-
-#
-# Tuning
-#
-
-class v4l2_tuner(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('type', v4l2_tuner_type),
- ('capability', ctypes.c_uint32),
- ('rangelow', ctypes.c_uint32),
- ('rangehigh', ctypes.c_uint32),
- ('rxsubchans', ctypes.c_uint32),
- ('audmode', ctypes.c_uint32),
- ('signal', ctypes.c_int32),
- ('afc', ctypes.c_int32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-class v4l2_modulator(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('capability', ctypes.c_uint32),
- ('rangelow', ctypes.c_uint32),
- ('rangehigh', ctypes.c_uint32),
- ('txsubchans', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-V4L2_TUNER_CAP_LOW = 0x0001
-V4L2_TUNER_CAP_NORM = 0x0002
-V4L2_TUNER_CAP_STEREO = 0x0010
-V4L2_TUNER_CAP_LANG2 = 0x0020
-V4L2_TUNER_CAP_SAP = 0x0020
-V4L2_TUNER_CAP_LANG1 = 0x0040
-V4L2_TUNER_CAP_RDS = 0x0080
-
-V4L2_TUNER_SUB_MONO = 0x0001
-V4L2_TUNER_SUB_STEREO = 0x0002
-V4L2_TUNER_SUB_LANG2 = 0x0004
-V4L2_TUNER_SUB_SAP = 0x0004
-V4L2_TUNER_SUB_LANG1 = 0x0008
-V4L2_TUNER_SUB_RDS = 0x0010
-
-V4L2_TUNER_MODE_MONO = 0x0000
-V4L2_TUNER_MODE_STEREO = 0x0001
-V4L2_TUNER_MODE_LANG2 = 0x0002
-V4L2_TUNER_MODE_SAP = 0x0002
-V4L2_TUNER_MODE_LANG1 = 0x0003
-V4L2_TUNER_MODE_LANG1_LANG2 = 0x0004
-
-
-class v4l2_frequency(ctypes.Structure):
- _fields_ = [
- ('tuner', ctypes.c_uint32),
- ('type', v4l2_tuner_type),
- ('frequency', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 8),
- ]
-
-
-class v4l2_hw_freq_seek(ctypes.Structure):
- _fields_ = [
- ('tuner', ctypes.c_uint32),
- ('type', v4l2_tuner_type),
- ('seek_upward', ctypes.c_uint32),
- ('wrap_around', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 8),
- ]
-
-
-#
-# RDS
-#
-
-class v4l2_rds_data(ctypes.Structure):
- _fields_ = [
- ('lsb', ctypes.c_char),
- ('msb', ctypes.c_char),
- ('block', ctypes.c_char),
- ]
-
- _pack_ = True
-
-
-V4L2_RDS_BLOCK_MSK = 0x7
-V4L2_RDS_BLOCK_A = 0
-V4L2_RDS_BLOCK_B = 1
-V4L2_RDS_BLOCK_C = 2
-V4L2_RDS_BLOCK_D = 3
-V4L2_RDS_BLOCK_C_ALT = 4
-V4L2_RDS_BLOCK_INVALID = 7
-
-V4L2_RDS_BLOCK_CORRECTED = 0x40
-V4L2_RDS_BLOCK_ERROR = 0x80
-
-
-#
-# Audio
-#
-
-class v4l2_audio(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('capability', ctypes.c_uint32),
- ('mode', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
-
-V4L2_AUDCAP_STEREO = 0x00001
-V4L2_AUDCAP_AVL = 0x00002
-
-V4L2_AUDMODE_AVL = 0x00001
-
-
-class v4l2_audioout(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ('capability', ctypes.c_uint32),
- ('mode', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
-
-#
-# Mpeg services (experimental)
-#
-
-V4L2_ENC_IDX_FRAME_I = 0
-V4L2_ENC_IDX_FRAME_P = 1
-V4L2_ENC_IDX_FRAME_B = 2
-V4L2_ENC_IDX_FRAME_MASK = 0xf
-
-
-class v4l2_enc_idx_entry(ctypes.Structure):
- _fields_ = [
- ('offset', ctypes.c_uint64),
- ('pts', ctypes.c_uint64),
- ('length', ctypes.c_uint32),
- ('flags', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
-
-V4L2_ENC_IDX_ENTRIES = 64
-
-
-class v4l2_enc_idx(ctypes.Structure):
- _fields_ = [
- ('entries', ctypes.c_uint32),
- ('entries_cap', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ('entry', v4l2_enc_idx_entry * V4L2_ENC_IDX_ENTRIES),
- ]
-
-
-V4L2_ENC_CMD_START = 0
-V4L2_ENC_CMD_STOP = 1
-V4L2_ENC_CMD_PAUSE = 2
-V4L2_ENC_CMD_RESUME = 3
-
-V4L2_ENC_CMD_STOP_AT_GOP_END = 1 << 0
-
-
-class v4l2_encoder_cmd(ctypes.Structure):
- class _u(ctypes.Union):
- class _s(ctypes.Structure):
- _fields_ = [
- ('data', ctypes.c_uint32 * 8),
- ]
-
- _fields_ = [
- ('raw', _s),
- ]
-
- _fields_ = [
- ('cmd', ctypes.c_uint32),
- ('flags', ctypes.c_uint32),
- ('_u', _u),
- ]
-
- _anonymous_ = ('_u',)
-
-
-#
-# Data services (VBI)
-#
-
-class v4l2_vbi_format(ctypes.Structure):
- _fields_ = [
- ('sampling_rate', ctypes.c_uint32),
- ('offset', ctypes.c_uint32),
- ('samples_per_line', ctypes.c_uint32),
- ('sample_format', ctypes.c_uint32),
- ('start', ctypes.c_int32 * 2),
- ('count', ctypes.c_uint32 * 2),
- ('flags', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
-
-V4L2_VBI_UNSYNC = 1 << 0
-V4L2_VBI_INTERLACED = 1 << 1
-
-
-class v4l2_sliced_vbi_format(ctypes.Structure):
- _fields_ = [
- ('service_set', ctypes.c_uint16),
- ('service_lines', ctypes.c_uint16 * 2 * 24),
- ('io_size', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 2),
- ]
-
-
-V4L2_SLICED_TELETEXT_B = 0x0001
-V4L2_SLICED_VPS = 0x0400
-V4L2_SLICED_CAPTION_525 = 0x1000
-V4L2_SLICED_WSS_625 = 0x4000
-V4L2_SLICED_VBI_525 = V4L2_SLICED_CAPTION_525
-V4L2_SLICED_VBI_625 = (
- V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
-
-
-class v4l2_sliced_vbi_cap(ctypes.Structure):
- _fields_ = [
- ('service_set', ctypes.c_uint16),
- ('service_lines', ctypes.c_uint16 * 2 * 24),
- ('type', v4l2_buf_type),
- ('reserved', ctypes.c_uint32 * 3),
- ]
-
-
-class v4l2_sliced_vbi_data(ctypes.Structure):
- _fields_ = [
- ('id', ctypes.c_uint32),
- ('field', ctypes.c_uint32),
- ('line', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32),
- ('data', ctypes.c_char * 48),
- ]
-
-
-#
-# Sliced VBI data inserted into MPEG Streams
-#
-
-
-V4L2_MPEG_VBI_IVTV_TELETEXT_B = 1
-V4L2_MPEG_VBI_IVTV_CAPTION_525 = 4
-V4L2_MPEG_VBI_IVTV_WSS_625 = 5
-V4L2_MPEG_VBI_IVTV_VPS = 7
-
-
-class v4l2_mpeg_vbi_itv0_line(ctypes.Structure):
- _fields_ = [
- ('id', ctypes.c_char),
- ('data', ctypes.c_char * 42),
- ]
-
- _pack_ = True
-
-
-class v4l2_mpeg_vbi_itv0(ctypes.Structure):
- _fields_ = [
- ('linemask', ctypes.c_uint32 * 2), # how to define __le32 in ctypes?
- ('line', v4l2_mpeg_vbi_itv0_line * 35),
- ]
-
- _pack_ = True
-
-
-class v4l2_mpeg_vbi_ITV0(ctypes.Structure):
- _fields_ = [
- ('line', v4l2_mpeg_vbi_itv0_line * 36),
- ]
-
- _pack_ = True
-
-
-V4L2_MPEG_VBI_IVTV_MAGIC0 = "itv0"
-V4L2_MPEG_VBI_IVTV_MAGIC1 = "ITV0"
-
-
-class v4l2_mpeg_vbi_fmt_ivtv(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('itv0', v4l2_mpeg_vbi_itv0),
- ('ITV0', v4l2_mpeg_vbi_ITV0),
- ]
-
- _fields_ = [
- ('magic', ctypes.c_char * 4),
- ('_u', _u)
- ]
-
- _anonymous_ = ('_u',)
- _pack_ = True
-
-
-#
-# Aggregate structures
-#
-
-class v4l2_format(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('pix', v4l2_pix_format),
- ('win', v4l2_window),
- ('vbi', v4l2_vbi_format),
- ('sliced', v4l2_sliced_vbi_format),
- ('raw_data', ctypes.c_char * 200),
- ]
-
- _fields_ = [
- ('type', v4l2_buf_type),
- ('fmt', _u),
- ]
-
-
-class v4l2_streamparm(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('capture', v4l2_captureparm),
- ('output', v4l2_outputparm),
- ('raw_data', ctypes.c_char * 200),
- ]
-
- _fields_ = [
- ('type', v4l2_buf_type),
- ('parm', _u)
- ]
-
-
-#
-# Advanced debugging
-#
-
-V4L2_CHIP_MATCH_HOST = 0
-V4L2_CHIP_MATCH_I2C_DRIVER = 1
-V4L2_CHIP_MATCH_I2C_ADDR = 2
-V4L2_CHIP_MATCH_AC97 = 3
-
-
-class v4l2_dbg_match(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('addr', ctypes.c_uint32),
- ('name', ctypes.c_char * 32),
- ]
-
- _fields_ = [
- ('type', ctypes.c_uint32),
- ('_u', _u),
- ]
-
- _anonymous_ = ('_u',)
- _pack_ = True
-
-
-class v4l2_dbg_register(ctypes.Structure):
- _fields_ = [
- ('match', v4l2_dbg_match),
- ('size', ctypes.c_uint32),
- ('reg', ctypes.c_uint64),
- ('val', ctypes.c_uint64),
- ]
-
- _pack_ = True
-
-
-class v4l2_dbg_chip_ident(ctypes.Structure):
- _fields_ = [
- ('match', v4l2_dbg_match),
- ('ident', ctypes.c_uint32),
- ('revision', ctypes.c_uint32),
- ]
-
- _pack_ = True
-
-
-#
-# ioctl codes for video devices
-#
-
-VIDIOC_QUERYCAP = _IOR('V', 0, v4l2_capability)
-VIDIOC_RESERVED = _IO('V', 1)
-VIDIOC_ENUM_FMT = _IOWR('V', 2, v4l2_fmtdesc)
-VIDIOC_G_FMT = _IOWR('V', 4, v4l2_format)
-VIDIOC_S_FMT = _IOWR('V', 5, v4l2_format)
-VIDIOC_REQBUFS = _IOWR('V', 8, v4l2_requestbuffers)
-VIDIOC_QUERYBUF = _IOWR('V', 9, v4l2_buffer)
-VIDIOC_G_FBUF = _IOR('V', 10, v4l2_framebuffer)
-VIDIOC_S_FBUF = _IOW('V', 11, v4l2_framebuffer)
-VIDIOC_OVERLAY = _IOW('V', 14, ctypes.c_int)
-VIDIOC_QBUF = _IOWR('V', 15, v4l2_buffer)
-VIDIOC_DQBUF = _IOWR('V', 17, v4l2_buffer)
-VIDIOC_STREAMON = _IOW('V', 18, ctypes.c_int)
-VIDIOC_STREAMOFF = _IOW('V', 19, ctypes.c_int)
-VIDIOC_G_PARM = _IOWR('V', 21, v4l2_streamparm)
-VIDIOC_S_PARM = _IOWR('V', 22, v4l2_streamparm)
-VIDIOC_G_STD = _IOR('V', 23, v4l2_std_id)
-VIDIOC_S_STD = _IOW('V', 24, v4l2_std_id)
-VIDIOC_ENUMSTD = _IOWR('V', 25, v4l2_standard)
-VIDIOC_ENUMINPUT = _IOWR('V', 26, v4l2_input)
-VIDIOC_G_CTRL = _IOWR('V', 27, v4l2_control)
-VIDIOC_S_CTRL = _IOWR('V', 28, v4l2_control)
-VIDIOC_G_TUNER = _IOWR('V', 29, v4l2_tuner)
-VIDIOC_S_TUNER = _IOW('V', 30, v4l2_tuner)
-VIDIOC_G_AUDIO = _IOR('V', 33, v4l2_audio)
-VIDIOC_S_AUDIO = _IOW('V', 34, v4l2_audio)
-VIDIOC_QUERYCTRL = _IOWR('V', 36, v4l2_queryctrl)
-VIDIOC_QUERYMENU = _IOWR('V', 37, v4l2_querymenu)
-VIDIOC_G_INPUT = _IOR('V', 38, ctypes.c_int)
-VIDIOC_S_INPUT = _IOWR('V', 39, ctypes.c_int)
-VIDIOC_G_OUTPUT = _IOR('V', 46, ctypes.c_int)
-VIDIOC_S_OUTPUT = _IOWR('V', 47, ctypes.c_int)
-VIDIOC_ENUMOUTPUT = _IOWR('V', 48, v4l2_output)
-VIDIOC_G_AUDOUT = _IOR('V', 49, v4l2_audioout)
-VIDIOC_S_AUDOUT = _IOW('V', 50, v4l2_audioout)
-VIDIOC_G_MODULATOR = _IOWR('V', 54, v4l2_modulator)
-VIDIOC_S_MODULATOR = _IOW('V', 55, v4l2_modulator)
-VIDIOC_G_FREQUENCY = _IOWR('V', 56, v4l2_frequency)
-VIDIOC_S_FREQUENCY = _IOW('V', 57, v4l2_frequency)
-VIDIOC_CROPCAP = _IOWR('V', 58, v4l2_cropcap)
-VIDIOC_G_CROP = _IOWR('V', 59, v4l2_crop)
-VIDIOC_S_CROP = _IOW('V', 60, v4l2_crop)
-VIDIOC_G_JPEGCOMP = _IOR('V', 61, v4l2_jpegcompression)
-VIDIOC_S_JPEGCOMP = _IOW('V', 62, v4l2_jpegcompression)
-VIDIOC_QUERYSTD = _IOR('V', 63, v4l2_std_id)
-VIDIOC_TRY_FMT = _IOWR('V', 64, v4l2_format)
-VIDIOC_ENUMAUDIO = _IOWR('V', 65, v4l2_audio)
-VIDIOC_ENUMAUDOUT = _IOWR('V', 66, v4l2_audioout)
-VIDIOC_G_PRIORITY = _IOR('V', 67, v4l2_priority)
-VIDIOC_S_PRIORITY = _IOW('V', 68, v4l2_priority)
-VIDIOC_G_SLICED_VBI_CAP = _IOWR('V', 69, v4l2_sliced_vbi_cap)
-VIDIOC_LOG_STATUS = _IO('V', 70)
-VIDIOC_G_EXT_CTRLS = _IOWR('V', 71, v4l2_ext_controls)
-VIDIOC_S_EXT_CTRLS = _IOWR('V', 72, v4l2_ext_controls)
-VIDIOC_TRY_EXT_CTRLS = _IOWR('V', 73, v4l2_ext_controls)
-
-VIDIOC_ENUM_FRAMESIZES = _IOWR('V', 74, v4l2_frmsizeenum)
-VIDIOC_ENUM_FRAMEINTERVALS = _IOWR('V', 75, v4l2_frmivalenum)
-VIDIOC_G_ENC_INDEX = _IOR('V', 76, v4l2_enc_idx)
-VIDIOC_ENCODER_CMD = _IOWR('V', 77, v4l2_encoder_cmd)
-VIDIOC_TRY_ENCODER_CMD = _IOWR('V', 78, v4l2_encoder_cmd)
-
-VIDIOC_DBG_S_REGISTER = _IOW('V', 79, v4l2_dbg_register)
-VIDIOC_DBG_G_REGISTER = _IOWR('V', 80, v4l2_dbg_register)
-
-VIDIOC_DBG_G_CHIP_IDENT = _IOWR('V', 81, v4l2_dbg_chip_ident)
-
-VIDIOC_S_HW_FREQ_SEEK = _IOW('V', 82, v4l2_hw_freq_seek)
-VIDIOC_ENUM_DV_PRESETS = _IOWR('V', 83, v4l2_dv_enum_preset)
-VIDIOC_S_DV_PRESET = _IOWR('V', 84, v4l2_dv_preset)
-VIDIOC_G_DV_PRESET = _IOWR('V', 85, v4l2_dv_preset)
-VIDIOC_QUERY_DV_PRESET = _IOR('V', 86, v4l2_dv_preset)
-VIDIOC_S_DV_TIMINGS = _IOWR('V', 87, v4l2_dv_timings)
-VIDIOC_G_DV_TIMINGS = _IOWR('V', 88, v4l2_dv_timings)
-
-VIDIOC_OVERLAY_OLD = _IOWR('V', 14, ctypes.c_int)
-VIDIOC_S_PARM_OLD = _IOW('V', 22, v4l2_streamparm)
-VIDIOC_S_CTRL_OLD = _IOW('V', 28, v4l2_control)
-VIDIOC_G_AUDIO_OLD = _IOWR('V', 33, v4l2_audio)
-VIDIOC_G_AUDOUT_OLD = _IOWR('V', 49, v4l2_audioout)
-VIDIOC_CROPCAP_OLD = _IOR('V', 58, v4l2_cropcap)
-
-BASE_VIDIOC_PRIVATE = 192