From 3144ede59345548ebfd5c1bfe339e912ee8d51a0 Mon Sep 17 00:00:00 2001 From: Pootle daemon Date: Mon, 21 Nov 2011 05:32:10 +0000 Subject: Merge branch 'master' of git.sugarlabs.org:turtleart/mainline --- 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") 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 \ -- cgit v0.9.1