Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS12
-rw-r--r--TurtleArt/talogo.py32
-rw-r--r--TurtleArt/tawindow.py1
-rw-r--r--TurtleArtActivity.py2
-rw-r--r--activity/activity.info2
-rw-r--r--plugins/camera_sensor/camera_sensor.py141
-rw-r--r--plugins/camera_sensor/tacamera.py40
-rw-r--r--plugins/turtle_blocks_extras/turtle_blocks_extras.py28
8 files changed, 146 insertions, 112 deletions
diff --git a/NEWS b/NEWS
index 35cea31..e85d758 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,19 @@
+127
+
+ENHANCEMENTS:
+* Changed mouse click block to mouse-button down block
+* Improved camera plugin: writing directly to a pixbuf
+
+BUG FIXES:
+* Fixed problem with missing help strings on XO hardware
+
126
ENHANCEMENTS
* Added speak block to media palette
+* Added sinewave block to media palette
* Added mouse x, y, and click blocks to sensor palette
-* Added plugin support for clear method attached to Clean block and
+* Added plugin support for clear method attached to clean block and
Erase button.
125
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py
index 0e28cf0..8f2b599 100644
--- a/TurtleArt/talogo.py
+++ b/TurtleArt/talogo.py
@@ -122,6 +122,7 @@ class LogoCode:
self.update_values = False
self.gplay = None
self.filepath = None
+ self.pixbuf = None
self.dsobject = None
self.start_time = None
@@ -562,50 +563,55 @@ class LogoCode:
return int((self.tw.canvas.height * self.scale) / 100.)
def insert_image(self, center=False, filepath=None, resize=True,
- offset=False):
+ offset=False, pixbuf=False):
""" Image only (at current x, y) """
if filepath is not None:
self.filepath = filepath
- pixbuf = None
+ if not pixbuf:
+ self.pixbuf = None
w, h = self.wpercent(), self.hpercent()
if w < 1 or h < 1:
return
- if self.dsobject is not None:
+ if pixbuf: # We may have to rescale the picture
+ if w != self.pixbuf.get_width() or h != self.pixbuf.get_height():
+ self.pixbuf = self.pixbuf.scale_simple(
+ w, h, gtk.gdk.INTERP_BILINEAR)
+ elif self.dsobject is not None:
try:
- pixbuf = get_pixbuf_from_journal(self.dsobject, w, h)
+ self.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 \
+ if self.pixbuf is None and \
self.filepath is not None and \
self.filepath != '':
try:
if not resize:
- pixbuf = gtk.gdk.pixbuf_new_from_file(self.filepath)
- w = pixbuf.get_width()
- h = pixbuf.get_height()
+ self.pixbuf = gtk.gdk.pixbuf_new_from_file(self.filepath)
+ w = self.pixbuf.get_width()
+ h = self.pixbuf.get_height()
else:
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
+ self.pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
self.filepath, w, h)
except:
self.tw.showlabel('nojournal', self.filepath)
debug_output("Couldn't open filepath %s" % (self.filepath),
self.tw.running_sugar)
- if pixbuf is not None:
+ if self.pixbuf is not None:
x = self.tw.canvas.xcor
y = self.tw.canvas.ycor
w *= self.tw.coord_scale
h *= self.tw.coord_scale
if center:
- self.tw.canvas.draw_pixbuf(pixbuf, 0, 0,
+ self.tw.canvas.draw_pixbuf(self.pixbuf, 0, 0,
self.x2tx() - int(w / 2),
self.y2ty() - int(h / 2), w, h,
self.filepath)
elif offset:
- self.tw.canvas.draw_pixbuf(pixbuf, 0, 0, self.x2tx(),
+ self.tw.canvas.draw_pixbuf(self.pixbuf, 0, 0, self.x2tx(),
self.y2ty() - h, w, h, self.filepath)
else:
- self.tw.canvas.draw_pixbuf(pixbuf, 0, 0,
+ self.tw.canvas.draw_pixbuf(self.pixbuf, 0, 0,
self.x2tx(),
self.y2ty(),
w, h, self.filepath)
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py
index 4b097fb..a5d1a37 100644
--- a/TurtleArt/tawindow.py
+++ b/TurtleArt/tawindow.py
@@ -1661,6 +1661,7 @@ class TurtleArtWindow():
def _buttonrelease_cb(self, win, event):
""" Button release """
x, y = xy(event)
+ self.mouse_flag = 0
self.mouse_x = x
self.mouse_y = y
self.button_release(x, y)
diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py
index 0e0f2cd..daba8f9 100644
--- a/TurtleArtActivity.py
+++ b/TurtleArtActivity.py
@@ -569,7 +569,7 @@ class TurtleArtActivity(activity.Activity):
''' The help toolbar must be setup we determine what hardware
is in use. '''
# FIXME: Temporary work-around gtk problem with XO175
- if get_hardware() not in [XO175] and \
+ if get_hardware() not in [XO1, XO15, XO175] and \
(gtk.gtk_version[0] > 2 or gtk.gtk_version[1] > 16):
self.hover_help_label = self._add_label(
_('Move the cursor over the orange palette for help.'),
diff --git a/activity/activity.info b/activity/activity.info
index ed61836..142badf 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -1,6 +1,6 @@
[Activity]
name = Turtle Art
-activity_version = 126
+activity_version = 127
license = MIT
bundle_id = org.laptop.TurtleArtActivity
exec = sugar-activity TurtleArtActivity.TurtleArtActivity
diff --git a/plugins/camera_sensor/camera_sensor.py b/plugins/camera_sensor/camera_sensor.py
index 5bd21ee..bb9698f 100644
--- a/plugins/camera_sensor/camera_sensor.py
+++ b/plugins/camera_sensor/camera_sensor.py
@@ -19,6 +19,8 @@ import gst
import gtk
from fcntl import ioctl
import os
+from time import time
+
from gettext import gettext as _
from plugins.camera_sensor.tacamera import Camera
@@ -37,22 +39,18 @@ from TurtleArt.taconstants import MEDIA_SHAPES, NO_IMPORT, SKIN_PATHS, \
class Camera_sensor(Plugin):
def __init__(self, parent):
+ ''' Make sure there is a camera device '''
self._parent = parent
self._status = False
- self._camera = None
+ self.function = None
+ self.camera = None
v4l2src = gst.element_factory_make('v4l2src')
if v4l2src.props.device_name is not None:
-
- if self._parent.running_sugar:
- self._imagepath = get_path(self._parent.activity,
- 'data/turtlepic.png')
- else:
- self._imagepath = '/tmp/turtlepic.png'
-
self._status = True
def setup(self):
+ ''' Set up the palettes '''
palette = make_palette('sensor',
colors=["#FF6060", "#A06060"],
help_string=_('Palette of sensor blocks'))
@@ -134,13 +132,18 @@ is pushed to the stack'),
''' Initialize the camera if there is an camera block in use '''
if len(self._parent.block_list.get_similar_blocks('block',
['camera', 'read_camera', 'luminance'])) > 0:
- if self._status and self._camera is None:
- self._camera = Camera(self._imagepath)
+ if self._status and self.camera is None:
+ self.camera = Camera()
def stop(self):
''' This gets called by the stop button '''
- if self._status and self._camera is not None:
- self._camera.stop_camera_input()
+ if self._status and self.camera is not None:
+ self.camera.stop_camera_input()
+
+ def clear(self):
+ ''' This gets called by the clean button and erase button '''
+ if self._status and self.camera is not None:
+ self.camera.stop_camera_input()
def _status_report(self):
debug_output('Reporting camera status: %s' % (str(self._status)),
@@ -150,19 +153,15 @@ is pushed to the stack'),
# Block primitives used in talogo
def prim_take_picture(self):
- if self._status:
- ''' method called by media block '''
- self._camera.save_camera_input_to_file()
- self._camera.stop_camera_input()
- self._parent.lc.filepath = self._imagepath
- else:
- self._parent.lc.filepath = os.path.join(
- self._parent.path, 'samples', 'images', 'me.jpg')
+ ''' method called by media block '''
+ self._get_pixbuf_from_camera()
+ self._parent.lc.pixbuf = self.camera.pixbuf
def prim_read_camera(self, luminance_only=False):
""" Read average pixel from camera and push b, g, r to the stack """
+ self.luminance_only = luminance_only
if not self._status:
- if luminance_only:
+ if self.luminance_only:
return -1
else:
self._parent.lc.heap.append(-1)
@@ -170,52 +169,64 @@ is pushed to the stack'),
self._parent.lc.heap.append(-1)
return
- pixbuf = None
array = None
+ try:
+ self._video_capture_device = open('/dev/video0', 'rw')
+ except:
+ self._video_capture_device = None
+ debug_output('video capture device not available',
+ self._parent.running_sugar)
+ self._set_autogain(0) # disable AUTOGAIN
+ self._get_pixbuf_from_camera()
+ self.calc_luminance()
+ if self.luminance_only:
+ self._parent.lc.update_label_value('luminance', self.luminance)
+ return self.luminance
+ else:
+ self._parent.lc.heap.append(self.b)
+ self._parent.lc.heap.append(self.g)
+ self._parent.lc.heap.append(self.r)
- if self._status:
- try:
- self._video_capture_device = open('/dev/video0', 'rw')
- except:
- self._video_capture_device = None
- debug_output('video capture device not available',
- self._parent.running_sugar)
-
- self._set_autogain(0) # disable AUTOGAIN
-
- pixbuf = self._get_pixbuf_from_camera()
- try:
- array = pixbuf.get_pixels()
- except:
- array = None
-
- self._set_autogain(1) # reenable AUTOGAIN
+ def calc_luminance(self):
+ array = self.camera.pixbuf.get_pixels()
+ width = self.camera.pixbuf.get_width()
+ height = self.camera.pixbuf.get_height()
+ self._set_autogain(1) # reenable AUTOGAIN
if array is not None:
- length = len(array) / 3
- r, g, b, i = 0, 0, 0, 0
- for j in range(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) / length)
- self._parent.lc.update_label_value('luminance', lum)
- return lum
+ length = int(len(array) / 3)
+ if length != width * height:
+ debug_output('array length != width x height (%d != %dx%d)' % \
+ (length, width, height),
+ self._parent.running_sugar)
+
+ # Average the 100 pixels in the center of the screen
+ r, g, b = 0, 0, 0
+ row_offset = int((height / 2 - 5) * width * 3)
+ column_offset = int(width / 2 - 5) * 3
+ for y in range(10):
+ i = row_offset + column_offset
+ for x in range(10):
+ r += ord(array[i])
+ i += 1
+ g += ord(array[i])
+ i += 1
+ b += ord(array[i])
+ i += 1
+ row_offset += width * 3
+ if self.luminance_only:
+ self.luminance = int((r * 0.3 + g * 0.6 + b * 0.1) / 100)
else:
- self._parent.lc.heap.append(int((b / length)))
- self._parent.lc.heap.append(int((g / length)))
- self._parent.lc.heap.append(int((r / length)))
+ self.r = int(r / 100)
+ self.g = int(g / 100)
+ self.b = int(b / 100)
else:
- if luminance_only:
- return -1
+ if self.luminance_only:
+ self.luminance = -1
else:
- self._parent.lc.heap.append(-1)
- self._parent.lc.heap.append(-1)
- self._parent.lc.heap.append(-1)
+ self.r = -1
+ self.g = -1
+ self.b = -1
def _set_autogain(self, state):
''' 0 is off; 1 is on '''
@@ -232,10 +243,6 @@ is pushed to the stack'),
def _get_pixbuf_from_camera(self):
''' Regardless of how we get it, we want to return a pixbuf '''
- if self._video_capture_device is not None:
- self._video_capture_device.close()
- self._camera.save_camera_input_to_file()
- self._camera.stop_camera_input()
- return gtk.gdk.pixbuf_new_from_file(self._imagepath)
- else:
- return None
+ self._parent.lc.pixbuf = None
+ if self._status:
+ self.camera.start_camera_input()
diff --git a/plugins/camera_sensor/tacamera.py b/plugins/camera_sensor/tacamera.py
index 15824a1..5a6f506 100644
--- a/plugins/camera_sensor/tacamera.py
+++ b/plugins/camera_sensor/tacamera.py
@@ -21,33 +21,41 @@
#THE SOFTWARE.
import gst, time
+import gobject
+
+from TurtleArt.tautils import debug_output
+
+GST_PIPE = ['v4l2src', 'ffmpegcolorspace', 'gdkpixbufsink']
-GST_PIPE = ['v4l2src', 'ffmpegcolorspace', 'pngenc']
-# GST_PIPE = ['v4l2src', 'ffmpegcolorspace', 'gdkpixbufsink']
class Camera():
- """ A class for representing the video camera """
+ ''' Sets up a pipe from the camera to a pixbuf and emits a signal
+ when the image is ready. '''
- def __init__(self, imagepath):
- # self.imagepath = imagepath
- GST_PIPE.append('filesink location=%s' % imagepath)
- self.pipe = gst.parse_launch('!'.join(GST_PIPE))
- self.bus = self.pipe.get_bus()
- # self.bus.add_signal_watch()
- # self.bus.connect('message', self._on_message)
+ def __init__(self):
+ ''' Prepare camera pipeline to pixbuf and signal watch '''
+ self.pipe = gst.parse_launch('!'.join(GST_PIPE))
+ self.bus = self.pipe.get_bus()
+ self.bus.add_signal_watch()
+ self.bus.connect('message', self._on_message)
def _on_message(self, bus, message):
''' We get a message if a pixbuf is available '''
if message.structure is not None:
- print message.structure.get_name()
+ # debug_output(message.structure.get_name(), True)
if message.structure.get_name() == 'pixbuf':
- message.structure['pixbuf'].save(self.imagepath, 'png')
+ self.pixbuf = message.structure['pixbuf']
+ self.image_ready = True
- def save_camera_input_to_file(self):
- """ Grab a frame from the camera """
+ def start_camera_input(self):
+ ''' Start grabbing '''
+ self.pixbuf = None
+ self.image_ready = False
self.pipe.set_state(gst.STATE_PLAYING)
- self.bus.poll(gst.MESSAGE_EOS, -1)
+ while not self.image_ready:
+ self.bus.poll(gst.MESSAGE_ANY, -1)
+ # self.stop_camera_input()
def stop_camera_input(self):
+ ''' Stop grabbing '''
self.pipe.set_state(gst.STATE_NULL)
-
diff --git a/plugins/turtle_blocks_extras/turtle_blocks_extras.py b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
index e5473e6..1406407 100644
--- a/plugins/turtle_blocks_extras/turtle_blocks_extras.py
+++ b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
@@ -287,16 +287,16 @@ amplitude, and duration (in seconds)'))
colors=["#FF6060", "#A06060"],
help_string=_('Palette of sensor blocks'))
- primitive_dictionary['mouseclick'] = self._prim_mouse_click
- palette.add_block('mouseclick',
+ primitive_dictionary['mousebutton'] = self._prim_mouse_button
+ palette.add_block('mousebutton',
style='box-style',
- label=_('click'),
- prim_name='mouseclick',
+ label=_('button down'),
+ prim_name='mousebutton',
value_block=True,
- help_string=_('returns 1 if mouse button has been \
-clicked'))
- self.tw.lc.def_prim('mouseclick', 0,
- lambda self: primitive_dictionary['mouseclick']())
+ help_string=_('returns 1 if mouse button is \
+pressed'))
+ self.tw.lc.def_prim('mousebutton', 0,
+ lambda self: primitive_dictionary['mousebutton']())
palette.add_block('mousex',
style='box-style',
@@ -1156,10 +1156,9 @@ bullets'))
csd.write("\n</CsoundSynthesizer>")
csd.close()
- def _prim_mouse_click(self):
- """ Return 1 if mouse button has been pressed """
+ def _prim_mouse_button(self):
+ """ Return 1 if mouse button is pressed """
if self.tw.mouse_flag == 1:
- self.tw.mouse_flag = 0
return 1
else:
return 0
@@ -1186,6 +1185,7 @@ bullets'))
pass
elif string[0:6] in ['media_', 'descr_', 'audio_', 'video_']:
self.tw.lc.filepath = None
+ self.tw.lc.pixbuf = None # Camera writes directly to pixbuf
self.tw.lc.dsobject = None
if string[6:].lower() in media_blocks_dictionary:
media_blocks_dictionary[string[6:].lower()]()
@@ -1200,7 +1200,9 @@ bullets'))
string[6:]), self.tw.running_sugar)
if self.tw.lc.dsobject is not None:
self.tw.lc.filepath = self.tw.lc.dsobject.file_path
- if self.tw.lc.filepath == None:
+ if self.tw.lc.pixbuf is not None:
+ self.tw.lc.insert_image(center=center, pixbuf=True)
+ elif self.tw.lc.filepath is None:
if self.tw.lc.dsobject is not None:
self.tw.showlabel('nojournal',
self.tw.lc.dsobject.metadata['title'])
@@ -1209,7 +1211,7 @@ bullets'))
debug_output("Couldn't open %s" % (string[6:]),
self.tw.running_sugar)
elif string[0:6] == 'media_':
- self.tw.lc.insert_image(center)
+ self.tw.lc.insert_image(center=center)
elif string[0:6] == 'descr_':
mimetype = None
if self.tw.lc.dsobject is not None and \