diff options
Diffstat (limited to 'tutorius')
-rw-r--r-- | tutorius/addon.py | 13 | ||||
-rw-r--r-- | tutorius/properties.py | 23 | ||||
-rw-r--r-- | tutorius/propwidgets.py | 110 |
3 files changed, 142 insertions, 4 deletions
diff --git a/tutorius/addon.py b/tutorius/addon.py index ca729ae..1fd5143 100644 --- a/tutorius/addon.py +++ b/tutorius/addon.py @@ -78,9 +78,16 @@ def create(name, *args, **kwargs): comp_metadata = _cache[name] try: return comp_metadata['class'](*args, **kwargs) - except: - logging.debug("Could not instantiate %s with parameters %s, %s"%(comp_metadata['name'],str(args), str(kwargs))) - return None + except Exception, e: + LOGGER.error("Could not instantiate %s with parameters %s, %s"%\ + (comp_metadata['name'],str(args), str(kwargs))) + + # fetch frame information to complement exception with traceback + type, value, tb = sys.exc_info() + formatted_tb = traceback.format_tb(tb) + LOGGER.error('Error loadin tutorius add-on named [%s]:\n%s\n%s' % \ + (name, '\n'.join(formatted_tb), str(e))) + return None except KeyError: logging.debug("Addon not found for class '%s'", name) return None diff --git a/tutorius/properties.py b/tutorius/properties.py index b363a2a..1905117 100644 --- a/tutorius/properties.py +++ b/tutorius/properties.py @@ -37,7 +37,8 @@ from .propwidgets import PropWidget, \ IntPropWidget, \ FloatPropWidget, \ IntArrayPropWidget, \ - ResourcePropWidget + ResourcePropWidget, \ + ScreenClipPropWidget import logging LOGGER = logging.getLogger("properties") @@ -390,6 +391,26 @@ class TResourceProperty(TutoriusProperty): self.default = self.validate("") +class TScreenClipProperty(TResourceProperty): + """ + Represents an image resource from a screen capture + + When the system encounters a resource, it knows that it refers to a file in + the resource folder and that it should translate this resource name to an + absolute file name before it is executed. + """ + + widget_class = ScreenClipPropWidget + + def __init__(self, *args, **kwargs): + """ + Creates a new resource pointing to an existing resource. + + @param resource_name The file name of the resource (should be only the + file name itself, no directory information) + """ + super(TScreenClipProperty, self).__init__(*args, **kwargs) + class TEnumProperty(TutoriusProperty): """ Represents a value in a given enumeration. This means that the value will diff --git a/tutorius/propwidgets.py b/tutorius/propwidgets.py index 3debf98..0e6c200 100644 --- a/tutorius/propwidgets.py +++ b/tutorius/propwidgets.py @@ -24,6 +24,8 @@ from jarabe.journal.objectchooser import ObjectChooser from sugar.datastore.datastore import DSObject from sugar import mime import uuid +import tempfile +import os import logging LOGGER = logging.getLogger("sugar.tutorius.propwidgets") @@ -570,3 +572,111 @@ class ResourcePropWidget(PropWidget): """ raise RuntimeError('Cannot select a default resource') +class ScreenClipPropWidget(PropWidget): + """Allows adding and changing tutorial resources.""" + def _on_drag_end(self, widget, event, pixbuf): + from . import creator + widget.destroy() + + end_x, end_y = event.get_coords() + width = abs(end_x - self.start_x) + height = abs(end_y - self.start_y) + x_off = min(self.start_x, end_x) + y_off = min(self.start_y, end_y) + + cropped = pixbuf.subpixbuf(x_off, y_off, width, height) + + tmp_name = tempfile.mktemp(suffix='.png') + try: + cropped.save(tmp_name, 'png') + creator_obj = creator.default_creator() + resource_id = creator_obj.set_resource(self.obj_prop, tmp_name) + self.obj_prop = resource_id + finally: + os.unlink(tmp_name) + + self.notify() + + def _on_drag_start(self, widget, event, pixbuf): + widget.connect('button-release-event', self._on_drag_end, pixbuf) + widget.connect('motion-notify-event', self._on_drag_move, pixbuf) + self.start_x, self.start_y = event.get_coords() + + def _on_drag_move(self, widget, event, pixbuf): + if gtk.gdk.events_pending(): + return + + end_x, end_y = event.get_coords() + width = abs(end_x - self.start_x) + height = abs(end_y - self.start_y) + x_off = min(self.start_x, end_x) + y_off = min(self.start_y, end_y) + + ctx = widget.window.cairo_create() + ctx.set_source_pixbuf(pixbuf, 0, 0) + ctx.paint() + + ctx.set_source_rgb(0, 0, 0) + ctx.rectangle(x_off, y_off, width, height) + ctx.stroke() + + def _get_capture(self, widget): + """ + Select a resource and add it through the creator. + This is expected to run in the same process, alongside the creator. + """ + # take screen capture + root = gtk.gdk.get_default_root_window() + width, height = root.get_size() + pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, + width, height) + pixbuf.get_from_drawable(src=root, + cmap=gtk.gdk.colormap_get_system(), + src_x=0, src_y=0, + dest_x=0, dest_y=0, + width=width, height=height) + + win = gtk.Window() + image = gtk.Image() + image.set_from_pixbuf(pixbuf) + win.add(image) + win.show_all() + win.set_app_paintable(True) + win.fullscreen() + win.present() + win.add_events(gtk.gdk.BUTTON_PRESS_MASK | \ + gtk.gdk.BUTTON_RELEASE_MASK | \ + gtk.gdk.POINTER_MOTION_MASK) + win.connect('button-press-event', self._on_drag_start, pixbuf) + + def create_widget(self, init_value=None): + """ + Create the Edit Widget for a property + @param init_value initial value + @return gtk.Widget + """ + propwdg = gtk.Button("Clip Screen") + propwdg.connect_after("clicked", self._get_capture) + return propwdg + + def refresh_widget(self): + """ + Force the widget to update it's value in case the property has changed + """ + # Nothing to refresh + pass + + @classmethod + def run_dialog(cls, parent, obj_prop, propname): + """ + Class Method. + Prompts the user for changing an object's property + @param parent widget + @param obj_prop TPropContainer to edit + @param propname name of property to edit + """ + # TODO We're assuming all reasource creation is done from the creator + # and not from the probe since there is a requirement to know the guid + # to add resources. But for this resource type, this could technically + # be done in the probe. + raise RuntimeError('Cannot select a default resource') |