diff options
author | Walter Bender <walter.bender@gmail.com> | 2011-04-19 13:02:57 (GMT) |
---|---|---|
committer | Walter Bender <walter.bender@gmail.com> | 2011-04-19 13:02:57 (GMT) |
commit | 2ac562c0663bd22865eca19933eec9ec2321b7bd (patch) | |
tree | 7a59ef057152e9668bf1b235608881bd152e4efb |
new project
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | NapierActivity.py | 412 | ||||
-rw-r--r-- | activity/activity-napier.svg | 37 | ||||
-rw-r--r-- | activity/activity.info | 8 | ||||
-rw-r--r-- | bones/blank-bone.svg | 139 | ||||
-rw-r--r-- | bones/bones-index.svg | 139 | ||||
-rw-r--r-- | bones/circle.svg | 32 | ||||
-rw-r--r-- | bones/oval.svg | 38 | ||||
-rw-r--r-- | icons/bones.svg | 45 | ||||
-rw-r--r-- | icons/new-game.svg | 19 | ||||
-rw-r--r-- | icons/number-0.svg | 31 | ||||
-rw-r--r-- | icons/number-1.svg | 31 | ||||
-rw-r--r-- | icons/number-2.svg | 31 | ||||
-rw-r--r-- | icons/number-3.svg | 31 | ||||
-rw-r--r-- | icons/number-4.svg | 31 | ||||
-rw-r--r-- | icons/number-5.svg | 31 | ||||
-rw-r--r-- | icons/number-6.svg | 31 | ||||
-rw-r--r-- | icons/number-7.svg | 31 | ||||
-rw-r--r-- | icons/number-8.svg | 31 | ||||
-rw-r--r-- | icons/number-9.svg | 31 | ||||
-rw-r--r-- | po/Napier.pot | 78 | ||||
-rw-r--r-- | sprites.py | 453 |
22 files changed, 1714 insertions, 0 deletions
@@ -0,0 +1,4 @@ +1 + +Napier's bones were invented by John Napier (1550-1617), a Scottish +mathematician and scientist. They help you to do multiplication. diff --git a/NapierActivity.py b/NapierActivity.py new file mode 100644 index 0000000..4954a40 --- /dev/null +++ b/NapierActivity.py @@ -0,0 +1,412 @@ +# -*- coding: utf-8 -*- +#Copyright (c) 2011 Walter Bender + +# 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 3 of the License, or +# (at your option) any later version. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import gtk +import gobject +import os + +import sugar +from sugar.activity import activity +from sugar import profile +try: + from sugar.graphics.toolbarbox import ToolbarBox + _have_toolbox = True +except ImportError: + _have_toolbox = False + +if _have_toolbox: + from sugar.bundle.activitybundle import ActivityBundle + from sugar.activity.widgets import ActivityToolbarButton + from sugar.activity.widgets import StopButton + from sugar.graphics.toolbarbox import ToolbarButton + +from sugar.graphics.toolbutton import ToolButton +from sugar.graphics.menuitem import MenuItem + +from sprites import Sprites, Sprite + +from gettext import gettext as _ + +try: + from sugar.graphics import style + GRID_CELL_SIZE = style.GRID_CELL_SIZE +except ImportError: + GRID_CELL_SIZE = 0 + +SERVICE = 'org.sugarlabs.NapierActivity' +IFACE = SERVICE +PATH = '/org/augarlabs/NapierActivity' +BONE_WIDTH = 101 +BONE_HEIGHT = 901 + + +def _svg_header(scale=1.0): + ''' Return standard header for SVG bones ''' + return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\ +<!-- Created with Emacs (http://gnu.org/) -->\ +<svg\ + xmlns:dc="http://purl.org/dc/elements/1.1/"\ + xmlns:cc="http://creativecommons.org/ns#"\ + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\ + xmlns:svg="http://www.w3.org/2000/svg"\ + xmlns="http://www.w3.org/2000/svg"\ + version="1.1"\ + width="%f"\ + height="%f">' % (101 * scale, 901 * scale) + + +def _svg_footer(): + ''' Return standard footer for SVG bones ''' + return '</svg>\ +' + +def _svg_single_box(a, scale=1.0): + ''' Return standard top-of-column box for SVG bones ''' + return ' <g>\ + <rect\ + width="%f"\ + height="%f"\ + x="%f"\ + y="%f"\ + style="fill:none;stroke:#000000;stroke-width:%f;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:%f;stroke-opacity:1;stroke-dasharray:none" />\ + <text\ + style="font-size:%fpx;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle">\ + <tspan x="%f" y="%f">\ + %d\ + </tspan>\ + </text>\ + </g>' % (99 * scale, 99 * scale, scale, scale, 2 * scale, + 4 * scale, 40 * scale, 55 * scale, 65 * scale, a) + + +def _svg_double_box(a, b, y, scale=1.0): + ''' Return standard double-digit box for SVG bones ''' + return ' <g>\ + <rect\ + width="%f"\ + height="%f"\ + x="%f"\ + y="%f"\ + style="fill:none;stroke:#000000;stroke-width:%f;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:%f;stroke-opacity:1;stroke-dasharray:none" />\ + <line\ + x1="%f"\ + y1="%f"\ + x2="%f"\ + y2="%f"\ + style="fill:none;stroke:#000000;stroke-width:%f;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:%f;stroke-opacity:1;stroke-dasharray:none" />\ + <text\ + style="font-size:%fpx;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans">\ + <tspan x="%f" y="%f">\ + %d\ + </tspan>\ + </text>\ + <text\ + style="font-size:%fpx;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans">\ + <tspan x="%f" y="%f">\ + %d\ + </tspan>\ + </text>\ + </g>' % (99 * scale, 99 * scale, scale, y * scale, 2 * scale, + 4 * scale, scale, (y + 99) * scale, 99 * scale, + (y + 1) * scale, 2 * scale, 4 * scale, 40 * scale, 12 * scale, + (y + 51) * scale, a, 40 * scale, 52 * scale, (y + 81) * scale, b) + + +def _bone_factory(value, scale=1.0): + svg = _svg_header(scale=scale) + svg += _svg_single_box(value, scale=scale) + for i in range(9): + if i > 0: + j = (i + 1) * value + svg += _svg_double_box(int(j / 10), j % 10, i * 100, scale=scale) + return svg + _svg_footer() + + +def _svg_str_to_pixbuf(svg_string): + ''' Load pixbuf from SVG string ''' + pl = gtk.gdk.PixbufLoader('svg') + pl.write(svg_string) + pl.close() + pixbuf = pl.get_pixbuf() + return pixbuf + + +def _load_svg_from_file(file_path, width, height): + '''Create a pixbuf from SVG in a file. ''' + return gtk.gdk.pixbuf_new_from_file_at_size(file_path, width, height) + + +def _button_factory(icon_name, tooltip, callback, toolbar, cb_arg=None, + accelerator=None): + '''Factory for making toolbar buttons''' + my_button = ToolButton(icon_name) + my_button.set_tooltip(tooltip) + my_button.props.sensitive = True + if accelerator is not None: + my_button.props.accelerator = accelerator + if cb_arg is not None: + my_button.connect('clicked', callback, cb_arg) + else: + my_button.connect('clicked', callback) + if hasattr(toolbar, 'insert'): # the main toolbar + toolbar.insert(my_button, -1) + else: # or a secondary toolbar + toolbar.props.page.insert(my_button, -1) + my_button.show() + return my_button + + +def _label_factory(label, toolbar): + ''' Factory for adding a label to a toolbar ''' + my_label = gtk.Label(label) + my_label.set_line_wrap(True) + my_label.show() + toolitem = gtk.ToolItem() + toolitem.add(my_label) + toolbar.insert(toolitem, -1) + toolitem.show() + return my_label + + +def _separator_factory(toolbar, visible=True, expand=False): + ''' Factory for adding a separator to a toolbar ''' + separator = gtk.SeparatorToolItem() + separator.props.draw = visible + separator.set_expand(expand) + toolbar.insert(separator, -1) + separator.show() + + +class NapierActivity(activity.Activity): + ''' Napier's bones: Napier's bones were invented by John Napier + (1550-1617), a Scottish mathematician and scientist. They help you + to do multiplication. ''' + + # TODO: Define your own bone. + + def __init__(self, handle): + ''' Initialize the toolbars and the work surface ''' + super(NapierActivity, self).__init__(handle) + + if os.path.exists(os.path.join('~', 'Activities', 'Napier.activity')): + self._bone_path = os.path.join('~', 'Activities', 'Napier.activity', + 'bones') + else: + self._bone_path = os.path.join('.', 'bones') + + self._bones = [] + self._bone_images = [None, None, None, None, None, None, None, None, + None, None] + self._blank_image = None + self._number = 0 + self._number_of_bones = 0 + self._circles = [None, None] + self._ovals = [] + + self._setup_toolbars(_have_toolbox) + self._setup_canvas() + self._setup_workspace() + + def _setup_canvas(self): + ''' Create a canvas ''' + self._canvas = gtk.DrawingArea() + self._canvas.set_size_request(gtk.gdk.screen_width(), + gtk.gdk.screen_height()) + self.set_canvas(self._canvas) + self._canvas.show() + self.show_all() + + self._canvas.set_flags(gtk.CAN_FOCUS) + self._canvas.add_events(gtk.gdk.BUTTON_PRESS_MASK) + self._canvas.add_events(gtk.gdk.BUTTON_RELEASE_MASK) + self._canvas.add_events(gtk.gdk.POINTER_MOTION_MASK) + self._canvas.connect("expose-event", self._expose_cb) + self._canvas.connect("motion-notify-event", self._mouse_move_cb) + # self._canvas.connect("key_press_event", self._key_press_cb) + + def _setup_workspace(self): + ''' Add the bones. ''' + self._width = gtk.gdk.screen_width() + self._height = int(gtk.gdk.screen_height() - (GRID_CELL_SIZE * 2)) + self._scale = self._height * 1.0 / BONE_HEIGHT + self._bone_width = int(BONE_WIDTH * self._scale) + self._bone_height = int(BONE_HEIGHT * self._scale) + + # Generate the sprites we'll need... + self._sprites = Sprites(self._canvas) + self._bone_index = Sprite(self._sprites, 0, 0, _load_svg_from_file( + os.path.join(self._bone_path, 'bones-index.svg'), + self._bone_width, self._bone_height)) + self._max_bones = int(self._width / self._bone_width) - 1 + self._blank_image = _load_svg_from_file( + os.path.join(self._bone_path, 'blank-bone.svg'), + self._bone_width, self._bone_height) + for bones in range(self._max_bones): + self._bones.append(Sprite(self._sprites, bones * self._bone_width, + 0, self._blank_image)) + circle_image = _load_svg_from_file( + os.path.join(self._bone_path, 'circle.svg'), int(self._scale * 45), + int(self._scale * 45)) + self._circles[0] = Sprite(self._sprites, 0, -100, circle_image) + self._circles[1] = Sprite(self._sprites, 0, -100, circle_image) + oval_image = _load_svg_from_file( + os.path.join(self._bone_path, 'oval.svg'), int(self._scale * 129), + int(self._scale * 92)) + for bones in range(self._max_bones - 1): + self._ovals.append(Sprite(self._sprites, 0, -100, oval_image)) + + def _setup_toolbars(self, have_toolbox): + ''' Setup the toolbars. ''' + + self.max_participants = 1 # no sharing + + if have_toolbox: + toolbox = ToolbarBox() + + # Activity toolbar + activity_button = ActivityToolbarButton(self) + + toolbox.toolbar.insert(activity_button, 0) + activity_button.show() + + self._bones_toolbar = gtk.Toolbar() + self._bones_toolbar_button = ToolbarButton(label=_('Select a bone'), + page=self._bones_toolbar, + icon_name='bones') + + self._bones_toolbar_button.show() + toolbox.toolbar.insert(self._bones_toolbar_button, -1) + self.set_toolbar_box(toolbox) + toolbox.show() + self.toolbar = toolbox.toolbar + + else: + # Use pre-0.86 toolbar design + self._bones_toolbar = gtk.Toolbar() + self.toolbar = gtk.Toolbar() + toolbox = activity.ActivityToolbox(self) + self.set_toolbox(toolbox) + toolbox.add_toolbar(_('Bones'), self._bones_toolbar) + toolbox.add_toolbar(_('Results'), self.toolbar) + toolbox.show() + toolbox.set_current_toolbar(1) + + _separator_factory(self.toolbar) + + self._new_calc_button = _button_factory( + 'new-game', _('Clear'), self._new_calc_cb, self.toolbar) + + self._status = _label_factory('', self.toolbar) + + _button_factory('number-0', _('zero'), self._number_cb, + self._bones_toolbar, cb_arg=0) + + _button_factory('number-1', _('one'), self._number_cb, + self._bones_toolbar, cb_arg=1) + + _button_factory('number-2', _('two'), self._number_cb, + self._bones_toolbar, cb_arg=2) + + _button_factory('number-3', _('three'), self._number_cb, + self._bones_toolbar, cb_arg=3) + + _button_factory('number-4', _('four'), self._number_cb, + self._bones_toolbar, cb_arg=4) + + _button_factory('number-5', _('five'), self._number_cb, + self._bones_toolbar, cb_arg=5) + + _button_factory('number-6', _('six'), self._number_cb, + self._bones_toolbar, cb_arg=6) + + _button_factory('number-7', _('seven'), self._number_cb, + self._bones_toolbar, cb_arg=7) + + _button_factory('number-8', _('eight'), self._number_cb, + self._bones_toolbar, cb_arg=8) + + _button_factory('number-9', _('nine'), self._number_cb, + self._bones_toolbar, cb_arg=9) + + if _have_toolbox: + _separator_factory(toolbox.toolbar, False, True) + + stop_button = StopButton(self) + stop_button.props.accelerator = '<Ctrl>q' + toolbox.toolbar.insert(stop_button, -1) + stop_button.show() + self._bones_toolbar_button.set_expanded(True) + + def _new_calc_cb(self, button=None): + ''' Start a new calculation. ''' + for bone in range(self._max_bones): + self._bones[bone].images[0] = self._blank_image + self._bones[bone].inval() + self._number_of_bones = 0 + self._number = 0 + self._status.set_label('') + return + + def _number_cb(self, button=None, value=0): + ''' Try to add a digit. ''' + if self._number_of_bones == self._max_bones: + return + self._number_of_bones += 1 + if self._bone_images[value] is None: + self._bone_images[value] = _svg_str_to_pixbuf( + _bone_factory(value, scale=self._scale)) + self._bones[self._number_of_bones].images[0] = self._bone_images[value] + self._bones[self._number_of_bones].inval() + self._number = self._number * 10 + value + + def _mouse_move_cb(self, win, event): + ''' Determine which row we are in and then calculate the product. ''' + win.grab_focus() + x, y = map(int, event.get_coords()) + factor = int(y / self._bone_width) # The row determines a factor + + if self._number == 0 or factor == 0: + self._status.set_label('') + self._circles[0].move((0, -100)) + self._circles[1].move((0, -100)) + for number in range(self._max_bones): + self._ovals[number].move((0, -100)) + else: + c0dx = int(4 * self._scale) + c0dy = int(12 * self._scale) + c1dx = int(44 * self._scale) + c1dy = int(42 * self._scale) + odx = int(42 * self._scale) + ody = int(2 * self._scale) + self._circles[0].move((self._bone_width + c0dx, + factor * self._bone_width + c0dy)) + self._circles[1].move(( + self._number_of_bones * self._bone_width + c1dx, + factor * self._bone_width + c1dy)) + for number in range(self._number_of_bones - 1): + self._ovals[number].move(((number + 1) * self._bone_width + odx, + factor * self._bone_width + ody)) + self._status.set_label('%d × %d = %d' % ( + factor + 1, self._number, (factor + 1) * self._number)) + return True + + def _key_press_cb(self, win, event): + ''' TODO: Add bones by typing numbers ''' + return True + + def _expose_cb(self, win, event): + self._sprites.redraw_sprites() + return True + + def _destroy_cb(self, win, event): + gtk.main_quit() diff --git a/activity/activity-napier.svg b/activity/activity-napier.svg new file mode 100644 index 0000000..cbfc4c0 --- /dev/null +++ b/activity/activity-napier.svg @@ -0,0 +1,37 @@ +<?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 "#000"> + <!ENTITY fill_color "#eee"> +]><svg height="55px" viewBox="0 0 55 55" width="55px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5" stroke="&stroke_color;" fill="&fill_color;"> + <g + transform="translate(-164.9317,-522.38248)" + id="layer1"> + <path + d="m 172.31971,536.76347 c -0.72411,-2.08754 -3.85535,-2.66829 -4.57016,-4.75911 -0.54398,-1.59114 0.41111,-4.84994 1.17519,-6.34548 0.87849,-1.71948 3.58403,-1.89878 5.48419,-2.11515 2.90308,-0.33058 4.65817,4.0255 5.87592,3.83372 1.55514,-0.1023 2.2545,-2.48793 3.7867,-2.77614 2.1694,-0.40808 4.92014,0.0599 6.39823,1.71856 1.68249,1.88803 1.99295,5.13094 1.17518,7.53525 -0.58154,1.70978 -3.24117,2.02778 -3.91728,3.70153 -1.51719,3.75593 0.59363,8.10493 0.5223,12.16216 -0.0785,4.46388 -2.44397,9.11811 -1.0446,13.35194 0.64576,1.9538 3.46637,2.65253 4.04785,4.62691 0.51535,1.74982 0.13809,3.85051 -0.78345,5.4201 -0.77839,1.32577 -2.19739,2.33161 -3.65613,2.77614 -1.41951,0.43258 -3.07626,0.32499 -4.43959,-0.26439 -1.52949,-0.66121 -2.02542,-3.10643 -3.65612,-3.43714 -1.72831,-0.35049 -2.54848,1.76353 -4.30901,1.85077 -2.0667,0.1024 -5.18389,-0.11769 -6.65938,-1.58637 -1.38558,-1.37919 -1.76507,-3.72751 -1.56691,-5.68449 0.15485,-1.52924 1.08998,-2.94065 2.08922,-4.09812 0.69927,-0.81 2.11477,-0.89977 2.61152,-1.85076 1.58723,-3.03868 -0.0538,-6.87906 0.13057,-10.3114 0.24699,-4.59719 -0.0601,-8.61145 1.30576,-13.74853 z" + id="path3060" + style="fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:2.4120214;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="174.17461" + y="554.1217" + transform="scale(0.99384853,1.0061895)" + id="text3062" + xml:space="preserve" + style="font-size:21.02147293px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:&stroke_color;;fill-opacity:1;stroke:none;font-family:Sans"><tspan + x="174.17461" + y="554.1217" + id="tspan3064">1</tspan></text> + <path + d="m 198.96079,536.76347 c -0.72412,-2.08754 -3.85535,-2.66829 -4.57016,-4.75911 -0.54398,-1.59114 0.41111,-4.84994 1.17518,-6.34548 0.8785,-1.71948 3.58403,-1.89878 5.4842,-2.11515 2.90308,-0.33058 4.65816,4.0255 5.87592,3.83372 1.55514,-0.1023 2.25449,-2.48793 3.7867,-2.77614 2.16939,-0.40808 4.92014,0.0599 6.39822,1.71856 1.6825,1.88803 1.99296,5.13094 1.17519,7.53525 -0.58155,1.70978 -3.24118,2.02778 -3.91728,3.70153 -1.5172,3.75593 0.59363,8.10493 0.5223,12.16216 -0.0785,4.46388 -2.44397,9.11811 -1.04461,13.35194 0.64577,1.9538 3.46637,2.65253 4.04786,4.62691 0.51535,1.74982 0.13809,3.85051 -0.78346,5.4201 -0.77839,1.32577 -2.19739,2.33161 -3.65612,2.77614 -1.41951,0.43258 -3.07626,0.32499 -4.43959,-0.26439 -1.5295,-0.66121 -2.02542,-3.10643 -3.65613,-3.43714 -1.72831,-0.35049 -2.54847,1.76353 -4.309,1.85077 -2.0667,0.1024 -5.1839,-0.11769 -6.65938,-1.58637 -1.38558,-1.37919 -1.76507,-3.72751 -1.56691,-5.68449 0.15485,-1.52924 1.08998,-2.94065 2.08921,-4.09812 0.69927,-0.81 2.11478,-0.89977 2.61152,-1.85076 1.58724,-3.03868 -0.0538,-6.87906 0.13058,-10.3114 0.24699,-4.59719 -0.0601,-8.61145 1.30576,-13.74853 z" + id="path3060-2" + style="fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:2.4120214;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="200.98058" + y="554.26031" + transform="scale(0.99384853,1.0061895)" + id="text3062-9" + xml:space="preserve" + style="font-size:21.02147293px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:&stroke_color;;fill-opacity:1;stroke:none;font-family:Sans"><tspan + x="200.98058" + y="554.26031" + id="tspan3064-9">2</tspan></text> + </g> +</svg> diff --git a/activity/activity.info b/activity/activity.info new file mode 100644 index 0000000..5fe2ff2 --- /dev/null +++ b/activity/activity.info @@ -0,0 +1,8 @@ +[Activity] +name = Napier +activity_version = 1 +license = GPLv3 +bundle_id = org.sugarlabs.NapierActivity +exec = sugar-activity NapierActivity.NapierActivity +icon = activity-napier +show_launcher = yes diff --git a/bones/blank-bone.svg b/bones/blank-bone.svg new file mode 100644 index 0000000..e3fee82 --- /dev/null +++ b/bones/blank-bone.svg @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Emacs (http://gnu.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="101" + height="901"> + <g> + <rect + width="99" + height="99" + x="1" + y="1" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="65"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="100" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="165"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="200" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="265"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="300" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="365"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="400" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="465"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="500" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="565"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="600" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="665"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="700" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="765"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="800" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="865"> + + </tspan> + </text> + </g> +</svg> diff --git a/bones/bones-index.svg b/bones/bones-index.svg new file mode 100644 index 0000000..cf993ff --- /dev/null +++ b/bones/bones-index.svg @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Emacs (http://gnu.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="101" + height="901"> + <g> + <rect + width="99" + height="99" + x="1" + y="1" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="65"> + + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="100" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="165"> + 2 + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="200" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="265"> + 3 + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="300" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="365"> + 4 + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="400" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="465"> + 5 + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="500" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="565"> + 6 + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="600" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="665"> + 7 + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="700" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="765"> + 8 + </tspan> + </text> + </g> + <g> + <rect + width="99" + height="99" + x="1" + y="800" + style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + style="font-size:40px;font-style:normal;font-weight:bold;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;text-align:center;text-anchor:middle"> + <tspan x="55" y="865"> + 9 + </tspan> + </text> + </g> +</svg> diff --git a/bones/circle.svg b/bones/circle.svg new file mode 100644 index 0000000..62ac83e --- /dev/null +++ b/bones/circle.svg @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="45" + height="45" + id="svg3918"> + <metadata + id="metadata3927"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs3925" /> + <path + d="m 43.239273,22.514342 a 20.746456,20.746456 0 1 1 -41.4929117,0 20.746456,20.746456 0 1 1 41.4929117,0 z" + id="path3921" + style="fill:none;stroke:#ff0000;stroke-width:3.5;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> +</svg> diff --git a/bones/oval.svg b/bones/oval.svg new file mode 100644 index 0000000..24941eb --- /dev/null +++ b/bones/oval.svg @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="129" + height="92" + id="svg2"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <g + transform="translate(-548.06803,-551.36311)" + id="g4" + style="stroke-width:3.5;stroke-miterlimit:4;stroke-dasharray:none"> + <path + d="m 47.575289,236.11583 a 20.083012,20.277992 0 1 1 -40.1660235,0 20.083012,20.277992 0 1 1 40.1660235,0 z" + transform="matrix(2.7914157,-1.9284131,1.1535178,0.79689271,263.40099,462.56247)" + id="path6" + style="fill:none;stroke:#ff0000;stroke-width:1.65936089;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + </g> +</svg> diff --git a/icons/bones.svg b/icons/bones.svg new file mode 100644 index 0000000..30d64ec --- /dev/null +++ b/icons/bones.svg @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="55" + height="55"> + <g + transform="translate(-164.9317,-522.38248)" + id="layer1"> + <path + d="m 172.31971,536.76347 c -0.72411,-2.08754 -3.85535,-2.66829 -4.57016,-4.75911 -0.54398,-1.59114 0.41111,-4.84994 1.17519,-6.34548 0.87849,-1.71948 3.58403,-1.89878 5.48419,-2.11515 2.90308,-0.33058 4.65817,4.0255 5.87592,3.83372 1.55514,-0.1023 2.2545,-2.48793 3.7867,-2.77614 2.1694,-0.40808 4.92014,0.0599 6.39823,1.71856 1.68249,1.88803 1.99295,5.13094 1.17518,7.53525 -0.58154,1.70978 -3.24117,2.02778 -3.91728,3.70153 -1.51719,3.75593 0.59363,8.10493 0.5223,12.16216 -0.0785,4.46388 -2.44397,9.11811 -1.0446,13.35194 0.64576,1.9538 3.46637,2.65253 4.04785,4.62691 0.51535,1.74982 0.13809,3.85051 -0.78345,5.4201 -0.77839,1.32577 -2.19739,2.33161 -3.65613,2.77614 -1.41951,0.43258 -3.07626,0.32499 -4.43959,-0.26439 -1.52949,-0.66121 -2.02542,-3.10643 -3.65612,-3.43714 -1.72831,-0.35049 -2.54848,1.76353 -4.30901,1.85077 -2.0667,0.1024 -5.18389,-0.11769 -6.65938,-1.58637 -1.38558,-1.37919 -1.76507,-3.72751 -1.56691,-5.68449 0.15485,-1.52924 1.08998,-2.94065 2.08922,-4.09812 0.69927,-0.81 2.11477,-0.89977 2.61152,-1.85076 1.58723,-3.03868 -0.0538,-6.87906 0.13057,-10.3114 0.24699,-4.59719 -0.0601,-8.61145 1.30576,-13.74853 z" + id="path3060" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.4120214;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="174.17461" + y="554.1217" + transform="scale(0.99384853,1.0061895)" + id="text3062" + xml:space="preserve" + style="font-size:21.02147293px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan + x="174.17461" + y="554.1217" + id="tspan3064">1</tspan></text> + <path + d="m 198.96079,536.76347 c -0.72412,-2.08754 -3.85535,-2.66829 -4.57016,-4.75911 -0.54398,-1.59114 0.41111,-4.84994 1.17518,-6.34548 0.8785,-1.71948 3.58403,-1.89878 5.4842,-2.11515 2.90308,-0.33058 4.65816,4.0255 5.87592,3.83372 1.55514,-0.1023 2.25449,-2.48793 3.7867,-2.77614 2.16939,-0.40808 4.92014,0.0599 6.39822,1.71856 1.6825,1.88803 1.99296,5.13094 1.17519,7.53525 -0.58155,1.70978 -3.24118,2.02778 -3.91728,3.70153 -1.5172,3.75593 0.59363,8.10493 0.5223,12.16216 -0.0785,4.46388 -2.44397,9.11811 -1.04461,13.35194 0.64577,1.9538 3.46637,2.65253 4.04786,4.62691 0.51535,1.74982 0.13809,3.85051 -0.78346,5.4201 -0.77839,1.32577 -2.19739,2.33161 -3.65612,2.77614 -1.41951,0.43258 -3.07626,0.32499 -4.43959,-0.26439 -1.5295,-0.66121 -2.02542,-3.10643 -3.65613,-3.43714 -1.72831,-0.35049 -2.54847,1.76353 -4.309,1.85077 -2.0667,0.1024 -5.1839,-0.11769 -6.65938,-1.58637 -1.38558,-1.37919 -1.76507,-3.72751 -1.56691,-5.68449 0.15485,-1.52924 1.08998,-2.94065 2.08921,-4.09812 0.69927,-0.81 2.11478,-0.89977 2.61152,-1.85076 1.58724,-3.03868 -0.0538,-6.87906 0.13058,-10.3114 0.24699,-4.59719 -0.0601,-8.61145 1.30576,-13.74853 z" + id="path3060-2" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.4120214;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="200.98058" + y="554.26031" + transform="scale(0.99384853,1.0061895)" + id="text3062-9" + xml:space="preserve" + style="font-size:21.02147293px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><tspan + x="200.98058" + y="554.26031" + id="tspan3064-9">2</tspan></text> + </g> +</svg> diff --git a/icons/new-game.svg b/icons/new-game.svg new file mode 100644 index 0000000..7dff35b --- /dev/null +++ b/icons/new-game.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Emacs --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + width="55" + height="55"> + <path + d="m 17,44 4,-13 -11,-8 13,0 5,-13 4,13 14,0 -11,8 4,13 -11,-8 z" + id="path6" + style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4" /> +</svg> diff --git a/icons/number-0.svg b/icons/number-0.svg new file mode 100644 index 0000000..9ce05a1 --- /dev/null +++ b/icons/number-0.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">0</tspan></text> +</svg> diff --git a/icons/number-1.svg b/icons/number-1.svg new file mode 100644 index 0000000..bffb371 --- /dev/null +++ b/icons/number-1.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">1</tspan></text> +</svg> diff --git a/icons/number-2.svg b/icons/number-2.svg new file mode 100644 index 0000000..297ad79 --- /dev/null +++ b/icons/number-2.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">2</tspan></text> +</svg> diff --git a/icons/number-3.svg b/icons/number-3.svg new file mode 100644 index 0000000..0cde39f --- /dev/null +++ b/icons/number-3.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">3</tspan></text> +</svg> diff --git a/icons/number-4.svg b/icons/number-4.svg new file mode 100644 index 0000000..bc27dd2 --- /dev/null +++ b/icons/number-4.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">4</tspan></text> +</svg> diff --git a/icons/number-5.svg b/icons/number-5.svg new file mode 100644 index 0000000..a47f8d1 --- /dev/null +++ b/icons/number-5.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">5</tspan></text> +</svg> diff --git a/icons/number-6.svg b/icons/number-6.svg new file mode 100644 index 0000000..19de7ef --- /dev/null +++ b/icons/number-6.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">6</tspan></text> +</svg> diff --git a/icons/number-7.svg b/icons/number-7.svg new file mode 100644 index 0000000..581999b --- /dev/null +++ b/icons/number-7.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">7</tspan></text> +</svg> diff --git a/icons/number-8.svg b/icons/number-8.svg new file mode 100644 index 0000000..e24a89c --- /dev/null +++ b/icons/number-8.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">8</tspan></text> +</svg> diff --git a/icons/number-9.svg b/icons/number-9.svg new file mode 100644 index 0000000..4ff26ff --- /dev/null +++ b/icons/number-9.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.0" + width="55" + height="55" + id="svg2"> + <defs + id="defs4" /> + <rect + width="50.94099" + height="50.940994" + rx="8.1506357" + ry="7.0263433" + x="2.0295048" + y="2.0295029" + id="rect2817" + style="fill:#000000;fill-opacity:1;stroke:#808080;stroke-width:4.05900621;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <text + x="14.980469" + y="42.060547" + id="text2394" + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan + x="14.980469" + y="42.060547" + id="tspan2396">9</tspan></text> +</svg> diff --git a/po/Napier.pot b/po/Napier.pot new file mode 100644 index 0000000..ac23756 --- /dev/null +++ b/po/Napier.pot @@ -0,0 +1,78 @@ +# 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: 2011-04-19 09:01-0400\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" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: activity/activity.info:2 +msgid "Napier" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:283 +msgid "Select a bone" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:299 +msgid "Bones" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:300 +msgid "Results" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:307 +msgid "Clear" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:311 +msgid "zero" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:314 +msgid "one" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:317 +msgid "two" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:320 +msgid "three" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:323 +msgid "four" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:326 +msgid "five" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:329 +msgid "six" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:332 +msgid "seven" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:335 +msgid "eight" +msgstr "" + +#: /home/walter/Desktop/Activities/napier/NapierActivity.py:338 +msgid "nine" +msgstr "" diff --git a/sprites.py b/sprites.py new file mode 100644 index 0000000..c633397 --- /dev/null +++ b/sprites.py @@ -0,0 +1,453 @@ +# -*- coding: utf-8 -*- + +#Copyright (c) 2007-8, Playful Invention Company. +#Copyright (c) 2008-10 Walter Bender + +#Permission is hereby granted, free of charge, to any person obtaining a copy +#of this software and associated documentation files (the "Software"), to deal +#in the Software without restriction, including without limitation the rights +#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the Software is +#furnished to do so, subject to the following conditions: + +#The above copyright notice and this permission notice shall be included in +#all copies or substantial portions of the Software. + +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +#THE SOFTWARE. + +""" + +sprites.py is a simple sprites library for managing graphics objects, +'sprites', on a canvas. It manages multiple sprites with methods such +as move, hide, set_layer, etc. + +There are two classes: + +class Sprites maintains a collection of sprites. +class Sprite manages individual sprites within the collection. + +Example usage: + # Import the classes into your program. + from sprites import Sprites Sprite + + # In your expose callback event handler, call refresh + def _expose_cb(self, win, event): + self.sprite_list.refresh(event) + return True + + # Create a new sprite collection for a gtk Drawing Area. + my_drawing_area = gtk.DrawingArea() + self.sprite_list = Sprites(my_drawing_area) + + # Create a "pixbuf" (in this example, from SVG). + my_pixbuf = svg_str_to_pixbuf("<svg>...some svg code...</svg>") + + # Create a sprite at position x1, y1. + my_sprite = sprites.Sprite(self.sprite_list, x1, y1, my_pixbuf) + + # Move the sprite to a new position. + my_sprite.move_relative((dx, dy)) + + # Create another "pixbuf". + your_pixbuf = svg_str_to_pixbuf("<svg>...some svg code...</svg>") + + # Create a sprite at position x2, y2. + your_sprite = sprites.Sprite(self.sprite_list, x2, y2, my_pixbuf) + + # Assign the sprites to layers. + # In this example, your_sprite will be on top of my_sprite. + my_sprite.set_layer(100) + your_sprite.set_layer(200) + + # Now put my_sprite on top of your_sprite. + my_sprite.set_layer(300) + +# method for converting SVG to a gtk pixbuf +def svg_str_to_pixbuf(svg_string): + pl = gtk.gdk.PixbufLoader('svg') + pl.write(svg_string) + pl.close() + pixbuf = pl.get_pixbuf() + return pixbuf +""" + +import pygtk +pygtk.require('2.0') +import gtk +import pango + + +class Sprites: + """ A class for the list of sprites and everything they share in common """ + + def __init__(self, canvas, area=None, gc=None): + """ Initialize an empty array of sprites """ + self.canvas = canvas + if area == None: + self.area = self.canvas.window + self.gc = self.area.new_gc() + else: + self.area = area + self.gc = gc + self.cm = self.gc.get_colormap() + self.list = [] + + def get_sprite(self, i): + """ Return a sprint from the array """ + if i < 0 or i > len(self.list) - 1: + return(None) + else: + return(self.list[i]) + + def length_of_list(self): + """ How many sprites are there? """ + return(len(self.list)) + + def append_to_list(self, spr): + """ Append a new sprite to the end of the list. """ + self.list.append(spr) + + def insert_in_list(self, spr, i): + """ Insert a sprite at position i. """ + if i < 0: + self.list.insert(0, spr) + elif i > len(self.list) - 1: + self.list.append(spr) + else: + self.list.insert(i, spr) + + def remove_from_list(self, spr): + """ Remove a sprite from the list. """ + if spr in self.list: + self.list.remove(spr) + + def find_sprite(self, pos, alpha=True): + """ Search based on (x, y) position. Return the 'top/first' one. """ + list = self.list[:] + list.reverse() + for spr in list: + if spr.hit(pos): + if not alpha or spr.get_pixel(pos)[3] == 255: + return spr + return None + + def refresh(self, event): + """ Handle expose event refresh """ + self.redraw_sprites(event.area) + + def redraw_sprites(self, area=None): + """ Redraw the sprites that intersect area. """ + for spr in self.list: + if area == None: + spr.draw() + else: + intersection = spr.rect.intersect(area) + if intersection.width > 0 or intersection.height > 0: + spr.draw() + + +class Sprite: + """ A class for the individual sprites """ + + def __init__(self, sprites, x, y, image): + """ Initialize an individual sprite """ + self._sprites = sprites + self.rect = gtk.gdk.Rectangle(int(x), int(y), 0, 0) + self._scale = [12] + self._rescale = [True] + self._horiz_align = ["center"] + self._vert_align = ["middle"] + self._fd = None + self._bold = False + self._italic = False + self._color = None + self._margins = [0, 0, 0, 0] + self.layer = 100 + self.labels = [] + self.images = [] + self._dx = [] # image offsets + self._dy = [] + self.set_image(image) + if self._sprites is not None: + self._sprites.append_to_list(self) + + def set_image(self, image, i=0, dx=0, dy=0): + """ Add an image to the sprite. """ + while len(self.images) < i + 1: + self.images.append(None) + self._dx.append(0) + self._dy.append(0) + self.images[i] = image + self._dx[i] = dx + self._dy[i] = dy + if isinstance(self.images[i], gtk.gdk.Pixbuf): + w = self.images[i].get_width() + h = self.images[i].get_height() + else: + w, h = self.images[i].get_size() + if i == 0: # Always reset width and height when base image changes. + self.rect.width = w + dx + self.rect.height = h + dy + else: + if w + dx > self.rect.width: + self.rect.width = w + dx + if h + dy > self.rect.height: + self.rect.height = h + dy + + def move(self, pos, visible=True): + """ Move to new (x, y) position """ + if visible: + self.inval() + self.rect.x, self.rect.y = int(pos[0]), int(pos[1]) + if visible: + self.inval() + + def move_relative(self, pos, visible=True): + """ Move to new (x+dx, y+dy) position """ + if visible: + self.inval() + self.rect.x += int(pos[0]) + self.rect.y += int(pos[1]) + if visible: + self.inval() + + def get_xy(self): + """ Return current (x, y) position """ + return (self.rect.x, self.rect.y) + + def get_dimensions(self): + """ Return current size """ + return (self.rect.width, self.rect.height) + + def get_layer(self): + """ Return current layer """ + return self.layer + + def set_shape(self, image, i=0): + """ Set the current image associated with the sprite """ + self.inval() + self.set_image(image, i) + self.inval() + + def set_layer(self, layer): + """ Set the layer for a sprite """ + if self._sprites is None: + return + self._sprites.remove_from_list(self) + self.layer = layer + for i in range(self._sprites.length_of_list()): + if layer < self._sprites.get_sprite(i).layer: + self._sprites.insert_in_list(self, i) + self.inval() + return + self._sprites.append_to_list(self) + self.inval() + + def set_label(self, new_label, i=0): + """ Set the label drawn on the sprite """ + self._extend_labels_array(i) + if type(new_label) is str or type(new_label) is unicode: + # pango doesn't like nulls + self.labels[i] = new_label.replace("\0", " ") + else: + self.labels[i] = str(new_label) + self.inval() + + def set_margins(self, l=0, t=0, r=0, b=0): + """ Set the margins for drawing the label """ + self._margins = [l, t, r, b] + + def _extend_labels_array(self, i): + """ Append to the labels attribute list """ + if self._fd is None: + self.set_font('Sans') + if self._color is None: + self._color = self._sprites.cm.alloc_color('black') + while len(self.labels) < i + 1: + self.labels.append(" ") + self._scale.append(self._scale[0]) + self._rescale.append(self._rescale[0]) + self._horiz_align.append(self._horiz_align[0]) + self._vert_align.append(self._vert_align[0]) + + def set_font(self, font): + """ Set the font for a label """ + self._fd = pango.FontDescription(font) + + def set_label_color(self, rgb): + """ Set the font color for a label """ + self._color = self._sprites.cm.alloc_color(rgb) + + def set_label_attributes(self, scale, rescale=True, horiz_align="center", + vert_align="middle", i=0): + """ Set the various label attributes """ + self._extend_labels_array(i) + self._scale[i] = scale + self._rescale[i] = rescale + self._horiz_align[i] = horiz_align + self._vert_align[i] = vert_align + + def hide(self): + """ Hide a sprite """ + if self._sprites is None: + return + self.inval() + self._sprites.remove_from_list(self) + + def inval(self): + """ Force a region redraw by gtk """ + if self._sprites is None: + return + self._sprites.area.invalidate_rect(self.rect, False) + + def draw(self): + """ Draw the sprite (and label) """ + if self._sprites is None: + return + for i, img in enumerate(self.images): + if isinstance(img, gtk.gdk.Pixbuf): + self._sprites.area.draw_pixbuf(self._sprites.gc, img, 0, 0, + self.rect.x + self._dx[i], + self.rect.y + self._dy[i]) + elif img is not None: + self._sprites.area.draw_drawable(self._sprites.gc, img, 0, 0, + self.rect.x + self._dx[i], + self.rect.y + self._dy[i], + -1, -1) + if len(self.labels) > 0: + self.draw_label() + + def hit(self, pos): + """ Is (x, y) on top of the sprite? """ + x, y = pos + if x < self.rect.x: + return False + if x > self.rect.x + self.rect.width: + return False + if y < self.rect.y: + return False + if y > self.rect.y + self.rect.height: + return False + return True + + def draw_label(self): + """ Draw the label based on its attributes """ + if self._sprites is None: + return + my_width = self.rect.width - self._margins[0] - self._margins[2] + if my_width < 0: + my_width = 0 + my_height = self.rect.height - self._margins[1] - self._margins[3] + for i in range(len(self.labels)): + pl = self._sprites.canvas.create_pango_layout(str(self.labels[i])) + self._fd.set_size(int(self._scale[i] * pango.SCALE)) + pl.set_font_description(self._fd) + w = pl.get_size()[0] / pango.SCALE + if w > my_width: + if self._rescale[i]: + self._fd.set_size( + int(self._scale[i] * pango.SCALE * my_width / w)) + pl.set_font_description(self._fd) + w = pl.get_size()[0] / pango.SCALE + else: + j = len(self.labels[i]) - 1 + while(w > my_width and j > 0): + pl = self._sprites.canvas.create_pango_layout( + "…" + self.labels[i][len(self.labels[i]) - j:]) + self._fd.set_size(int(self._scale[i] * pango.SCALE)) + pl.set_font_description(self._fd) + w = pl.get_size()[0] / pango.SCALE + j -= 1 + if self._horiz_align[i] == "center": + x = int(self.rect.x + self._margins[0] + (my_width - w) / 2) + elif self._horiz_align[i] == 'left': + x = int(self.rect.x + self._margins[0]) + else: # right + x = int(self.rect.x + self.rect.width - w - self._margins[2]) + h = pl.get_size()[1] / pango.SCALE + if self._vert_align[i] == "middle": + y = int(self.rect.y + self._margins[1] + (my_height - h) / 2) + elif self._vert_align[i] == "top": + y = int(self.rect.y + self._margins[1]) + else: # bottom + y = int(self.rect.y + self.rect.height - h - self._margins[3]) + self._sprites.gc.set_foreground(self._color) + self._sprites.area.draw_layout(self._sprites.gc, x, y, pl) + + def label_width(self): + """ Calculate the width of a label """ + max = 0 + for i in range(len(self.labels)): + pl = self._sprites.canvas.create_pango_layout(self.labels[i]) + self._fd.set_size(int(self._scale[i] * pango.SCALE)) + pl.set_font_description(self._fd) + w = pl.get_size()[0] / pango.SCALE + if w > max: + max = w + return max + + def label_safe_width(self): + """ Return maximum width for a label """ + return self.rect.width - self._margins[0] - self._margins[2] + + def label_safe_height(self): + """ Return maximum height for a label """ + return self.rect.height - self._margins[1] - self._margins[3] + + def label_left_top(self): + """ Return the upper-left corner of the label safe zone """ + return(self._margins[0], self._margins[1]) + + def get_pixel(self, pos, i=0, mode='888'): + """ Return the pixel at (x, y) """ + x, y = pos + x = x - self.rect.x + y = y - self.rect.y + if isinstance(self.images[i], gtk.gdk.Pixbuf): + if y > self.images[i].get_height() - 1: + return(-1, -1, -1, -1) + array = self.images[i].get_pixels() + if array is not None: + try: + if self.images[i].get_has_alpha(): + offset = (y * self.images[i].get_width() + x) * 4 + a = ord(array[offset + 3]) + else: + offset = (y * self.images[i].get_width() + x) * 3 + a = 255 + r = ord(array[offset]) + g = ord(array[offset + 1]) + b = ord(array[offset + 2]) + return(r, g, b, a) + except IndexError: + """ + print "Index Error: %d %d (%d, %d) (w: %d, h: %d) (%dx%d)"\ + % (len(array), offset, x, y, + self.images[i].get_width(), + self.images[i].get_height(), + self.rect.width, self.rect.height) + """ + pass + return(-1, -1, -1, -1) + else: + w, h = self.images[i].get_size() + if x < 0 or x > (w - 1) or y < 0 or y > (h - 1): + return(-1, -1, -1, -1) + image = self.images[i].get_image(x, y, 1, 1) + pixel = image.get_pixel(0, 0) + visual = self.images[i].get_visual() + r = int((pixel & visual.red_mask) >> visual.red_shift) + g = int((pixel & visual.green_mask) >> visual.green_shift) + b = int((pixel & visual.blue_mask) >> visual.blue_shift) + # Rescale to 8 bits + if mode == '565': + r = r << 3 + g = g << 2 + b = b << 3 + return(r, g, b, 0) |