diff options
Diffstat (limited to 'createcardpanel.py')
-rw-r--r-- | createcardpanel.py | 436 |
1 files changed, 252 insertions, 184 deletions
diff --git a/createcardpanel.py b/createcardpanel.py index 5fc1366..5671cd8 100644 --- a/createcardpanel.py +++ b/createcardpanel.py @@ -20,6 +20,7 @@ import gtk from os import environ from os.path import join, dirname, basename +import hippo import shutil import tempfile @@ -31,49 +32,70 @@ from xml.dom.minidom import parse from sugar.graphics.objectchooser import ObjectChooser from sugar import mime from sugar.graphics import style +from sugar.graphics.toolbutton import ToolButton +from sugar.graphics.icon import Icon +from sugar.graphics.palette import Palette +from port.widgets import ToggleToolButton +from port.widgets import CanvasRoundBox, ToolComboBox +from port import chooser import theme +import speak.espeak +import speak.widgets +import speak.face _logger = logging.getLogger('memorize-activity') class CreateCardPanel(gtk.EventBox): - __gsignals__ = { - 'add-pair': (SIGNAL_RUN_FIRST, None, 6 * [TYPE_PYOBJECT]), - 'update-pair': (SIGNAL_RUN_FIRST, None, 6 * [TYPE_PYOBJECT]), + 'add-pair': (SIGNAL_RUN_FIRST, None, 8 * [TYPE_PYOBJECT]), + 'update-pair': (SIGNAL_RUN_FIRST, None, 8 * [TYPE_PYOBJECT]), } - + def __init__(self): + def make_label(icon_name, label): + label_box = gtk.HBox() + icon = Icon( + icon_name=icon_name, + icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR) + label_box.pack_start(icon, False) + label = gtk.Label(label) + label.modify_fg(gtk.STATE_NORMAL, + style.COLOR_TOOLBAR_GREY.get_gdk_color()) + label_box.pack_start(label) + label_box.show_all() + return label_box + gtk.EventBox.__init__(self) - + self.equal_pairs = False self._updatebutton_sensitive = False self._card1_has_sound = False self._card2_has_sound = False - - # Set the add new pair buttom - add_icon = join(dirname(__file__), 'images', 'pair-add.svg') - add_image = gtk.Image() - add_image.set_from_file(add_icon) - self._addbutton = gtk.Button(' ' + _('Add as new pair')) - self._addbutton.set_image(add_image) - self._addbutton.connect('pressed', self.emit_add_pair) - self._addbutton.set_size_request( - theme.PAIR_SIZE + theme.PAD*4, -1) - self._addbutton.set_sensitive(False) - # Set update selected pair buttom - update_icon = join(dirname(__file__), 'images', 'pair-update.svg') - update_image = gtk.Image() - update_image.set_from_file(update_icon) - self._updatebutton = gtk.Button(' ' + _('Update selected pair')) - self._updatebutton.set_image(update_image) - self._updatebutton.connect('pressed', self.emit_update_pair) - self._updatebutton.set_size_request( - theme.PAIR_SIZE + theme.PAD*4, -1) - self._updatebutton.set_sensitive(False) + # save buttons + + buttons_bar = gtk.HBox() + buttons_bar.props.border_width = 10 + + self._addbutton = ToolButton( + tooltip=_('Add as new pair'), + sensitive=False) + self._addbutton.set_icon_widget( + make_label('pair-add', ' ' + _('Add'))) + self._addbutton.connect('clicked', self.emit_add_pair) + buttons_bar.pack_start(self._addbutton, False) + + self._updatebutton = ToolButton( + tooltip=_('Update selected pair'), + sensitive=False) + self._updatebutton.set_icon_widget( + make_label('pair-update', ' ' + _('Update'))) + self._updatebutton.connect('clicked', self.emit_update_pair) + buttons_bar.pack_start(self._updatebutton, False) # Set card editors + self.cardeditor1 = CardEditor() self.cardeditor2 = CardEditor() self.clean(None) @@ -83,20 +105,20 @@ class CreateCardPanel(gtk.EventBox): self.cardeditor2.connect('has-picture', self.receive_picture_signals) self.cardeditor1.connect('has-sound', self.receive_sound_signals) self.cardeditor2.connect('has-sound', self.receive_sound_signals) - - # Create table and add components to the table - self.table = gtk.Table() - self.table.set_homogeneous(False) - self.table.set_col_spacings(theme.PAD) - self.table.set_row_spacings(theme.PAD) - self.table.set_border_width(theme.PAD) - self.table.attach(self.cardeditor1, 0, 1, 0, 1, yoptions=gtk.SHRINK) - self.table.attach(self.cardeditor2, 1, 2, 0, 1, yoptions=gtk.SHRINK) - self.table.attach(self._addbutton, 0, 1, 1, 2, yoptions=gtk.SHRINK) - self.table.attach(self._updatebutton, 1, 2, 1, 2, yoptions=gtk.SHRINK) - self.add(self.table) + + # edit panel + + self.card_box = gtk.HBox() + self.card_box.pack_start(self.cardeditor1) + self.card_box.pack_start(self.cardeditor2) + + box = gtk.VBox() + box.pack_start(self.card_box, False) + box.pack_start(buttons_bar, False) + self.add(box) + self.show_all() - + def emit_add_pair(self, widget): self._addbutton.set_sensitive(False) if self.equal_pairs: @@ -104,15 +126,18 @@ class CreateCardPanel(gtk.EventBox): self.cardeditor1.get_text(), self.cardeditor1.get_pixbuf(), self.cardeditor1.get_pixbuf(), - self.cardeditor1.get_snd(), self.cardeditor1.get_snd()) + self.cardeditor1.get_snd(), self.cardeditor1.get_snd(), + self.cardeditor1.get_speak(), self.cardeditor1.get_speak() + ) else: self.emit('add-pair', self.cardeditor1.get_text(), self.cardeditor2.get_text(), self.cardeditor1.get_pixbuf(), self.cardeditor2.get_pixbuf(), - self.cardeditor1.get_snd(), self.cardeditor2.get_snd()) + self.cardeditor1.get_snd(), self.cardeditor2.get_snd(), + self.cardeditor1.get_speak(), self.cardeditor2.get_speak() + ) self.clean(None) - def emit_update_pair(self, widget): self._addbutton.set_sensitive(False) @@ -121,17 +146,21 @@ class CreateCardPanel(gtk.EventBox): self.cardeditor1.get_text(), self.cardeditor1.get_pixbuf(), self.cardeditor1.get_pixbuf(), - self.cardeditor1.get_snd(), self.cardeditor1.get_snd()) + self.cardeditor1.get_snd(), self.cardeditor1.get_snd(), + self.cardeditor1.get_speak(), self.cardeditor1.get_speak() + ) else: self.emit('update-pair', self.cardeditor1.get_text(), self.cardeditor2.get_text(), self.cardeditor1.get_pixbuf(), self.cardeditor2.get_pixbuf(), - self.cardeditor1.get_snd(), self.cardeditor2.get_snd()) + self.cardeditor1.get_snd(), self.cardeditor2.get_snd(), + self.cardeditor1.get_speak(), self.cardeditor2.get_speak() + ) self.clean(None) - + def pair_selected(self, widget, selected, newtext1, newtext2, aimg, bimg, - asnd, bsnd): + asnd, bsnd, aspeak, bspeak): if selected: self.cardeditor1.set_text(newtext1) self.cardeditor2.set_text(newtext2) @@ -139,6 +168,8 @@ class CreateCardPanel(gtk.EventBox): self.cardeditor2.set_pixbuf(bimg) self.cardeditor1.set_snd(asnd) self.cardeditor2.set_snd(bsnd) + self.cardeditor1.set_speak(aspeak) + self.cardeditor2.set_speak(bspeak) self._addbutton.set_sensitive(True) self._updatebutton.set_sensitive(selected) self._updatebutton_sensitive = selected @@ -146,16 +177,14 @@ class CreateCardPanel(gtk.EventBox): def change_equal_pairs(self, widget, state): self.equal_pairs = state self.clean(None) + if self.equal_pairs: - self.table.remove(self.cardeditor1) - self.table.remove(self.cardeditor2) - self.table.attach(self.cardeditor1, 0, 2, 0, 1, - gtk.SHRINK, gtk.SHRINK) + if self.cardeditor2.parent: + self.card_box.remove(self.cardeditor2) else: - self.table.remove(self.cardeditor1) - self.table.attach(self.cardeditor1, 0, 1, 0, 1, yoptions=gtk.SHRINK) - self.table.attach(self.cardeditor2, 1, 2, 0, 1, yoptions=gtk.SHRINK) - + if not self.cardeditor2.parent: + self.card_box.pack_start(self.cardeditor2) + def clean(self, widget): self.cardeditor1.clean() self.cardeditor2.clean() @@ -164,28 +193,28 @@ class CreateCardPanel(gtk.EventBox): self._card2_has_text = False self._card1_has_picture = False self._card2_has_picture = False - + def receive_text_signals(self, widget, has_text): if widget == self.cardeditor1: self._card1_has_text = has_text if widget == self.cardeditor2: self._card2_has_text = has_text self._update_buttom_status() - + def receive_picture_signals(self, widget, has_picture): if widget == self.cardeditor1: self._card1_has_picture = has_picture if widget == self.cardeditor2: self._card2_has_picture = has_picture self._update_buttom_status() - + def receive_sound_signals(self, widget, has_sound): if widget == self.cardeditor1: self._card1_has_sound = has_sound if widget == self.cardeditor2: self._card2_has_sound = has_sound self._update_buttom_status() - + def _update_buttom_status(self): if not self.equal_pairs: if (self._card1_has_text or self._card1_has_picture or self._card1_has_sound) and (self._card2_has_text or self._card2_has_picture or self._card2_has_sound): @@ -201,48 +230,31 @@ class CreateCardPanel(gtk.EventBox): else: self._addbutton.set_sensitive(False) self._updatebutton.set_sensitive(False) - + class CardEditor(gtk.EventBox): - + __gsignals__ = { - 'has-text': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), - 'has-picture': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), - 'has-sound': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), + 'has-text': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), + 'has-picture': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), + 'has-sound': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), } - + def __init__(self): gtk.EventBox.__init__(self) + self.snd = None + tmp_root = join(environ['SUGAR_ACTIVITY_ROOT'], 'instance') self.temp_folder = tempfile.mkdtemp(dir=tmp_root) - - table = gtk.Table() + + box = gtk.VBox() + box.props.spacing = theme.PAD + box.props.border_width = theme.PAD + self.previewlabel = gtk.Label(_('Preview:')) self.previewlabel.set_alignment(0, 1) - self.textlabel = gtk.Label(_('Text:')) - self.textlabel.set_alignment(0, 1) - - picture_icon = join(dirname(__file__), 'images', 'import_picture.svg') - picture_image = gtk.Image() - picture_image.set_from_file(picture_icon) - self.browsepicture = gtk.Button() - self.browsepicture.set_image(picture_image) - self.browsepicture.connect('button-press-event', self._import_image) - - sound_icon = join(dirname(__file__), 'images', 'import_sound.svg') - sound_image = gtk.Image() - sound_image.set_from_file(sound_icon) - self.browsesound = gtk.Button() - self.browsesound.set_image(sound_image) - self.browsesound.connect('button-press-event', self._import_audio) - self.snd = None - self.textentry = gtk.Entry() - self.textentry.connect('changed', self.update_text) - - table.set_homogeneous(False) - table.set_col_spacings(theme.PAD) - table.set_row_spacings(theme.PAD) - table.set_border_width(theme.PAD) + box.pack_start(self.previewlabel, False) + self.card = svgcard.SvgCard(-1, { 'front_text' : { 'card_text' : '', 'text_color' : '#ffffff' }, @@ -251,28 +263,62 @@ class CardEditor(gtk.EventBox): 'opacity' : '1' } }, None, theme.PAIR_SIZE, 1, '#c0c0c0') self.card.flip() - - table.attach(self.previewlabel, 0, 2, 0, 1, yoptions=gtk.SHRINK) - table.attach(self.card, 0, 2, 1, 2, gtk.SHRINK, gtk.SHRINK, - theme.PAD) - #Text label and entry - table.attach(self.textlabel, 0, 1, 2, 3, yoptions=gtk.SHRINK) - table.attach(self.textentry, 0, 2, 3, 4, yoptions=gtk.SHRINK) - self.textentry.set_size_request(0, -1) - #Picture label and entry - table.attach(self.browsepicture, 0, 1, 4, 5, yoptions=gtk.SHRINK) - #Sound label and entry - table.attach(self.browsesound, 1, 2, 4, 5, yoptions=gtk.SHRINK) - - self.add(table) - + card_align = gtk.Alignment(.5, .5, 0, 0) + card_align.add(self.card) + box.pack_start(card_align, False) + + textlabel = gtk.Label(_('Text:')) + textlabel.set_alignment(0, 1) + box.pack_start(textlabel, False) + + self.textentry = gtk.Entry() + self.textentry.connect('changed', self.update_text) + box.pack_start(self.textentry, False) + + toolbar = gtk.HBox() + + browsepicture = ToolButton( + icon_name='import_picture', + tooltip=_('Insert picture')) + toolbar.pack_start(browsepicture, False) + + browsesound = ToolButton( + icon_name='import_sound', + tooltip=_('Insert sound')) + toolbar.pack_start(browsesound, False) + + browsepicture.connect('clicked', self._load_image) + browsesound.connect('clicked', self._load_audio) + + if speak.espeak.supported: + self.usespeak = ToggleToolButton( + named_icon='speak', + palette=SpeakPalette(self)) + toolbar.pack_start(self.usespeak, False) + self.usespeak.connect('toggled', self._usespeak_cb) + else: + self.usespeak = None + + toolbar_box = CanvasRoundBox( + radius=8, + border=2, + border_color=style.COLOR_BUTTON_GREY.get_int(), + background_color=style.COLOR_PANEL_GREY.get_int()) + toolbar_box.append(hippo.CanvasWidget(widget=toolbar), + hippo.PACK_EXPAND) + toolbar_canvas = hippo.Canvas() + toolbar_canvas.set_root(toolbar_box) + box.pack_start(toolbar_canvas, False) + + self.add(box) + def update_text(self, entry): self.card.change_text(entry.get_text()) if len(entry.get_text()) == 0: self.emit('has-text', False) else: self.emit('has-text', True) - + def get_text(self): return self.textentry.get_text() @@ -280,91 +326,90 @@ class CardEditor(gtk.EventBox): if newtext == None: newtext = '' self.textentry.set_text(newtext) - + + def get_speak(self): + if self.usespeak is None: + return None + if self.usespeak.props.active: + return self.usespeak.palette.face.status.voice.friendlyname + + def set_speak(self, value): + if self.usespeak is None: + return + if value is None: + self.usespeak.props.active = False + else: + try: + self.usespeak.handler_block_by_func(self._usespeak_cb) + self.usespeak.props.active = True + finally: + self.usespeak.handler_unblock_by_func(self._usespeak_cb) + self.usespeak.palette.voices.resume(value) + def get_pixbuf(self): return self.card.get_pixbuf() - + def set_pixbuf(self, pixbuf): self.card.set_pixbuf(pixbuf) - - def _import_image(self, widget, event): - if hasattr(mime, 'GENERIC_TYPE_IMAGE'): - filter = { 'what_filter': mime.GENERIC_TYPE_IMAGE } - else: - filter = { } - - chooser = ObjectChooser(_('Choose image'), None, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - **filter) - try: - result = chooser.run() - if result == gtk.RESPONSE_ACCEPT: - _logger.debug('ObjectChooser: %r' % chooser.get_selected_object()) - jobject = chooser.get_selected_object() - if jobject and jobject.file_path: - self._load_image(jobject.file_path) - finally: - chooser.destroy() - del chooser - - def _load_image(self, index): - pixbuf_t = gtk.gdk.pixbuf_new_from_file_at_size( - index, theme.PAIR_SIZE - theme.PAD*2, theme.PAIR_SIZE - theme.PAD*2) - if pixbuf_t.get_width() > pixbuf_t.get_height(): - size = pixbuf_t.get_width() - else: - size = pixbuf_t.get_height() - pixbuf_z = gtk.gdk.pixbuf_new_from_file_at_size( - 'images/white.png', size, size) - pixbuf_t.composite(pixbuf_z, 0, 0, pixbuf_t.get_width(), - pixbuf_t.get_height(), 0, 0, 1, 1, - gtk.gdk.INTERP_BILINEAR, 255) - self.card.set_pixbuf(pixbuf_z) - _logger.error('Picture Loaded: '+index) - self.emit('has-picture', True) - del pixbuf_t - del pixbuf_z - - def _import_audio(self, widget, event): - if hasattr(mime, 'GENERIC_TYPE_AUDIO'): - filter = { 'what_filter': mime.GENERIC_TYPE_AUDIO } - else: - filter = { } - - chooser = ObjectChooser(_('Choose audio'), None, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - **filter) - jobject = '' - try: - result = chooser.run() - if result == gtk.RESPONSE_ACCEPT: - _logger.debug('ObjectChooser: %r' % chooser.get_selected_object()) - jobject = chooser.get_selected_object() - if not jobject or not jobject.file_path: - return - finally: - chooser.destroy() - del chooser - - if jobject and jobject.file_path: - self._load_audio(jobject.file_path) - - def _load_audio(self, index): - dst = join(self.temp_folder, basename(index)) - shutil.copy(index, dst) - self.set_snd(dst) - icon_theme = gtk.icon_theme_get_default() - pixbuf_t = icon_theme.load_icon("audio-x-generic", - style.XLARGE_ICON_SIZE, 0) - self.card.set_pixbuf(pixbuf_t) - self.emit('has-sound', True) - _logger.debug('Audio Loaded: '+dst) - + + def _load_image(self, widget): + def load(index): + self.set_speak(None) + + pixbuf_t = gtk.gdk.pixbuf_new_from_file_at_size( + index, theme.PAIR_SIZE - theme.PAD*2, + theme.PAIR_SIZE - theme.PAD*2) + size = max(pixbuf_t.get_width(), pixbuf_t.get_height()) + pixbuf_z = gtk.gdk.pixbuf_new_from_file_at_size( + 'images/white.png', size, size) + pixbuf_t.composite(pixbuf_z, 0, 0, pixbuf_t.get_width(), + pixbuf_t.get_height(), 0, 0, 1, 1, + gtk.gdk.INTERP_BILINEAR, 255) + self.card.set_pixbuf(pixbuf_z) + _logger.debug('Picture Loaded: '+index) + self.emit('has-picture', True) + del pixbuf_t + del pixbuf_z + + chooser.pick(what=chooser.IMAGE, + cb=lambda jobject: load(jobject.file_path)) + + def _load_audio(self, widget): + def load(index): + self.set_speak(None) + + dst = join(self.temp_folder, basename(index)) + shutil.copy(index, dst) + self.set_snd(dst) + icon_theme = gtk.icon_theme_get_default() + pixbuf_t = icon_theme.load_icon("audio-x-generic", + style.XLARGE_ICON_SIZE, 0) + self.card.set_pixbuf(pixbuf_t) + self.emit('has-sound', True) + _logger.debug('Audio Loaded: '+dst) + + chooser.pick(what=chooser.AUDIO, + cb=lambda jobject: load(jobject.file_path)) + + def _usespeak_cb(self, button): + self.card.change_speak(button.props.active) + + if not button.props.active: + self.usespeak.palette.face.shut_up() + return + + self.snd = None + self.card.set_pixbuf(None) + self.emit('has-sound', False) + self.emit('has-picture', False) + + button.palette.face.say(self.get_text()) + def set_snd(self, snd): self.snd = snd - + def get_snd(self): - return self.snd + return self.snd def clean(self): self.textentry.set_text('') @@ -373,3 +418,26 @@ class CardEditor(gtk.EventBox): self.emit('has-text', False) self.emit('has-picture', False) self.emit('has-sound', False) + if self.usespeak is not None: + self.usespeak.props.active = False + self.usespeak.palette.face.shut_up() + +class SpeakPalette(Palette): + def __init__(self, editor): + Palette.__init__(self, _('Pronounce text while fliping tile')) + + self.face = speak.face.View() + + toolbar = gtk.HBox() + toolbar.modify_bg(gtk.STATE_NORMAL, style.COLOR_BLACK.get_gdk_color()) + + usespeak_play = ToolButton(icon_name='media-playback-start') + usespeak_play.connect('clicked', lambda button: + self.face.say(editor.get_text())) + toolbar.pack_start(usespeak_play, False) + + self.voices = speak.widgets.Voices(self.face) + toolbar.pack_start(ToolComboBox(self.voices)) + + toolbar.show_all() + self.set_content(toolbar) |