Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@member.fsf.org>2009-02-11 14:19:46 (GMT)
committer Aleksey Lim <alsroot@member.fsf.org>2009-02-11 14:19:46 (GMT)
commit4ea603bdfbe16d48ff01615b15d62cd53c7641d5 (patch)
tree206033446038959974e548a45ab9ef7e6a4c6fe9
parent68feb6abb7fa6803da378c94c69d59faea530867 (diff)
Refactoring gui, checkpoint #2
-rw-r--r--activity.py196
-rw-r--r--icons/media-playback-start-back.svg79
-rw-r--r--icons/tempo1.svg8
-rw-r--r--icons/tempo2.svg9
-rw-r--r--icons/tempo3.svg8
-rw-r--r--icons/tempo4.svg9
-rw-r--r--icons/tempo5.svg9
-rw-r--r--icons/tempo6.svg11
-rw-r--r--icons/tempo7.svg9
-rw-r--r--icons/tempo8.svg10
-rw-r--r--lessons.py81
-rw-r--r--montage.py (renamed from flipsticks.py)176
-rw-r--r--screen.py2
-rw-r--r--shared.py131
-rw-r--r--theme.py20
-rw-r--r--utils.py89
16 files changed, 713 insertions, 134 deletions
diff --git a/activity.py b/activity.py
index 6a89e0b..86f3a4a 100644
--- a/activity.py
+++ b/activity.py
@@ -12,43 +12,191 @@
# 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 gtk
-from sugar.activity import activity
-from sugar.presence import presenceservice
-from sugar.presence.tubeconn import TubeConnection
-import telepathy
-import telepathy.client
-from dbus import Interface
-from dbus.service import method, signal
-from dbus.gobject_service import ExportedGObject
+from gettext import gettext as _
+
+from sugar.activity.activity import Activity, ActivityToolbox
+from sugar.graphics.toggletoolbutton import ToggleToolButton
+from sugar.graphics.toolbutton import ToolButton
import model
+import montage
+import lessons
+import messenger
+from shared import SharedActivity
from theme import *
-from flipsticks import flipsticks
+from utils import *
-class flipsticksActivity(activity.Activity):
+class flipsticksActivity(SharedActivity):
def __init__(self, handle):
- activity.Activity.__init__(self,handle)
- bundle_path = activity.get_bundle_path()
- os.chdir(bundle_path)
- self.set_title('FlipSticks')
- toolbox = activity.ActivityToolbox(self)
- self.set_toolbox(toolbox)
+ self.notebook = gtk.Notebook()
+ SharedActivity.__init__(self, self.notebook, messenger.SERVICE, handle)
+
+ self.notebook.show()
+ self.notebook.props.show_border = False
+ self.notebook.props.show_tabs = False
+
+ self.montage = montage.View(self)
+ self.notebook.append_page(self.montage)
+ self.lessons = lessons.View()
+ self.lessons.show()
+ self.notebook.append_page(self.lessons)
+
+ toolbox = ActivityToolbox(self)
toolbox.show()
- if hasattr(self, '_jobject'):
- self._jobject.metadata['title'] = 'FlipSticks'
- title_widget = toolbox._activity_toolbar.title
- title_widget.set_size_request(title_widget.get_layout().get_pixel_size()[0] + 20, -1)
+ toolbox.connect('current-toolbar-changed', self._toolbar_changed_cb)
+ self.set_toolbox(toolbox)
- self.app = flipsticks(self, bundle_path)
+ montage_bar = MontageToolbar(self.montage)
+ montage_bar.show()
+ toolbox.add_toolbar(_('Montage'), montage_bar)
+ lessons_bar = LessonsToolbar()
+ lessons_bar.show()
+ toolbox.add_toolbar(_('Lessons'), lessons_bar)
- self.set_canvas(self.app)
+ toolbox.set_current_toolbar(1)
def read_file(self, filepath):
model.load(filepath)
- self.app.restore()
+ self.montage.restore()
def write_file(self, filepath):
model.save(filepath)
+
+ def _toolbar_changed_cb(self, widget, index):
+ if index == 2:
+ self.notebook.set_current_page(1)
+ else:
+ self.notebook.set_current_page(0)
+
+class MontageToolbar(gtk.Toolbar):
+ def __init__(self, montage):
+ gtk.Toolbar.__init__(self)
+ self.montage = montage
+
+ # edit buttons
+
+ setframe = ToolButton('dialog-ok')
+ setframe.connect('clicked', self._setframe_cb)
+ setframe.set_tooltip(_('Set frame'))
+ self.insert(setframe, -1)
+
+ clearframe = ToolButton('gtk-delete')
+ clearframe.connect('clicked', self._clearframe_cb)
+ clearframe.set_tooltip(_('Clear frame'))
+ self.insert(clearframe, -1)
+
+ resetframe = ToolButton('gtk-cancel')
+ resetframe.connect('clicked', self._resetframe_cb)
+ resetframe.set_tooltip(_('Reset'))
+ self.insert(resetframe, -1)
+
+ separator = gtk.SeparatorToolItem()
+ self.insert(separator,-1)
+
+ # play/pause buttons
+
+ play_img_1 = gtk.Image()
+ play_img_1.set_from_icon_name('media-playback-start-back',
+ gtk.ICON_SIZE_LARGE_TOOLBAR)
+ pause_img_1 = gtk.Image()
+ pause_img_1.set_from_icon_name('media-playback-pause',
+ gtk.ICON_SIZE_LARGE_TOOLBAR)
+
+ play_img_2 = gtk.Image()
+ play_img_2.set_from_icon_name('media-playback-start',
+ gtk.ICON_SIZE_LARGE_TOOLBAR)
+ pause_img_2 = gtk.Image()
+ pause_img_2.set_from_icon_name('media-playback-pause',
+ gtk.ICON_SIZE_LARGE_TOOLBAR)
+
+ paly_1 = ToggleToolButton('media-playback-start-back')
+ play_2 = ToggleToolButton('media-playback-start')
+
+ paly_1.connect('toggled', self._play_cb,
+ (paly_1, play_2), (play_img_1, pause_img_1),
+ self.montage.playbackwards)
+ self.insert(paly_1, -1)
+ paly_1.set_tooltip(_('Play backward / Pause'))
+
+ play_2.connect('toggled', self._play_cb,
+ (play_2, paly_1), (play_img_2, pause_img_2),
+ self.montage.playforwards)
+ self.insert(play_2, -1)
+ play_2.set_tooltip(_('Play forward / Pause'))
+
+ # tempo button
+
+ tempo = TempoSlider(0, 99)
+ tempo.adjustment.connect("value-changed", self._tempo_cb)
+ tempo.set_size_request(250, -1)
+ tempo.set_value(5)
+ tempo_item = gtk.ToolItem()
+ tempo_item.add(tempo)
+ self.insert(tempo_item, -1)
+
+ separator = gtk.SeparatorToolItem()
+ self.insert(separator,-1)
+
+ # export buttons
+
+ exportframe = ToolButton('image')
+ exportframe.connect('clicked', self._exportframe_cb)
+ exportframe.set_tooltip(_('Snapshot'))
+ self.insert(exportframe, -1)
+
+ self.show_all()
+
+ def _exportframe_cb(self, widget):
+ self.montage.exportframe()
+
+ def _setframe_cb(self, widget):
+ self.montage.setframe()
+
+ def _clearframe_cb(self, widget):
+ self.montage.clearframe()
+
+ def _resetframe_cb(self, widget):
+ self.montage.reset()
+
+ def _tempo_cb(self, widget):
+ self.montage.setplayspeed(widget.value)
+
+ def _play_cb(self, widget, buttons, images, play):
+ if widget.get_active():
+ buttons[1].set_active(False)
+ images[1].show()
+ widget.set_icon_widget(images[1])
+ play()
+ else:
+ images[0].show()
+ widget.set_icon_widget(images[0])
+ self.montage.stop()
+
+class LessonsToolbar(gtk.Toolbar):
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+ self._mask = False
+
+ for lesson in lessons.THEMES:
+ button = gtk.ToggleToolButton()
+ button.set_label(lesson.name)
+ button.connect('clicked', self._lessons_cb, lesson)
+ self.insert(button, -1)
+
+ self.get_nth_item(0).set_active(True)
+ self.show_all()
+
+ def _lessons_cb(self, widget, lesson):
+ if self._mask:
+ return
+ self._mask = True
+
+ for i, j in enumerate(lessons.THEMES):
+ if j != lesson:
+ self.get_nth_item(i).set_active(False)
+
+ widget.props.active = True
+ lesson.change()
+ self._mask = False
diff --git a/icons/media-playback-start-back.svg b/icons/media-playback-start-back.svg
new file mode 100644
index 0000000..4c97aab
--- /dev/null
+++ b/icons/media-playback-start-back.svg
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<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"
+ enable-background="new 0 0 55 55"
+ height="55px"
+ version="1.1"
+ viewBox="0 0 55 55"
+ width="55px"
+ x="0px"
+ xml:space="preserve"
+ y="0px"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="media-playback-start-back.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
+ id="metadata20"><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><defs
+ id="defs18"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 27.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="55 : 27.5 : 1"
+ inkscape:persp3d-origin="27.5 : 18.333333 : 1"
+ id="perspective22" /></defs><sodipodi:namedview
+ inkscape:window-height="735"
+ inkscape:window-width="1278"
+ 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"
+ showgrid="true"
+ inkscape:zoom="8.4"
+ inkscape:cx="27.5"
+ inkscape:cy="22.320051"
+ inkscape:window-x="0"
+ inkscape:window-y="32"
+ inkscape:current-layer="svg2"><inkscape:grid
+ type="xygrid"
+ id="grid2395" /></sodipodi:namedview><g
+ display="block"
+ id="media-playback-start"
+ transform="matrix(0.4908954,-0.8712186,0.8712186,0.4908954,-9.9581467,37.958872)"
+ style="display:block">
+ <g
+ display="inline"
+ id="g5"
+ style="display:inline">
+ <g
+ id="g7">
+ <g
+ id="g9">
+ <g
+ id="g11">
+ <path
+ d="M 27.496,5.051 C 15.036,5.07 4.952,15.155 4.93,27.618 C 4.952,40.08 15.036,50.164 27.496,50.185 C 39.961,50.164 50.045,40.081 50.064,27.619 C 50.045,15.155 39.961,5.07 27.496,5.051 z M 21.551,37.977 L 21.551,17.667 L 39.512,27.822 L 21.551,37.977 z"
+ id="path13"
+ style="fill:#FFFFFF" />
+ </g>
+ </g>
+ <path
+ d="M 27.498,0 C 12.311,0 0,12.313 0,27.5 C 0,42.688 12.311,55 27.498,55 C 42.686,55 55,42.688 55,27.5 C 55,12.313 42.686,0 27.498,0 z M 27.496,52.646 C 13.67,52.646 2.463,41.437 2.461,27.613 C 2.463,13.787 13.67,2.577 27.496,2.574 C 41.322,2.577 52.531,13.787 52.535,27.612 C 52.531,41.437 41.322,52.646 27.496,52.646 z"
+ id="path15"
+ style="fill:#FFFFFF" />
+ </g>
+ </g>
+</g></svg>
diff --git a/icons/tempo1.svg b/icons/tempo1.svg
new file mode 100644
index 0000000..bb9aeec
--- /dev/null
+++ b/icons/tempo1.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M23.5,6.5c3,3,7,7,9,11c-7,5-4,6-3,26c-1,1-8,1-9,0c0,0,2,1,2-1
+ c0-3-2-7-2-11c0-2,1-4,1-6c0-3-2-1-2-3c0-3,3-8,3-11c0-2-1-1-2-2v-3H23.5z"/>
+</svg>
diff --git a/icons/tempo2.svg b/icons/tempo2.svg
new file mode 100644
index 0000000..4a98310
--- /dev/null
+++ b/icons/tempo2.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M27.5,44.5v-3C28.5,42.5,28.5,43.5,27.5,44.5z M26.5,10.5
+ c2,2,2,6,2,8c0,4-3,11-3,13s4,7,7,10c-2,2-4,3-5,5h-6c1-1,2-3,2-5c0-3-2-9-3-14c0,0,0-1-1,0v-6c0-3,3-8,3-11c0-1-2-2-2-6h3
+ C23.5,5.5,26.5,9.5,26.5,10.5z"/>
+</svg>
diff --git a/icons/tempo3.svg b/icons/tempo3.svg
new file mode 100644
index 0000000..bd893bd
--- /dev/null
+++ b/icons/tempo3.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M30.5,17.5c0,3-2,2-2,4c0,3,4,14,7,21c-1,0-3,1-5,1c1-1,2,0,2-3
+ c0-2-4-7-6-10c-3,3-5,8-7,13c-1,0-3-1-4-1c3-3,7-14,7-18s-1-3-4-4c3-2,4-8,4-14h3C23.5,9.5,30.5,14.5,30.5,17.5z"/>
+</svg>
diff --git a/icons/tempo4.svg b/icons/tempo4.svg
new file mode 100644
index 0000000..6fa5afa
--- /dev/null
+++ b/icons/tempo4.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M34.5,22.5c-1-1-2-4-5-6c-1,2,0,3,0,6c0,2-3,4-3,7c0,2,4,2,4,4
+ c0,3-1,4-2,5c0-1,0-3-1-4c-1,3-2,7-3,10c-4-3,0-6,0-9s-3-11-4-17l-4,4c1-5,8.25-11.12,7.25-16.12c0.68,0.68,3.029,0,2.87,2.12
+ C26.5,10.25,33.62,17.75,34.5,22.5z"/>
+</svg>
diff --git a/icons/tempo5.svg b/icons/tempo5.svg
new file mode 100644
index 0000000..9500e7e
--- /dev/null
+++ b/icons/tempo5.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M24.5,13.5c2,1,5,3,5,6c0,2-2,3-2,5c0,9,11,4,11,13c-1,0-3-2-4-3
+ c-3-1-9,1-10-3c-2,3-5,7-7,11c-3,0-3-1-4-1c0-2,3-3,4-6s4-8,4-10c0-3-1-3-2-5c-1,0-2,1-3,2c0-1,2-3,2-4c1-2,3-5,2-8c0,0,1-1,4-2
+ C25.5,9.5,25.5,11.5,24.5,13.5z"/>
+</svg>
diff --git a/icons/tempo6.svg b/icons/tempo6.svg
new file mode 100644
index 0000000..9844fd6
--- /dev/null
+++ b/icons/tempo6.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 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M22.5,10.5c3,2,7,5,7,7c0,3-4,8-4,10c0,3,1,3,1,5h5l2-2l2,2v4
+ c-1,0-3-2-5-2c-3,0-5,1-8,1c-1,3-2,7-2,10h-5c1-1,3-3,3-4c1-5,1-11,1-18l-1-1c-1,1-1.75,2.88-2.75,2.88c0,0-0.25-0.63-0.25-1.63
+ c4-4,2-8.25,2-13.25c0-1,0.25-2.5,0.38-5.38L22.5,5.5C23.12,6.5,22.5,8.5,22.5,10.5z"/>
+<polygon fill-rule="evenodd" clip-rule="evenodd" fill="#333333" stroke="#333333" stroke-linecap="round" stroke-linejoin="round" points="
+ 25,20 25.25,16.75 26.5,17.88 "/>
+</svg>
diff --git a/icons/tempo7.svg b/icons/tempo7.svg
new file mode 100644
index 0000000..54bed80
--- /dev/null
+++ b/icons/tempo7.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M20.5,7.5c1,1,1,3,1,4c10,4,8,6,8,14c0,2,6,9,10,13c-1,2-2,4-4,5
+ c1.62-8.88-8.75-13.88-12-15c-1,1-1,0-1,2c0,3,2,5,3,7c-1,1-3,2-6,2c0-1,2-1,2-4c0-2-4-4-4-6c0-3,3-4,5-6c-3-8-8-2-11-6h6
+ c0-1,1,0,1-3c0-2-1-1-2-2l1-5H20.5z"/>
+</svg>
diff --git a/icons/tempo8.svg b/icons/tempo8.svg
new file mode 100644
index 0000000..2c0154f
--- /dev/null
+++ b/icons/tempo8.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M20.5,12.5c0.67,0.4,0.4,1.9,1.75,2.25s1.05-0.38,1.5-0.37
+ c4.971,0,10.95-0.88,11.75,7.12c-1-2-3-4-5-5l-4,1c1,2,4,4,5,7c1,1,1,4,1,6c3,3,8-1,11,6c-2.88-0.82-4.25-2.62-12.75-2.75
+ c-1.561-0.02-2.34-1.561-3.75-1.87c-3.42-0.76-4.67-0.38-5.5-0.38c-3,0-8,7-11,7c-2,0-3-1-3-2c4,2,8-4,9-7c2-1,5-1,8-3c-2-4-6-5-8-3
+ l-6-6l2-2c1,1,1,2,1,4c1,0,4.12,0.38,6.12-0.62L16.5,17.5v-5H20.5z"/>
+</svg>
diff --git a/lessons.py b/lessons.py
new file mode 100644
index 0000000..82ee0f4
--- /dev/null
+++ b/lessons.py
@@ -0,0 +1,81 @@
+# 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 gtk
+import locale
+import logging
+from glob import glob
+
+from sugar.activity.activity import get_bundle_path
+
+import theme
+
+logger = logging.getLogger('flipsticks')
+
+THEMES = []
+
+class Lesson:
+ def __init__(self, index, filename):
+ self.index = index
+ self.name = os.path.splitext(os.path.basename(filename).lstrip(
+ '.-_1234567890').replace('_', ' '))[0]
+ self.text = file(filename, 'r').read()
+
+ def change(self):
+ View.notebook.set_current_page(self.index)
+
+class View(gtk.EventBox):
+ notebook = None
+
+ def __init__(self):
+ gtk.EventBox.__init__(self)
+
+ View.notebook = gtk.Notebook()
+ View.notebook.props.show_border = False
+ View.notebook.props.show_tabs = False
+ self.add(View.notebook)
+
+ for i in THEMES:
+ view = gtk.TextView()
+ view.get_buffer().set_text(i.text)
+ view.set_wrap_mode(gtk.WRAP_WORD)
+ view.set_editable(False)
+
+ view_box = gtk.EventBox()
+ view_box.add(view)
+ view_box.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(theme.WHITE))
+ view_box.props.border_width = 10
+
+ border_box = gtk.EventBox()
+ border_box.add(view_box)
+ border_box.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(theme.WHITE))
+
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(border_box)
+
+ View.notebook.append_page(scrolled_window)
+
+ self.show_all()
+
+_lessons_dir = os.path.join(get_bundle_path(), 'lessons')
+_lang = locale.getdefaultlocale()[0].split('_')[0]
+
+if not os.path.isdir(os.path.join(_lessons_dir, _lang)):
+ logger.info('Cannot find lessons for language %s, thus use en' % _lang)
+ _lang = 'en'
+
+for i, filename in enumerate(sorted(glob(os.path.join(_lessons_dir, _lang, '*')))):
+ THEMES.append(Lesson(i, filename))
diff --git a/flipsticks.py b/montage.py
index 5df2ca9..b1c4515 100644
--- a/flipsticks.py
+++ b/montage.py
@@ -21,50 +21,77 @@ import os
import gtk
import math
import gobject
+import logging
from gettext import gettext as _
+from sugar.activity.activity import get_bundle_path
+
import model
import screen
import kinematic
+import theme
from theme import *
-def prepare_btn(btn, w=-1, h=-1):
- for state, color in COLOR_BG_BUTTONS:
- btn.modify_bg(state, gtk.gdk.color_parse(color))
- c = btn.get_child()
- if c is not None:
- for state, color in COLOR_FG_BUTTONS:
- c.modify_fg(state, gtk.gdk.color_parse(color))
- else:
- for state, color in COLOR_FG_BUTTONS:
- btn.modify_fg(state, gtk.gdk.color_parse(color))
- if w>0 or h>0:
- btn.set_size_request(w, h)
- return btn
-
-class flipsticks(gtk.EventBox):
-
- def reset(self, widget, data=None):
+logger = logging.getLogger('flipsticks')
+
+class View(gtk.EventBox):
+ def reset(self):
self.key.reset()
self.selectstickebox()
self.drawmainframe()
- def setframe(self, widget, data=None):
+ def setframe(self):
model.keys[self.kfselected].assign(self.key)
self.drawkeyframe()
- def clearframe(self, widget, data=None):
+ def clearframe(self):
model.keys[self.kfselected].clear()
self.drawkeyframe()
- def setplayspeed(self,adj):
- #self.waittime = int((6-adj.value)*150)
- self.waittime = int((6-adj.value)*75)
+ def setplayspeed(self, value):
+ self.waittime = int((100-value)*5)
if self.playing:
gobject.source_remove(self.playing)
self.playing = gobject.timeout_add(self.waittime, self.playframe)
- def exportanim(self, widget, data=None):
+ def playbackwards(self):
+ self.frames = kinematic.makeframes()
+ fsecs = self.frames.keys()
+ fsecs.sort()
+ if fsecs:
+ self.playframenum = fsecs[-1]
+ else:
+ self.playframenum = -1
+ self.playingbackwards = True
+
+ logger.debug('playbackwards speed=%s' % self.waittime)
+ self.playing = gobject.timeout_add(self.waittime, self.playframe)
+
+ def playforwards(self):
+ self.frames = kinematic.makeframes()
+ fsecs = self.frames.keys()
+ fsecs.sort()
+ if fsecs:
+ self.playframenum = fsecs[0]
+ else:
+ self.playframenum = -1
+
+ logger.debug('playforwards speed=%s' % self.waittime)
+ self.playingbackwards = False
+ self.playing = gobject.timeout_add(self.waittime, self.playframe)
+
+ def stop(self):
+ if not self.playing:
+ return
+
+ self.playing = False
+ # set the main window to the keyframe
+ if not model.keys[self.kfselected].empty():
+ self.key.assign(model.keys[self.kfselected])
+ self.drawmainframe()
+ self.updateentrybox()
+
+ def exportframe(self):
self.frames = kinematic.makeframes()
fsecs = self.frames.keys()
firstpixindex = fsecs[0]
@@ -118,7 +145,7 @@ class flipsticks(gtk.EventBox):
state = event.state
if state & gtk.gdk.BUTTON1_MASK and self.pixmap != None:
if self.jointpressed:
- if _inarea(x,y,DRAWWIDTH,DRAWHEIGHT):
+ if _inarea(widget, x, y):
#self.key.joints[self.jointpressed] = (x,y) # old hack way
# first find the parents x,y
(px,py) = model.getparentjoint(self.jointpressed,self.key.joints,
@@ -149,14 +176,14 @@ class flipsticks(gtk.EventBox):
self.drawmainframe()
self.updateentrybox()
elif self.middlepressed:
- if _inarea(x,y,DRAWWIDTH,DRAWHEIGHT):
+ if _inarea(widget, x, y):
xdiff = x-self.key.middle[0]
ydiff = y-self.key.middle[1]
self.key.move(xdiff, ydiff)
self.key.middle = (x,y)
self.drawmainframe()
elif self.rotatepressed:
- if _inarea(x,y,DRAWWIDTH,DRAWHEIGHT):
+ if _inarea(widget, x, y):
(px,py) = self.key.middle
if x-px == 0:
#computeangle = 0
@@ -198,7 +225,7 @@ class flipsticks(gtk.EventBox):
state = event.state
if state & gtk.gdk.BUTTON1_MASK and self.pixmap != None:
if self.kfpressed >= 0:
- if _inarea(x, y, KEYFRAMEWIDTH, KEYFRAMEHEIGHT):
+ if _inarea(widget, x, y):
xdiff = int(x - self.kf_mouse_pos)
frame = model.keys[self.kfpressed]
if frame.x + xdiff > KEYFRAME_RADIUS \
@@ -332,6 +359,9 @@ class flipsticks(gtk.EventBox):
self.drawmainframe()
def drawmainframe(self):
+ if not self.pixmap:
+ return
+
area = self.toplevel.window
drawgc = area.new_gc()
drawgc.line_width = 3
@@ -519,68 +549,16 @@ class flipsticks(gtk.EventBox):
self.sizeentry.set_text(str(size))
self.size_adj.set_value(size)
- def playbackwards(self, widget, data=None):
- if self.playing:
- playimg = gtk.Image()
- playimg.set_from_file(os.path.join(self.iconsdir,'big_left_arrow.png'))
- playimg.show()
- widget.set_image(playimg)
- self.playing = False
- # set the main window to the keyframe
- if model.keys[self.kfselected]:
- self.key.assign(model.keys[self.kfselected])
- self.drawmainframe()
- self.updateentrybox()
- else:
- stopimg = gtk.Image()
- stopimg.set_from_file(os.path.join(self.iconsdir,'big_pause.png'))
- stopimg.show()
- widget.set_image(stopimg)
- self.frames = kinematic.makeframes()
- fsecs = self.frames.keys()
- fsecs.sort()
- if fsecs:
- self.playframenum = fsecs[-1]
- else:
- self.playframenum = -1
- self.playingbackwards = True
- self.playing = gobject.timeout_add(self.waittime, self.playframe)
-
- def playforwards(self, widget, data=None):
- if self.playing:
- playimg = gtk.Image()
- playimg.set_from_file(os.path.join(self.iconsdir,'big_right_arrow.png'))
- playimg.show()
- widget.set_image(playimg)
- self.playing = False
- # set the main window to the keyframe
- if model.keys[self.kfselected]:
- self.key.assign(model.keys[self.kfselected])
- self.drawmainframe()
- self.updateentrybox()
- else:
- stopimg = gtk.Image()
- stopimg.set_from_file(os.path.join(self.iconsdir,'big_pause.png'))
- stopimg.show()
- widget.set_image(stopimg)
- self.frames = kinematic.makeframes()
- fsecs = self.frames.keys()
- fsecs.sort()
- if fsecs:
- self.playframenum = fsecs[0]
- else:
- self.playframenum = -1
- self.playingbackwards = False
- self.playing = gobject.timeout_add(self.waittime, self.playframe)
-
- def __init__(self, toplevel_window, mdirpath):
+ def __init__(self, activity):
gtk.EventBox.__init__(self)
self.playing = False
self.playingbackwards = False
- self.waittime = 3*150
- self.toplevel = toplevel_window
+ self.toplevel = activity
self.stickselected = 'RIGHT SHOULDER'
+ self.pixmap = None
+
+ self.setplayspeed(50)
self.keys_overlap_stack = []
for i in range(len(model.keys)):
@@ -593,13 +571,12 @@ class flipsticks(gtk.EventBox):
self.kfpressed = -1
self.middlepressed = False
self.rotatepressed = False
- self.iconsdir = os.path.join(mdirpath, 'icons')
+ self.iconsdir = os.path.join(get_bundle_path(), 'icons')
self.language = 'English'
# screen
self.mfdraw = gtk.DrawingArea()
- self.mfdraw.set_size_request(DRAWWIDTH,DRAWHEIGHT)
self.mfdraw.connect('expose_event', self.expose_event)
self.mfdraw.connect('configure_event', self.configure_event)
self.mfdraw.connect('motion_notify_event', self.motion_notify_event)
@@ -614,12 +591,12 @@ class flipsticks(gtk.EventBox):
screen_box = gtk.EventBox()
screen_box.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND))
- screen_box.set_border_width(5)
+ screen_box.set_border_width(PAD/2)
screen_box.add(self.mfdraw)
screen_pink = gtk.EventBox()
screen_pink.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(PINK))
- screen_pink.set_border_width(10)
+ screen_pink.set_border_width(PAD)
screen_pink.add(screen_box)
# keyframes
@@ -638,6 +615,10 @@ class flipsticks(gtk.EventBox):
| gtk.gdk.POINTER_MOTION_MASK
| gtk.gdk.POINTER_MOTION_HINT_MASK)
+ kfdraw_box = gtk.EventBox()
+ kfdraw_box.set_border_width(PAD)
+ kfdraw_box.add(self.kfdraw)
+
# control box
angle_box = gtk.HBox()
@@ -716,12 +697,12 @@ class flipsticks(gtk.EventBox):
control_bg = gtk.EventBox()
control_bg.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BUTTON_BACKGROUND))
- control_bg.set_border_width(5)
+ control_bg.set_border_width(PAD/2)
control_bg.add(control_box)
control_pink = gtk.EventBox()
control_pink.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(PINK))
- control_pink.set_border_width(5)
+ control_pink.set_border_width(PAD)
control_pink.add(control_bg)
# left control box
@@ -741,11 +722,11 @@ class flipsticks(gtk.EventBox):
desktop = gtk.VBox()
desktop.pack_start(hdesktop)
- desktop.pack_start(self.kfdraw, False, False, 0)
+ desktop.pack_start(kfdraw_box, False, False, 0)
greenbox = gtk.EventBox()
greenbox.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND))
- greenbox.set_border_width(5)
+ greenbox.set_border_width(PAD/2)
greenbox.add(desktop)
self.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(YELLOW))
@@ -798,13 +779,8 @@ class flipsticks(gtk.EventBox):
self.sizeentry.set_text(str(int(adj.value)))
self.enterlen_callback(None, self.sizeentry)
-def _inarea(x, y, awidth, aheight):
- if x+5 > awidth:
- return False
- if y+5 > aheight:
- return False
- if y < 5:
- return False
- if x < 5:
+def _inarea(widget, x, y):
+ x_, y_, width, height = widget.get_allocation()
+ if x < 0 or y < 0 or x >= width or y >= height:
return False
return True
diff --git a/screen.py b/screen.py
index a818a5e..31ba47f 100644
--- a/screen.py
+++ b/screen.py
@@ -28,7 +28,7 @@ class ScreenFrame:
self.parts = theme.PARTS.copy()
self.sticks = theme.STICKS.copy()
self.joints = _initjoints()
- self.middle = (int(theme.DRAWWIDTH/2.0), int(theme.DRAWHEIGHT/2.0))
+ self.middle = (theme.DRAWWIDTH/2, theme.DRAWHEIGHT/3)
self.setjoints()
def assign(self, x):
diff --git a/shared.py b/shared.py
new file mode 100644
index 0000000..3ca51ca
--- /dev/null
+++ b/shared.py
@@ -0,0 +1,131 @@
+# 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 logging
+import telepathy
+from gobject import property, SIGNAL_RUN_FIRST, TYPE_PYOBJECT
+
+from sugar.activity.activity import Activity
+from sugar.presence.sugartubeconn import SugarTubeConnection
+
+logger = logging.getLogger('cartoon-builder')
+
+class CanvasActivity(Activity):
+ __gsignals__ = {
+ 'init' : (SIGNAL_RUN_FIRST, None, []) }
+
+ def __init__(self, canvas, *args):
+ Activity.__init__(self, *args)
+
+ self._inited = False
+
+ # XXX do it after(possible) read_file() invoking
+ # have to rely on calling read_file() from map_cb in sugar-toolkit
+ canvas.connect_after('map', self._map_canvasactivity_cb)
+ self.set_canvas(canvas)
+
+ def get_inited(self):
+ return self._inited
+
+ inited = property(type=bool, default=False, getter=get_inited, setter=None)
+
+ def _map_canvasactivity_cb(self, widget):
+ self._inited = True
+ self.emit('init')
+ return False
+
+class SharedActivity(CanvasActivity):
+ __gsignals__ = {
+ 'tube' : (SIGNAL_RUN_FIRST, None, 2*[TYPE_PYOBJECT]) }
+
+ def __init__(self, canvas, service, *args):
+ CanvasActivity.__init__(self, canvas, *args)
+
+ self.service = service
+ self._postpone_tubes = []
+
+ self.connect_after('init', self._init_sharedactivity_cb)
+ self.connect('shared', self._shared_cb)
+
+ # Owner.props.key
+ if self._shared_activity:
+ # We are joining the activity
+ self.connect('joined', self._joined_cb)
+ if self.get_shared():
+ # We've already joined
+ self._joined_cb()
+
+ def _init_sharedactivity_cb(self, sender):
+ for i in self._postpone_tubes:
+ self.emit('tube', i, self._initiating)
+ self._postpone_tubes = []
+
+ def _shared_cb(self, activity):
+ logger.debug('My activity was shared')
+ self._initiating = True
+ self._sharing_setup()
+
+ logger.debug('This is my activity: making a tube...')
+ id = self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
+ self.service, {})
+
+ def _joined_cb(self, activity):
+ if not self._shared_activity:
+ return
+
+ logger.debug('Joined an existing shared activity')
+
+ self._initiating = False
+ self._sharing_setup()
+
+ logger.debug('This is not my activity: waiting for a tube...')
+ self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
+ reply_handler=self._list_tubes_reply_cb,
+ error_handler=self._list_tubes_error_cb)
+
+ def _sharing_setup(self):
+ if self._shared_activity is None:
+ logger.error('Failed to share or join activity')
+ return
+ self._conn = self._shared_activity.telepathy_conn
+ self._tubes_chan = self._shared_activity.telepathy_tubes_chan
+ self._text_chan = self._shared_activity.telepathy_text_chan
+
+ self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube', self._new_tube_cb)
+
+ def _list_tubes_reply_cb(self, tubes):
+ for tube_info in tubes:
+ self._new_tube_cb(*tube_info)
+
+ def _list_tubes_error_cb(self, e):
+ logger.error('ListTubes() failed: %s', e)
+
+ def _new_tube_cb(self, id, initiator, type, service, params, state):
+ logger.debug('New tube: ID=%d initator=%d type=%d service=%s '
+ 'params=%r state=%d', id, initiator, type, service,
+ params, state)
+
+ if (type == telepathy.TUBE_TYPE_DBUS and
+ service == self.service):
+ if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
+
+ tube_conn = SugarTubeConnection(self._conn,
+ self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
+ id, group_iface=self._text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+
+ if self.get_inited():
+ self.emit('tube', tube_conn, self._initiating)
+ else:
+ self._postpone_tubes.append(tube_conn)
diff --git a/theme.py b/theme.py
index 4198f22..5bf4b07 100644
--- a/theme.py
+++ b/theme.py
@@ -94,21 +94,23 @@ LANG = {'English':{'size':'Size',
'LOWER LEFT LEG':u'Una pierna izquierda m\xe1s baja',
'LEFT FOOT':'Pie izquierdo'}}
-FPWIDTH = 150
-FPHEIGHT = 100
-#DRAWHEIGHT = 300 for my laptop
-KEYFRAMEWIDTH = gtk.gdk.screen_width() - 406 # 675
+PAD = 10
+LOGO_WIDTH = 276
+
+KEYFRAMEWIDTH = gtk.gdk.screen_width() - PAD*3
KEYFRAMEHEIGHT = 80
-DRAWWIDTH = KEYFRAMEWIDTH + 64 # 750
-DRAWHEIGHT = gtk.gdk.screen_height() - 370 # 500
-KEYFRAMES = [] # [50,190,337,487,625]
+DRAWWIDTH = gtk.gdk.screen_width() - LOGO_WIDTH - PAD*4
+DRAWHEIGHT = gtk.gdk.screen_height() - KEYFRAMEHEIGHT - PAD*5
+
+KEYFRAMES = []
+KEYFRAMES_NUMBER = 5
TOTALFRAMES = 30
KEYFRAME_RADIUS = 40
-for i in range(5):
- keyframe_width = KEYFRAMEWIDTH/5
+for i in range(KEYFRAMES_NUMBER):
+ keyframe_width = KEYFRAMEWIDTH/KEYFRAMES_NUMBER
KEYFRAMES.append(keyframe_width/2 + i*keyframe_width)
STICKS = {'HEAD':(0,15),
diff --git a/utils.py b/utils.py
new file mode 100644
index 0000000..63e9d64
--- /dev/null
+++ b/utils.py
@@ -0,0 +1,89 @@
+# 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 gtk
+
+import sugar
+from sugar.graphics import style
+from sugar.activity.activity import get_bundle_path
+
+from theme import *
+
+def map_range(value, ilower, iupper, olower, oupper):
+ if value == iupper:
+ return oupper
+ return olower + int((oupper-olower+1) * (value-ilower) /
+ float(iupper-ilower))
+
+class TempoSlider(gtk.HBox):
+ def __init__(self, min_value, max_value):
+ gtk.HBox.__init__(self)
+
+ self._pixbuf = [None] * 8
+ self._image = gtk.Image()
+ self._image.show()
+
+ # used to store tempo updates while the slider is active
+ self._delayed = 0
+ self._active = False
+
+ self.adjustment = gtk.Adjustment(min_value, min_value, max_value,
+ (max_value - min_value) / 8, (max_value - min_value) / 8, 0)
+ self._adjustment_h = self.adjustment.connect('value-changed',
+ self._changed_cb)
+
+ slider = gtk.HScale(adjustment = self.adjustment)
+ slider.show()
+ slider.set_draw_value(False)
+ slider.connect("button-press-event", self._press_cb)
+ slider.connect("button-release-event", self._release_cb)
+
+ self.pack_start(slider, True, True)
+ self.pack_end(self._image, False, False)
+
+ def set_value(self, tempo, quiet = False):
+ if self._active:
+ self._delayed = tempo
+ elif quiet:
+ self.adjustment.handler_block(self._adjustment_h)
+ self.adjustment.set_value(tempo)
+ self._update(tempo)
+ self.adjustment.handler_unblock(self._adjustment_h)
+ else:
+ self.adjustment.set_value(tempo)
+
+ def _changed_cb(self, widget):
+ self._update(widget.get_value())
+
+ def _update(self, tempo):
+ img = map_range(tempo, self.adjustment.lower,
+ self.adjustment.upper, 0, 7)
+
+ if not self._pixbuf[img]:
+ self._pixbuf[img] = gtk.gdk.pixbuf_new_from_file_at_size(
+ os.path.join(get_bundle_path(), 'icons/tempo' +
+ str(img+1) + '.svg'),
+ style.STANDARD_ICON_SIZE, style.STANDARD_ICON_SIZE)
+
+ self._image.set_from_pixbuf(self._pixbuf[img])
+
+ def _press_cb(self, widget, event):
+ self._active = True
+
+ def _release_cb(self, widget, event):
+ self._active = False
+ if self._delayed != 0:
+ self.set_value(self._delayed, True)
+ self._delayed = 0