Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflorent <florent.pigout@gmail.com>2011-02-24 02:09:07 (GMT)
committer florent <florent.pigout@gmail.com>2011-02-24 02:09:07 (GMT)
commit1bca40986ceccc80afb2c314fe70d6cb71d1e415 (patch)
tree40361b8f042f52ae2b3a97a476450c4af63a886b
parent1229ea068cba7a91b1459cc4ebd0cb638b33b68a (diff)
play with the graphics in default resolution 1024x468
-rw-r--r--activity.py6
-rw-r--r--atoidepoc/storage/__init__.py0
-rw-r--r--atoidepoc/storage/utils.py90
-rw-r--r--atoidepoc/tools/image.py69
-rw-r--r--atoidepoc/ui/screens.py155
-rw-r--r--static/graphics/CHIEN.pngbin0 -> 7632 bytes
-rw-r--r--static/graphics/CIEL.pngbin0 -> 150866 bytes
-rw-r--r--static/graphics/MAISONS.pngbin0 -> 840816 bytes
-rw-r--r--static/graphics/OVERLAY.pngbin0 -> 79574 bytes
-rw-r--r--static/graphics/PROMENEUR.pngbin0 -> 26558 bytes
-rw-r--r--static/graphics/ROUTE.pngbin0 -> 518733 bytes
-rw-r--r--static/graphics/demo.pngbin1196 -> 0 bytes
-rw-r--r--static/graphics/demo.svg232
-rw-r--r--static/graphics/mask_default.pngbin0 -> 10747 bytes
14 files changed, 212 insertions, 340 deletions
diff --git a/activity.py b/activity.py
index ec0dacd..de710d9 100644
--- a/activity.py
+++ b/activity.py
@@ -3,6 +3,11 @@
import logging
from gettext import gettext as _
+# gtk import
+import gobject
+# ...
+gobject.threads_init()
+
# sugar import
from sugar.activity import activity
@@ -13,6 +18,7 @@ from atoidepoc.ui import screens, toolbar
logger = logging.getLogger('atoidepoc')
logger.setLevel(logging.DEBUG)
+
class AToiDePocActivity(activity.Activity):
def __init__(self, handle):
diff --git a/atoidepoc/storage/__init__.py b/atoidepoc/storage/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/atoidepoc/storage/__init__.py
+++ /dev/null
diff --git a/atoidepoc/storage/utils.py b/atoidepoc/storage/utils.py
deleted file mode 100644
index f37b192..0000000
--- a/atoidepoc/storage/utils.py
+++ /dev/null
@@ -1,90 +0,0 @@
-
-# python import
-import logging, os
-
-# gtk import
-import gtk
-
-# sugar import
-from sugar.datastore import datastore
-
-# get application logger
-logger = logging.getLogger('atoidepoc')
-
-ACTIVITY_NAMES = {
- 'paint': 'org.laptop.Oficina'
- }
-
-
-def get_pixbuf_from_data(data, image_type=None, size=None):
- # load it
- if image_type:
- _loader = gtk.gdk.PixbufLoader(image_type=image_type)
- else:
- _loader = gtk.gdk.PixbufLoader()
- # size check
- if size is None:
- pass
- else:
- # parse size
- _w, _h = size
- # set loader size
- _loader.set_size(_w, _h)
- # load date
- _loader.write(data)
- # close loader
- _loader.close()
- # pix it
- return _loader.get_pixbuf()
-
-
-def get_journal_objects(activity_name):
- # prepare query
- _query = {'activity': ACTIVITY_NAMES[activity_name]}
- # find in ds
- _results, _count = datastore.find(_query, sorting='timestamp')
- # return it
- return _results
-
-
-def list_info_from_journal(activity_name):
- # get objects first
- _objs = get_journal_objects(activity_name)
- # make unique titles
- _titles = {}
- # return infos
- for _o in _objs:
- # get meta
- _m = _o.get_metadata()
- # get title
- _t = _m['title']
- # little check
- if _t in _titles:
- # udpate reg
- _titles[_t] += 1
- # update value to show
- _t = '%s (%s)' % (_t, _titles[_t])
- # init title reg
- else:
- _titles[_t] = 1
- # ensure info
- yield {
- 'description' : _m['description'],
- 'activity_id' : _m['activity_id'],
- 'timestamp' : _m['timestamp'],
- 'preview' : _m['preview'],
- 'title' : _t,
- }
-
-
-def list_files_from_journal(activity_name):
- # get objects first
- _objs = get_journal_objects(activity_name)
- # return paths
- for _o in _objs:
- # TODO open the files
- yield _o.get_file_path()
-
-
-def open_file_from_journal(activity_name, file_id):
- pass
diff --git a/atoidepoc/tools/image.py b/atoidepoc/tools/image.py
new file mode 100644
index 0000000..f995506
--- /dev/null
+++ b/atoidepoc/tools/image.py
@@ -0,0 +1,69 @@
+
+# python import
+import struct, StringIO
+
+def get_image_info(path):
+ """Tricky method found on Internet that returns the image info from a given
+ raw image data.
+ """
+ # read file
+ _f = open(path)
+ _data = _f.read()
+ _f.close()
+ #
+ size = len(_data)
+ height = None
+ width = None
+ content_type = None
+
+ # handle GIFs
+ if (size >= 10) and _data[:6] in ('GIF87a', 'GIF89a'):
+ # Check to see if content_type is correct
+ content_type = 'image/gif'
+ w, h = struct.unpack("<HH", _data[6:10])
+ width = int(w)
+ height = int(h)
+
+ # See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
+ # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
+ # and finally the 4-byte width, height
+ elif ((size >= 24) and _data.startswith('\211PNG\r\n\032\n')
+ and (_data[12:16] == 'IHDR')):
+ content_type = 'image/png'
+ w, h = struct.unpack(">LL", _data[16:24])
+ width = int(w)
+ height = int(h)
+
+ # Maybe this is for an older PNG version.
+ elif (size >= 16) and _data.startswith('\211PNG\r\n\032\n'):
+ # Check to see if we have the right content type
+ content_type = 'image/png'
+ w, h = struct.unpack(">LL", _data[8:16])
+ width = int(w)
+ height = int(h)
+
+ # handle JPEGs
+ elif (size >= 2) and _data.startswith('\377\330'):
+ content_type = 'image/jpeg'
+ jpeg = StringIO.StringIO(_data)
+ jpeg.read(2)
+ b = jpeg.read(1)
+ try:
+ while (b and ord(b) != 0xDA):
+ while (ord(b) != 0xFF): b = jpeg.read(1)
+ while (ord(b) == 0xFF): b = jpeg.read(1)
+ if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
+ jpeg.read(3)
+ h, w = struct.unpack(">HH", jpeg.read(4))
+ break
+ else:
+ jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
+ b = jpeg.read(1)
+ width = int(w)
+ height = int(h)
+ except struct.error:
+ pass
+ except ValueError:
+ pass
+
+ return content_type, width, height
diff --git a/atoidepoc/ui/screens.py b/atoidepoc/ui/screens.py
index 2db1f99..0371c45 100644
--- a/atoidepoc/ui/screens.py
+++ b/atoidepoc/ui/screens.py
@@ -1,6 +1,6 @@
# python import
-import logging, os
+import logging, os, threading, time
from gettext import gettext as _
# gtk import
@@ -11,7 +11,7 @@ from sugar.activity import activity
from sugar.graphics import style
# atoidepoc import
-from atoidepoc.tools import sound, storage
+from atoidepoc.tools import image, sound, storage
# get application logger
logger = logging.getLogger('atoidepoc')
@@ -105,6 +105,64 @@ class ScreenBrowserSounds(ScreenBrowser):
ScreenBrowser.__init__(self, toolbar, title=_('Sounds'),
_type='sound')
+PROMENEUR_KEYS = [(20, 12), (40, 12), (60, 12), (80, 12), (100, 12), (80, 12),
+ (100, 12), (120, 12), (100, 12), (80, 12), (60, 12), (80, 12),
+ (100, 12), (120, 12), (140, 12), (160, 12), (120, 12), (200, 12),
+ (120, 12), (200, 12), (220, 12), (220, 12), (220, 12), (220, 12)]
+
+CHIEN_KEYS = [(80, 54), (100, 32), (80, 54), (100, 32), (120, 54), (140, 32),
+ (140, 54), (160, 32), (200, 54), (200, 32), (220, 54), (240, 32),
+ (260, 54), (240, 32), (220, 54), (200, 32), (180, 54), (160, 32),
+ (200, 54), (200, 32), (220, 54), (240, 32), (160, 54), (280, 32)]
+
+MAISONS_KEYS = [(0, 0), (0, 2), (2, 4), (0, 2), (2, 0), (2, 2),
+ (0, 4), (0, 6), (-2, 8), (0, 6), (-2, 4), (0, 2),
+ (0, 2), (2, 2), (0, 0), (-2, 2), (0, 4), (2, 6),
+ (0, 8), (0, 6), (0, 4), (-2, 2), (-2, 2), (0, 0)]
+
+CIEL_KEYS = [(0, -9) for _i in range(24)]
+
+BOTTOM_KEYS = [(0, 16) for _i in range(24)]
+
+DEFAULT_KEYS = [(0, 0) for _i in range(24)]
+
+ALL_KEYS = {
+ 'CIEL': CIEL_KEYS,
+ 'MAISONS': MAISONS_KEYS,
+ 'ROUTE': DEFAULT_KEYS,
+ 'PROMENEUR': PROMENEUR_KEYS,
+ 'CHIEN': CHIEN_KEYS,
+ 'OVERLAY': DEFAULT_KEYS,
+ 'mask_default': DEFAULT_KEYS,
+ }
+
+NAMES = [
+ 'CIEL',
+ 'MAISONS',
+ 'ROUTE',
+ 'PROMENEUR',
+ 'CHIEN',
+ 'OVERLAY',
+ 'mask_default',
+ ]
+
+
+class ThreadMove(threading.Thread):
+
+ def __init__(self, fixed, filename):
+ # init parent
+ threading.Thread.__init__(self)
+ # ...
+ self._fixed = fixed
+ self._filename = filename
+
+ def run(self):
+ for _align in ALL_KEYS[self._filename]:
+ # ...
+ self._fixed._move_image(self._filename, align=_align)
+ # ...
+ time.sleep(1)
+
class ScreenStory(gtk.Fixed):
@@ -113,36 +171,79 @@ class ScreenStory(gtk.Fixed):
gtk.Fixed.__init__(self)
# keep toolbar
self.toolbar = toolbar
+ # init image dict
+ self.__graphics = dict()
+ self.__sizes = dict()
+ self.__positions = dict()
+ # keep some info
+ self._screen_height = gtk.gdk.screen_height()
+ self._screen_width = gtk.gdk.screen_width()
# render
self._render()
# and show
self._show()
+ # do anim
+ for _n in NAMES:
+ self._anim(_n)
+
+ def _anim(self, filename):
+ # init thread
+ _t = ThreadMove(self, filename)
+ # start it
+ _t.start()
def _render(self):
# png check
- self._add_image('demo.png', align=(0,0))
- self._add_image('demo.png', align=(200, 0), size=(100, 100))
- # png check
- self._add_image('demo.svg', align=(0, 200))
- self._add_image('demo.svg', align=(200, 200), size=(100, 100))
+ self._add_image('CIEL', align=(0, -10))
+ self._add_image('MAISONS', align=(0, 0))
+ self._add_image('ROUTE', align=(0, 16))
+ self._add_image('PROMENEUR', align=(0, 16))
+ self._add_image('CHIEN', align=(0, 16))
+ self._add_image('OVERLAY', align=(0, 0))
+ # add border
+ self._add_image('mask_default', align=(0, 0))
+
+ def _get_image_path(self, filename):
+ return os.path.join(activity.get_bundle_path(),
+ 'static', 'graphics', '%s.png' % filename)
+
+ def _update_x_y(self, width, height, x, y):
+ # update x
+ x = ((gtk.gdk.screen_width() - width) / 2) + x
+ # update y
+ y = ((gtk.gdk.screen_height() - height - + 88) / 2) + y
+ # return it
+ return x, y
- def _add_image(self, filename, align=None, size=None):
- # get graphics path
- _path = os.path.join(activity.get_bundle_path(),
- 'static', 'graphics', filename)
- # add a picture here
- _image = gtk.Image()
+ def _move_image(self, filename, align=None):
+ # get graphic from dict
+ _image = self.__graphics[filename]
# set alignment
if align is None:
- _x = 0
- _y = 0
+ # use current position by default
+ _x , _y = self.__positions[filename]
else:
# parse align value
_x, _y = align
+ # get image size
+ _w, _h = self.__sizes[filename]
+ # update x, y
+ _x, _y = self._update_x_y(_w, _h, _x, _y)
+ self.__positions[filename] = (_x, _y)
+ # move
+ self.move(_image, _x, _y)
+
+ def _add_image(self, filename, align=None, size=None):
+ # get graphics path
+ _path = self._get_image_path(filename)
+ # add a picture here
+ _image = gtk.Image()
# set size
if size is None:
# set file
_image.set_from_file(_path)
+ # get file size
+ _c, _w, _h = image.get_image_info(_path)
else:
# parse size value
_w, _h = size
@@ -151,16 +252,34 @@ class ScreenStory(gtk.Fixed):
# do resize and set image
_image.set_from_pixbuf(
_pixbuf.scale_simple(_w, _h, gtk.gdk.INTERP_BILINEAR))
- # TODO manage cb for dnd
+ # set alignment
+ if align is None:
+ _x = 0
+ _y = 0
+ else:
+ # parse align value
+ _x, _y = align
+ # TODO manage cb for click or dnd
# ...
# show
_image.show()
+ # update graphic dict
+ self.__graphics[filename] = _image
+ self.__sizes[filename] = (_w, _h)
+ # update x, y
+ _x, _y = self._update_x_y(_w, _h, _x, _y)
+ self.__positions[filename] = (_x, _y)
# add
self.put(_image, _x, _y)
def _show(self):
# show self
self.show()
+
+ # DEBUG
+ logger.debug('[screen_story] _show - width: %s' % gtk.gdk.screen_width())
+ # DEBUG
+
# update toolbar
self.toolbar.activity.set_canvas(self)
@@ -202,8 +321,8 @@ class ScreenPlayerSounds(ScreenPlayer):
def render(self):
# init 2 players
- _s_player_1 = sound.Player(soundfile='/home/florent/shared/demo1.ogg')
- _s_player_2 = sound.Player(soundfile='/home/florent/shared/demo2.ogg')
+ _s_player_1 = sound.Player(soundfile='/home/sugar/shared/demo1.ogg')
+ _s_player_2 = sound.Player(soundfile='/home/sugar/shared/demo2.ogg')
# get duration
_d1 = _s_player_1.get_duration()
diff --git a/static/graphics/CHIEN.png b/static/graphics/CHIEN.png
new file mode 100644
index 0000000..ebe9d02
--- /dev/null
+++ b/static/graphics/CHIEN.png
Binary files differ
diff --git a/static/graphics/CIEL.png b/static/graphics/CIEL.png
new file mode 100644
index 0000000..6a2958f
--- /dev/null
+++ b/static/graphics/CIEL.png
Binary files differ
diff --git a/static/graphics/MAISONS.png b/static/graphics/MAISONS.png
new file mode 100644
index 0000000..64a9dd0
--- /dev/null
+++ b/static/graphics/MAISONS.png
Binary files differ
diff --git a/static/graphics/OVERLAY.png b/static/graphics/OVERLAY.png
new file mode 100644
index 0000000..d539424
--- /dev/null
+++ b/static/graphics/OVERLAY.png
Binary files differ
diff --git a/static/graphics/PROMENEUR.png b/static/graphics/PROMENEUR.png
new file mode 100644
index 0000000..f3a8788
--- /dev/null
+++ b/static/graphics/PROMENEUR.png
Binary files differ
diff --git a/static/graphics/ROUTE.png b/static/graphics/ROUTE.png
new file mode 100644
index 0000000..3442fbd
--- /dev/null
+++ b/static/graphics/ROUTE.png
Binary files differ
diff --git a/static/graphics/demo.png b/static/graphics/demo.png
deleted file mode 100644
index af96edc..0000000
--- a/static/graphics/demo.png
+++ /dev/null
Binary files differ
diff --git a/static/graphics/demo.svg b/static/graphics/demo.svg
deleted file mode 100644
index bdfad6f..0000000
--- a/static/graphics/demo.svg
+++ /dev/null
@@ -1,232 +0,0 @@
-<?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"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- version="1.0"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="0.47 r22583"
- sodipodi:docname="activity-atoidepoc.svg"
- width="55"
- height="55"
- inkscape:output_extension="org.inkscape.output.svg.inkscape">
- <metadata
- id="metadata371">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <sodipodi:namedview
- inkscape:window-height="882"
- inkscape:window-width="1233"
- inkscape:pageshadow="2"
- inkscape:pageopacity="0.0"
- guidetolerance="10.0"
- gridtolerance="10.0"
- objecttolerance="10.0"
- borderopacity="1.0"
- bordercolor="#666666"
- pagecolor="#ffffff"
- id="base"
- inkscape:zoom="4.2923284"
- inkscape:cx="63.342591"
- inkscape:cy="51.710699"
- inkscape:window-x="168"
- inkscape:window-y="24"
- inkscape:current-layer="svg2"
- width="210mm"
- height="40mm"
- units="mm"
- showgrid="false"
- inkscape:window-maximized="0" />
- <defs
- id="defs4">
- <inkscape:perspective
- sodipodi:type="inkscape:persp3d"
- inkscape:vp_x="0 : 71.887497 : 1"
- inkscape:vp_y="0 : 1000 : 0"
- inkscape:vp_z="486.04999 : 71.887497 : 1"
- inkscape:persp3d-origin="243.02499 : 47.924998 : 1"
- id="perspective46" />
- <linearGradient
- id="linearGradient2795">
- <stop
- style="stop-color: rgb(184, 184, 184); stop-opacity: 0.498039;"
- offset="0"
- id="stop2797" />
- <stop
- style="stop-color: rgb(127, 127, 127); stop-opacity: 0;"
- offset="1"
- id="stop2799" />
- </linearGradient>
- <linearGradient
- id="linearGradient2787">
- <stop
- style="stop-color: rgb(127, 127, 127); stop-opacity: 0.5;"
- offset="0"
- id="stop2789" />
- <stop
- style="stop-color: rgb(127, 127, 127); stop-opacity: 0;"
- offset="1"
- id="stop2791" />
- </linearGradient>
- <linearGradient
- id="linearGradient3676">
- <stop
- style="stop-color: rgb(178, 178, 178); stop-opacity: 0.5;"
- offset="0"
- id="stop3678" />
- <stop
- style="stop-color: rgb(179, 179, 179); stop-opacity: 0;"
- offset="1"
- id="stop3680" />
- </linearGradient>
- <linearGradient
- id="linearGradient3236">
- <stop
- style="stop-color: rgb(244, 244, 244); stop-opacity: 1;"
- offset="0"
- id="stop3244" />
- <stop
- style="stop-color: white; stop-opacity: 1;"
- offset="1"
- id="stop3240" />
- </linearGradient>
- <linearGradient
- id="linearGradient4671">
- <stop
- style="stop-color: rgb(255, 212, 59); stop-opacity: 1;"
- offset="0"
- id="stop4673" />
- <stop
- style="stop-color: rgb(255, 232, 115); stop-opacity: 1;"
- offset="1"
- id="stop4675" />
- </linearGradient>
- <linearGradient
- id="linearGradient4689">
- <stop
- style="stop-color: rgb(90, 159, 212); stop-opacity: 1;"
- offset="0"
- id="stop4691" />
- <stop
- style="stop-color: rgb(48, 105, 152); stop-opacity: 1;"
- offset="1"
- id="stop4693" />
- </linearGradient>
- <linearGradient
- x1="224.23996"
- y1="144.75717"
- x2="-65.308502"
- y2="144.75717"
- id="linearGradient2987"
- xlink:href="#linearGradient4671"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(100.27,99.6112)" />
- <linearGradient
- x1="172.94208"
- y1="77.475983"
- x2="26.670298"
- y2="76.313133"
- id="linearGradient2990"
- xlink:href="#linearGradient4689"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(100.27,99.6112)" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4689"
- id="linearGradient2587"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(100.27,99.6112)"
- x1="172.94208"
- y1="77.475983"
- x2="26.670298"
- y2="76.313133" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4671"
- id="linearGradient2589"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(100.27,99.6112)"
- x1="224.23996"
- y1="144.75717"
- x2="-65.308502"
- y2="144.75717" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4689"
- id="linearGradient2248"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(100.27,99.6112)"
- x1="172.94208"
- y1="77.475983"
- x2="26.670298"
- y2="76.313133" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4671"
- id="linearGradient2250"
- gradientUnits="userSpaceOnUse"
- gradientTransform="translate(100.27,99.6112)"
- x1="224.23996"
- y1="144.75717"
- x2="-65.308502"
- y2="144.75717" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4671"
- id="linearGradient2255"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.562541,0,0,0.567972,-11.5974,-7.60954)"
- x1="224.23996"
- y1="144.75717"
- x2="-65.308502"
- y2="144.75717" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4689"
- id="linearGradient2258"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.562541,0,0,0.567972,-11.5974,-7.60954)"
- x1="172.94208"
- y1="76.176224"
- x2="26.670298"
- y2="76.313133" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient2795"
- id="radialGradient2801"
- cx="61.518883"
- cy="132.28575"
- fx="61.518883"
- fy="132.28575"
- r="29.036913"
- gradientTransform="matrix(1,0,0,0.177966,0,108.743)"
- gradientUnits="userSpaceOnUse" />
- </defs>
- <g
- id="g2847"
- transform="matrix(0.46766264,0,0,0.46766264,-1.1078811,-1.5517981)">
- <path
- id="path1948"
- d="m 60.510156,6.3979729 c -4.583653,0.021298 -8.960939,0.4122177 -12.8125,1.09375 C 36.35144,9.4962267 34.291407,13.691825 34.291406,21.429223 l 0,10.21875 26.8125,0 0,3.40625 -26.8125,0 -10.0625,0 c -7.792459,0 -14.6157592,4.683717 -16.7500002,13.59375 -2.46182,10.212966 -2.5710151,16.586023 0,27.25 1.9059283,7.937852 6.4575432,13.593748 14.2500002,13.59375 l 9.21875,0 0,-12.25 c 0,-8.849902 7.657144,-16.656248 16.75,-16.65625 l 26.78125,0 c 7.454951,0 13.406253,-6.138164 13.40625,-13.625 l 0,-25.53125 c 0,-7.266339 -6.12998,-12.7247775 -13.40625,-13.9375001 -4.605987,-0.7667253 -9.385097,-1.1150483 -13.96875,-1.09375 z m -14.5,8.2187501 c 2.769547,0 5.03125,2.298646 5.03125,5.125 -2e-6,2.816336 -2.261703,5.09375 -5.03125,5.09375 -2.779476,-1e-6 -5.03125,-2.277415 -5.03125,-5.09375 -1e-6,-2.826353 2.251774,-5.125 5.03125,-5.125 z"
- style="fill:#000000;fill-opacity:1" />
- <path
- id="path1950"
- d="m 91.228906,35.054223 0,11.90625 c 0,9.230755 -7.825895,16.999999 -16.75,17 l -26.78125,0 c -7.335833,0 -13.406249,6.278483 -13.40625,13.625 l 0,25.531247 c 0,7.26634 6.318588,11.54032 13.40625,13.625 8.487331,2.49561 16.626237,2.94663 26.78125,0 6.750155,-1.95439 13.406253,-5.88761 13.40625,-13.625 l 0,-10.218747 -26.78125,0 0,-3.40625 26.78125,0 13.406254,0 c 7.79246,0 10.69625,-5.435408 13.40624,-13.59375 2.79933,-8.398886 2.68022,-16.475776 0,-27.25 -1.92578,-7.757441 -5.60387,-13.59375 -13.40624,-13.59375 l -10.062504,0 z m -15.0625,64.65625 c 2.779478,3e-6 5.03125,2.277417 5.03125,5.093747 -2e-6,2.82635 -2.251775,5.125 -5.03125,5.125 -2.76955,0 -5.03125,-2.29865 -5.03125,-5.125 2e-6,-2.81633 2.261697,-5.093747 5.03125,-5.093747 z"
- style="fill:#000000;fill-opacity:1" />
- </g>
-</svg>
diff --git a/static/graphics/mask_default.png b/static/graphics/mask_default.png
new file mode 100644
index 0000000..5e9c1d1
--- /dev/null
+++ b/static/graphics/mask_default.png
Binary files differ