From 4ea603bdfbe16d48ff01615b15d62cd53c7641d5 Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Wed, 11 Feb 2009 14:19:46 +0000 Subject: Refactoring gui, checkpoint #2 --- 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 @@ + +image/svg+xml + + + + + + + + + + + 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 @@ + + + + + + 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 @@ + + + + + + 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 @@ + + + + + + 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 @@ + + + + + + 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 @@ + + + + + + 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 @@ + + + + + + + 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 @@ + + + + + + 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 @@ + + + + + + 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 -- cgit v0.9.1