Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSayamindu Dasgupta <sayamindu@gmail.com>2009-11-21 19:07:00 (GMT)
committer Sayamindu Dasgupta <sayamindu@gmail.com>2009-11-21 19:07:00 (GMT)
commit685b6aa6153468a41c9b417bfd18d8476014154e (patch)
tree4a7bd0f26e2bf2613e9fda2bbe2afcfbf38b5c4d
Initial import
-rw-r--r--activity/activity-scribble.svg26
-rw-r--r--activity/activity.info9
-rw-r--r--icons/tool-pencil.svg21
-rw-r--r--icons/tool-shape-ellipse.svg11
-rw-r--r--icons/tool-shape-rectangle.svg11
-rw-r--r--miscwidgets.py93
-rw-r--r--po/Scribble.pot55
-rw-r--r--scribblewidget.py201
-rwxr-xr-xsetup.py6
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()
+