From 0373970d57b2d56530d79b5af8cb97ab39e8e0b7 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Fri, 18 Feb 2011 13:16:28 +0000 Subject: added plugin mechanisms, camera plugin --- diff --git a/TurtleArt/taconstants.py b/TurtleArt/taconstants.py index f842719..54fc099 100644 --- a/TurtleArt/taconstants.py +++ b/TurtleArt/taconstants.py @@ -224,8 +224,8 @@ BOX_STYLE = ['number', 'xcor', 'ycor', 'heading', 'pensize', 'color', 'shade', 'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'white', 'black', 'titlex', 'titley', 'leftx', 'topy', 'rightx', 'bottomy', 'sound', 'volume', 'pitch', 'voltage', 'resistance', 'gray', 'see', 'rfid', - 'luminance', 'time'] -BOX_STYLE_MEDIA = ['description', 'audio', 'journal', 'video', 'camera'] + 'time'] +BOX_STYLE_MEDIA = ['description', 'audio', 'journal', 'video'] NUMBER_STYLE = ['plus2', 'product2', 'myfunc'] NUMBER_STYLE_VAR_ARG = ['myfunc1arg', 'myfunc2arg', 'myfunc3arg'] NUMBER_STYLE_BLOCK = ['random'] @@ -279,7 +279,7 @@ OLD_DOCK = ['and', 'or', 'plus', 'minus', 'division', 'product', 'remainder'] # Blocks that contain media # CONTENT_BLOCKS = ['number', 'string', 'description', 'audio', 'video', - 'journal', 'camera'] + 'journal'] # # These blocks get a special skin @@ -315,7 +315,6 @@ BLOCK_NAMES = { 'box': [_('box')], 'box1': [_('box 1')], 'box2': [_('box 2')], - 'camera': [' '], 'cartesian': [_('Cartesian')], 'clean': [_(' clean ')], 'clearheap': [_('empty heap')], @@ -355,7 +354,6 @@ BLOCK_NAMES = { 'leftx': [_('picture left')], 'less2': ['<'], 'list': ['list'], - 'luminance': [_('brightness')], 'mediawait': [_('media wait')], 'minus2': ['–'], 'myfunc': [_('Python'), 'f(x)', 'x'], @@ -630,7 +628,6 @@ DEFAULTS = { 'audio': [None], 'back': [100], 'box': [_('my box')], - 'camera': ['CAMERA'], 'comment': [_('comment')], 'description': [None], 'fillscreen': [60, 80], @@ -765,7 +762,6 @@ TEMPLATES = {'t1x1': (0.5, 0.5, 0.0625, 0.125, 1.05, 0), # SPECIAL_NAMES = { 'audio': _('audio'), - 'camera': _('camera'), 'division2': _('divide'), 'equal2': _('equal'), 'greater2': _('greater than'), @@ -805,7 +801,6 @@ HELP_STRINGS = { '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)"), @@ -843,7 +838,6 @@ HELP_STRINGS = { 'leftpos': _("xcor of left of screen"), 'left': _("turns turtle counterclockwise (angle in degrees)"), 'less2': _("logical less-than operator"), - 'luminance': _("light level detected by camera"), 'media': _("Palette of media objects"), 'mediawait': _("wait for current video or audio to complete"), 'minus2': _("subtracts bottom numeric input from top numeric input"), diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py index 421953f..38f2586 100644 --- a/TurtleArt/talogo.py +++ b/TurtleArt/talogo.py @@ -29,8 +29,6 @@ from numpy import append from numpy.fft import rfft from random import uniform from operator import isNumberType -from fcntl import ioctl -import v4l2 import os.path from UserDict import UserDict @@ -55,7 +53,9 @@ from gettext import gettext as _ VALUE_BLOCKS = ['box1', 'box2', 'color', 'shade', 'gray', 'scale', 'pensize', 'heading', 'xcor', 'ycor', 'pop', 'time', 'keyboard', 'sound', - 'volume', 'pitch', 'resistance', 'voltage', 'luminance', 'see'] + 'volume', 'pitch', 'resistance', 'voltage', 'see'] +MEDIA_BLOCKS_DICTIONARY = {} # new media blocks get added here +PLUGIN_DICTIONARY = {} # new block primitives get added here import logging _logger = logging.getLogger('turtleart-activity') @@ -317,6 +317,7 @@ class LogoCode: self.tw = tw self.oblist = {} + # TODO: remove plugin blocks DEFPRIM = { '(': [1, lambda self, x: self._prim_opar(x)], 'and': [2, lambda self, x, y: _and(x, y)], @@ -366,7 +367,6 @@ class LogoCode: '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)], @@ -394,7 +394,6 @@ class LogoCode: '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], @@ -524,25 +523,16 @@ class LogoCode: self.voltage_gain = -0.0001471 self.voltage_bias = 1.695 - if self.tw.camera_available: - if self.tw.running_sugar: - self.imagepath = get_path(self.tw.activity, - 'data/turtlepic.png') - else: - self.imagepath = '/tmp/turtlepic.png' - from tacamera import Camera - 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 p in self.tw._plugins: + print p.stop() if self.tw.gst_available: from tagplay import stop_media stop_media(self) - if self.tw.camera_available: - self.camera.stop_camera_input() - self.tw.active_turtle.show() + self.tw.active_turtle.show() def _def_prim(self, name, args, fcn, rprim=False): """ Define the primitives associated with the blocks """ @@ -633,8 +623,8 @@ class LogoCode: str(blk.values[0])) else: code.append(PREFIX_DICTIONARY[blk.name] + 'None') - elif blk.name == 'camera': - code.append('#smedia_CAMERA') + elif blk.name in MEDIA_BLOCKS_DICTIONARY: + code.append('#smedia_' + blk.name.upper()) else: return ['%nothing%'] else: @@ -1091,7 +1081,8 @@ class LogoCode: 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': + if n[0:6] == 'media_' and \ + n[6:].lower not in MEDIA_BLOCKS_DICTIONARY: try: if self.tw.running_sugar: try: @@ -1325,11 +1316,9 @@ class LogoCode: 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 + print string[6:], MEDIA_BLOCKS_DICTIONARY + if string[6:].lower() in MEDIA_BLOCKS_DICTIONARY: + MEDIA_BLOCKS_DICTIONARY[string[6:].lower()]() elif os.path.exists(string[6:]): # is it a path? self.filepath = string[6:] elif self.tw.running_sugar: # is it a datastore object? @@ -1490,66 +1479,6 @@ class LogoCode: 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 """ - pixbuf = None - array = None - w, h = self._w(), self._h() - if w > 0 and h > 0 and self.tw.camera_available: - try: - self._video_capture_device = open('/dev/video0', 'rw') - except: - self._video_capture_device = None - _logger.debug('video capture device not available') - - if self._video_capture_device is not None: - 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 = 0 # disable AUTOGAIN - ioctl(self._video_capture_device, v4l2.VIDIOC_S_CTRL, - self._ag_control) - except: - _logger.debug('AUTOGAIN control not available') - - 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() - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.imagepath, w, h) - try: - array = pixbuf.get_pixels() - except: - array = None - - 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.update_label_value('luminance', lum) - return lum - else: - self.heap.append(int((b / length))) - self.heap.append(int((g / length))) - self.heap.append(int((r / length))) - else: - if luminance_only: - return -1 - else: - self.heap.append(-1) - self.heap.append(-1) - self.heap.append(-1) - def _get_volume(self): """ return mic in value """ #TODO: Adjust gain for different HW diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py index b67f604..73894e4 100644 --- a/TurtleArt/tawindow.py +++ b/TurtleArt/tawindow.py @@ -105,6 +105,9 @@ _logger = logging.getLogger('turtleart-activity') class TurtleArtWindow(): """ TurtleArt Window class abstraction """ timeout_tag = [0] + _INSTALL_PATH = '/usr/share/turtleart' + _ALTERNATE_INSTALL_PATH = '/usr/local/share/turtleart' + _PLUGIN_SUBPATH = 'plugins' def __init__(self, win, path, parent=None, mycolors=None, mynick=None): self._loaded_project = '' @@ -276,18 +279,13 @@ class TurtleArtWindow(): PALETTES[PALETTE_NAMES.index('sensor')].append('voltage') self.audio_started = False - self.camera_available = False - if self.gst_available: - 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._plugins = [] + self._init_plugins() self.lc = LogoCode(self) - self.saved_pictures = [] + self._run_plugins() + self.saved_pictures = [] self.block_operation = '' """ @@ -324,6 +322,60 @@ class TurtleArtWindow(): PALETTES[PALETTE_NAMES.index('sensor')].append('rfid') + #### + + def _get_plugin_home(self): + """ Look in current directory first, then usual places """ + path = os.path.join(os.getcwd(), self._PLUGIN_SUBPATH) + if os.path.exists(path): + return path + path = os.path.expanduser(os.path.join('~', 'Activities', + 'TurtleBlocks.activity', + self._PLUGIN_SUBPATH)) + if os.path.exists(path): + return path + path = os.path.expanduser(os.path.join('~', 'Activities', + 'TurtleArt.activity', + self._PLUGIN_SUBPATH)) + if os.path.exists(path): + return path + path = os.path.join(self._INSTALL_PATH, self._PLUGIN_SUBPATH) + if os.path.exists(path): + return path + path = os.path.join(self._ALTERNATE_INSTALL_PATH, + self._PLUGIN_SUBPATH) + if os.path.exists(path): + return path + return None + + def _get_plugin_candidates(self, path): + """ Look for plugin files in plugin directory. """ + plugin_files = [] + if path is not None: + candidates = os.listdir(path) + for c in candidates: + if c[-10:] == '_plugin.py' and c[0] != '#' and c[0] != '.': + plugin_files.append(c.split('.')[0]) + return plugin_files + + def _init_plugins(self): + for p in self._get_plugin_candidates(self._get_plugin_home()): + P = p.capitalize() + f = "def f(self): from plugins.%s import %s; return %s(self)" \ + % (p, P, P) + plugin = {} + try: + exec f in globals(), plugin + self._plugins.append(plugin.values()[0](self)) + except ImportError: + print 'failed to import %s' % (P) + + def _run_plugins(self): + for p in self._plugins: + p.setup() + + #### + def _device_added_cb(self, path): """ Called from hal connection when a new device is plugged. @@ -1602,6 +1654,7 @@ class TurtleArtWindow(): blk.spr.labels[0] += CURSOR elif blk.name in 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) @@ -2533,6 +2586,7 @@ class TurtleArtWindow(): else: self._block_skin('pythonoff', blk) elif btype in 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) -- cgit v0.9.1