diff options
author | Sayamindu Dasgupta <sayamindu@gmail.com> | 2009-11-21 19:07:00 (GMT) |
---|---|---|
committer | Sayamindu Dasgupta <sayamindu@gmail.com> | 2009-11-21 19:07:00 (GMT) |
commit | 685b6aa6153468a41c9b417bfd18d8476014154e (patch) | |
tree | 4a7bd0f26e2bf2613e9fda2bbe2afcfbf38b5c4d |
Initial import
-rw-r--r-- | activity/activity-scribble.svg | 26 | ||||
-rw-r--r-- | activity/activity.info | 9 | ||||
-rw-r--r-- | icons/tool-pencil.svg | 21 | ||||
-rw-r--r-- | icons/tool-shape-ellipse.svg | 11 | ||||
-rw-r--r-- | icons/tool-shape-rectangle.svg | 11 | ||||
-rw-r--r-- | miscwidgets.py | 93 | ||||
-rw-r--r-- | po/Scribble.pot | 55 | ||||
-rw-r--r-- | scribblewidget.py | 201 | ||||
-rwxr-xr-x | setup.py | 6 |
9 files changed, 433 insertions, 0 deletions
diff --git a/activity/activity-scribble.svg b/activity/activity-scribble.svg new file mode 100644 index 0000000..a480452 --- /dev/null +++ b/activity/activity-scribble.svg @@ -0,0 +1,26 @@ +<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [ + <!ENTITY stroke_color "#666666"> + <!ENTITY fill_color "#FFFFFF"> +]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><defs + id="defs10" /> + <rect + width="50" + height="50" + x="5" + y="5" + transform="matrix(0.68770843,0,0,0.69320514,8.9434765,6.5594193)" + id="rect4" + style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3.5" /> + <g + transform="matrix(0.68770843,0,0,0.69320514,16.549154,-6.2574121)" + id="Pencil"> + <g + id="g36" + style="display:inline"> + <path + d="m 12.727,45.969 c -0.053,0.132 -0.02,0.281 0.09,0.373 0.11,0.092 0.264,0.103 0.385,0.025 l 4.635,-2.984 -3.009,-2.407 -2.101,4.993 z m 30.24,-31.898 c 0,-0.073 -0.004,-0.15 -0.014,-0.227 C 42.841,12.895 42.05,11.735 40.891,10.819 39.731,9.904 38.417,9.406 37.467,9.515 37.053,9.567 36.72,9.743 36.494,10.006 L 36.473,9.991 19.716,32.17 l -0.073,0.073 -0.011,0.015 c -0.026,0.029 -0.029,0.069 -0.05,0.103 l -2.177,2.677 c 0,0 0.128,0.099 0.256,0.201 l -0.002,0.004 -0.009,0.011 c -0.128,-0.103 -0.252,-0.197 -0.252,-0.197 l -0.042,0.051 c -0.097,0.121 -0.155,0.271 -0.203,0.429 -0.015,0.019 -0.046,0.025 -0.057,0.048 l -1.361,3.236 4.097,3.278 3.202,-2.062 c 0.019,-0.011 0.015,-0.037 0.031,-0.052 0.083,-0.065 0.178,-0.121 0.243,-0.201 0.008,-0.011 0.043,-0.059 0.048,-0.062 l 2.237,-2.79 0.033,-0.033 -0.004,-0.004 0.023,-0.029 0.006,0.004 16.939,-21.85 c 0.029,-0.029 0.071,-0.044 0.1,-0.077 0.032,-0.044 0.049,-0.103 0.076,-0.15 l 0.015,-0.019 -0.003,-0.003 c 0.117,-0.205 0.189,-0.432 0.189,-0.7 z" + id="path38" + style="fill:&stroke_color;;" /> + </g> + </g> +</svg> diff --git a/activity/activity.info b/activity/activity.info new file mode 100644 index 0000000..c894f11 --- /dev/null +++ b/activity/activity.info @@ -0,0 +1,9 @@ +[Activity] +name = Scribble +bundle_id = org.randomink.sayamindu.ScribbleActivity +class = scribbleactivity.ScribbleActivity +icon = activity-scribble +activity_version = 1 +host_version = 1 +show_launcher = yes +license = GPLv2+ diff --git a/icons/tool-pencil.svg b/icons/tool-pencil.svg new file mode 100644 index 0000000..c7a1ef9 --- /dev/null +++ b/icons/tool-pencil.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="55px"
+ height="55px" viewBox="0 0 55 55" enable-background="new 0 0 55 55" xml:space="preserve">
+
+<g id="Pencil" >
+ <g display="inline">
+ <path fill="#FFFFFF" d="M12.727,45.969c-0.053,0.132-0.02,0.281,0.09,0.373s0.264,0.103,0.385,0.025l4.635-2.984l-3.009-2.407
+ L12.727,45.969z M42.967,14.071c0-0.073-0.004-0.15-0.014-0.227c-0.112-0.949-0.903-2.109-2.062-3.025
+ c-1.16-0.915-2.474-1.413-3.424-1.304c-0.414,0.052-0.747,0.228-0.973,0.491l-0.021-0.015L19.716,32.17l-0.073,0.073l-0.011,0.015
+ c-0.026,0.029-0.029,0.069-0.05,0.103l-2.177,2.677c0,0,0.128,0.099,0.256,0.201l-0.002,0.004l-0.009,0.011
+ c-0.128-0.103-0.252-0.197-0.252-0.197l-0.042,0.051c-0.097,0.121-0.155,0.271-0.203,0.429c-0.015,0.019-0.046,0.025-0.057,0.048
+ l-1.361,3.236l4.097,3.278l3.202-2.062c0.019-0.011,0.015-0.037,0.031-0.052c0.083-0.065,0.178-0.121,0.243-0.201
+ c0.008-0.011,0.043-0.059,0.048-0.062l2.237-2.79l0.033-0.033l-0.004-0.004l0.023-0.029l0.006,0.004L42.59,15.02
+ c0.029-0.029,0.071-0.044,0.1-0.077c0.032-0.044,0.049-0.103,0.076-0.15l0.015-0.019l-0.003-0.003
+ C42.895,14.566,42.967,14.339,42.967,14.071z"/>
+ </g>
+</g>
+
+</svg>
diff --git a/icons/tool-shape-ellipse.svg b/icons/tool-shape-ellipse.svg new file mode 100644 index 0000000..2cdb119 --- /dev/null +++ b/icons/tool-shape-ellipse.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="55px"
+ height="55px" viewBox="0 0 55 55" enable-background="new 0 0 55 55" xml:space="preserve">
+
+<g id="Ellipse" >
+ <circle display="inline" fill="#FFFFFF" cx="27.499" cy="27.5" r="19.802"/>
+</g>
+
+</svg>
diff --git a/icons/tool-shape-rectangle.svg b/icons/tool-shape-rectangle.svg new file mode 100644 index 0000000..d926cd1 --- /dev/null +++ b/icons/tool-shape-rectangle.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="55px"
+ height="55px" viewBox="0 0 55 55" enable-background="new 0 0 55 55" xml:space="preserve">
+
+<g id="Rectangle" >
+ <rect x="8.832" y="8.833" display="inline" fill="#FFFFFF" width="37.334" height="37.334"/>
+</g>
+
+</svg>
diff --git a/miscwidgets.py b/miscwidgets.py new file mode 100644 index 0000000..fff1962 --- /dev/null +++ b/miscwidgets.py @@ -0,0 +1,93 @@ +# Originally part of Write Activity +# Modified by Sayamindu Dasgupta <sayamindu@laptop.org> + +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import time +from gettext import gettext as _ +import logging + +import gobject + +from sugar.graphics.toolbutton import ToolButton +from sugar.graphics.menuitem import MenuItem +from sugar.datastore import datastore + +logger = logging.getLogger('scribble-activity') + +class ExportButton(ToolButton): + _EXPORT_FORMATS = [{'mime_type' : 'image/jpeg', + 'title' : _('JPEG'), + 'exp_props' : {"quality":"85"}}, + + {'mime_type' : 'image/png', + 'title' : _('PNG'), + 'exp_props' : {}}] + + def __init__(self, activity): + ToolButton.__init__(self, 'document-save') + self.props.tooltip = _('Export') + self.props.label = _('Export') + self._activity = activity + + for i in self._EXPORT_FORMATS: + menu_item = MenuItem(i['title']) + menu_item.connect('activate', self.__activate_cb, activity, i) + self.props.palette.menu.append(menu_item) + menu_item.show() + + self.connect('clicked', self._clicked_cb) + + def _clicked_cb(self, widget): + self._export(self._activity, self._EXPORT_FORMATS[0]) + + #def do_clicked(self): + # self._export(self._activity, _EXPORT_FORMATS[0]) + + def _export(self, activity, fmt): + exp_props = fmt['exp_props'] + + # create a new journal item + fileObject = datastore.create() + act_meta = activity.metadata + fileObject.metadata['title'] = \ + _('Exported image from %s') % (act_meta['title']) + fileObject.metadata['title_set_by_user'] = \ + act_meta['title_set_by_user'] + fileObject.metadata['mime_type'] = fmt['mime_type'] + + fileObject.metadata['icon-color'] = act_meta['icon-color'] + fileObject.metadata['keep'] = act_meta['keep'] + + #fileObject.metadata['share-scope'] = act_meta['share-scope'] + + # write out the document contents in the requested format + fileObject.file_path = os.path.join(activity.get_activity_root(), + 'instance', '%i' % time.time()) + activity.export(fileObject.file_path, fmt['mime_type'], \ + exp_props) + + # store the journal item + datastore.write(fileObject, transfer_ownership=True) + fileObject.destroy() + del fileObject + + return False + + def __activate_cb(self, menu_item, activity, fmt): + logger.debug('exporting file: %r' % fmt) + + gobject.timeout_add_seconds(1, self._export, activity, fmt) diff --git a/po/Scribble.pot b/po/Scribble.pot new file mode 100644 index 0000000..72f57e2 --- /dev/null +++ b/po/Scribble.pot @@ -0,0 +1,55 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-22 00:04+0530\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: activity/activity.info:2 +msgid "Scribble" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/scribbleactivity.py:38 +msgid "Pencil" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/scribbleactivity.py:43 +msgid "Ellipse" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/scribbleactivity.py:49 +msgid "Rectangle" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/scribbleactivity.py:67 +msgid "Toolbox" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/miscwidgets.py:35 +msgid "JPEG" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/miscwidgets.py:39 +msgid "PNG" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/miscwidgets.py:44 +#: /home/sayamindu/Work/Devel/scribble/miscwidgets.py:45 +msgid "Export" +msgstr "" + +#: /home/sayamindu/Work/Devel/scribble/miscwidgets.py:68 +#, python-format +msgid "Exported image from %s" +msgstr "" diff --git a/scribblewidget.py b/scribblewidget.py new file mode 100644 index 0000000..3406890 --- /dev/null +++ b/scribblewidget.py @@ -0,0 +1,201 @@ +# Copyright (C) 2008, 2009 Sayamindu Dasgupta <sayamindu@gmail.com> +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import gtk +import gobject +import goocanvas + +import math +import uuid + +DEFAULT_WIDTH = 10 +DEFAULT_HEIGHT = 10 + +CANVAS_WIDTH = 1187 +CANVAS_HEIGHT = 767 + +class ScribbleWidget(goocanvas.Canvas): + __gsignals__ = { + 'item-added': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([])), + } + def __init__(self): + goocanvas.Canvas.__init__(self) + self.set_size_request(CANVAS_WIDTH, CANVAS_HEIGHT) + self.set_bounds(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT) + + self.connect("button_press_event", self.on_button_press) + self.connect("button_release_event", self.on_button_release) + self.connect("motion_notify_event", self.on_motion) + + self._root = self.get_root_item() + + self.tool = None + self.item = None + self.item_id = None + self.item_orig_x = 0 + self.item_orig_y = 0 + self.item_width = 0 + self.item_height = 0 + self.line_points = [] + self.prev_time = 0 + self._fill_color = 0 + self._stroke_color = 0 + self.cmd = None # method to draw the last item + self.cmd_list = "" # list of methods to draw the entire canvas + + def set_fill_color(self, color): + self._fill_color = int(color.strip('#')+'FF', 16) + + def set_stroke_color(self, color): + self._stroke_color = int(color.strip('#')+'FF', 16) + + def set_tool(self, tool): + self.tool = tool + + def create_item(self, x, y): + self.item_id = str(uuid.uuid4()) + + self.item_orig_x = x + self.item_orig_y = y + + self.item_width = DEFAULT_WIDTH + self.item_height = DEFAULT_HEIGHT + + if self.tool == 'circle': + self.item = goocanvas.Ellipse(parent=self._root, center_x=x, \ + center_y=y, radius_x = DEFAULT_WIDTH/2, \ + radius_y = DEFAULT_HEIGHT/2, title=self.item_id, \ + fill_color_rgba = self._fill_color, \ + stroke_color_rgba = self._stroke_color) + elif self.tool == 'rect': + self.item = goocanvas.Rect(parent=self._root, x=x, y=y, \ + width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT, \ + fill_color_rgba = self._fill_color, \ + stroke_color_rgba = self._stroke_color, title=self.item_id) + elif self.tool == 'pencil': + self.line_points = [] #Reset + self.line_points.append((x, y)) + self.item = goocanvas.Polyline(parent=self._root, \ + points=goocanvas.Points(self.line_points), \ + stroke_color_rgba = self._stroke_color, title=self.item_id) + else: + pass + + def process_motion(self, x, y, time): + dx = x - self.item_orig_x + dy = y - self.item_orig_y + dt = time - self.prev_time + + if self.tool == 'circle': + self.item.props.radius_x = abs(dx) + self.item.props.radius_y = abs(dy) + elif self.tool == 'rect': + if dx < 0: + self.item.props.x = x + #self.item_orig_x = x + if dy < 0: + self.item.props.y = y + #self.item_orig_y = y + self.item.props.width = abs(dx) + self.item.props.height = abs(dy) + elif self.tool == 'pencil': + #XXX: This is pretty ugly - we should try some curve fitting stuff + dist = abs(math.sqrt(dx*dx + dy*dy)) + self.line_points.append((x, y)) + if dist > 10 or dt > 10: + self.item.props.points = goocanvas.Points(self.line_points) + self.item_orig_x = x + self.item_orig_y = y + + self.prev_time = time + + def get_cmd(self): + return self.cmd + + def get_cmd_list(self): + return self.cmd_list + + def process_item_finalize(self): + if self.tool == 'circle': + self.cmd = "goocanvas.Ellipse(parent=self._root, center_x=%d, \ + center_y=%d, radius_x = %d, radius_y = %d, \ + fill_color_rgba = %d, stroke_color_rgba = %d, \ + title = '%s')" % (self.item.props.center_x, \ + self.item.props.center_y, self.item.props.radius_x, \ + self.item.props.radius_y, self._fill_color, \ + self._stroke_color, self.item_id) + elif self.tool == 'rect': + self.cmd = "goocanvas.Rect(parent=self._root, x=%d, y=%d, \ + width=%d, height=%d, fill_color_rgba = %d, \ + stroke_color_rgba = %d, title = '%s')" % (self.item.props.x, \ + self.item.props.y, self.item.props.width, \ + self.item.props.height, self._fill_color, self._stroke_color, \ + self.item_id) + elif self.tool == 'pencil': + self.cmd = "goocanvas.Polyline(parent=self._root, \ + points=goocanvas.Points(%s), stroke_color_rgba = %d, \ + title = '%s')" % (str(self.line_points), self._stroke_color, \ + self.item_id) + + #print self.cmd + + if len(self.cmd_list) > 0: + self.cmd_list += (';' + self.cmd) + else: + self.cmd_list = self.cmd + + self.emit('item-added') + + def process_cmd(self, cmd): + #print 'Processing cmd :' + cmd + exec(cmd) #FIXME: Ugly hack, but I'm too lazy to do this nicely + + if len(self.cmd_list) > 0: + self.cmd_list += (';' + cmd) + else: + self.cmd_list = cmd + + + def on_button_press(self, canvas, event): + self.create_item(event.x, event.y) + fleur = gtk.gdk.Cursor(gtk.gdk.FLEUR) + canvas.pointer_grab(self.item, \ + gtk.gdk.POINTER_MOTION_MASK | \ + gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.BUTTON_RELEASE_MASK, + fleur, event.time) + return True + + def on_button_release(self, canvas, event): + canvas.pointer_ungrab(self.item, event.time) + self.process_item_finalize() + return True + + def on_motion(self, canvas, event): + if event.is_hint: + x, y, state = event.window.get_pointer() + else: + x = event.x + y = event.y + state = event.state + + if not state & gtk.gdk.BUTTON1_MASK: + return False + + self.process_motion(x, y, event.time) + return True + diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..e8d870b --- /dev/null +++ b/setup.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +from sugar.activity import bundlebuilder + +bundlebuilder.start() + |