diff options
Diffstat (limited to 'cardlist.py')
-rw-r--r-- | cardlist.py | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/cardlist.py b/cardlist.py new file mode 100644 index 0000000..5b5793e --- /dev/null +++ b/cardlist.py @@ -0,0 +1,408 @@ +# Copyright (C) 2006, 2007, 2008 One Laptop Per Child +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import gtk +import svgcard +import logging + +import os +from os import environ +from os.path import join + +import model +import zipfile +import tempfile +from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT + +from sugar.graphics import style +from sugar.graphics.icon import Icon + +import theme + +_logger = logging.getLogger('memorize-activity') + +class CardList(gtk.EventBox): + + __gsignals__ = { + 'pair-selected': (SIGNAL_RUN_FIRST, None, 11 * [TYPE_PYOBJECT]), + 'update-create-toolbar': (SIGNAL_RUN_FIRST, None, 3 * [TYPE_PYOBJECT]), + 'update-create-buttons': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]), + } + + def __init__(self): + gtk.EventBox.__init__(self) + self.model = model.Model() + self.pairs = [] + self.current_pair = None + self.current_game_key = None + + self.vbox = gtk.VBox(False) + + fill_box = gtk.Label() + fill_box.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#000000')) + fill_box.show() + self.vbox.pack_end(fill_box, True, True) + + scroll = gtk.ScrolledWindow() + scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scroll.add_with_viewport(self.vbox) + scroll.set_border_width(0) + scroll.get_child().modify_bg(gtk.STATE_NORMAL, + gtk.gdk.color_parse('#000000')) + self.add(scroll) + self.show_all() + + def load_game(self, widget, game_name): + self.model.read(game_name) + self.current_game_key = self.model.data['game_file'] + self.emit('update-create-toolbar', self.model.data['name'], + self.model.data.get('equal_pairs', 'False'), + self.model.data.get('divided', '0')) + game_pairs = self.model.pairs + game_data = self.model.data + self.clean_list() + for key in game_pairs: + if game_pairs[key].props.aimg != None: + aimg = gtk.gdk.pixbuf_new_from_file( \ + join(self.model.data['pathimg'], + game_pairs[key].props.aimg)) + else: + aimg = None + + if game_pairs[key].props.bimg != None: + bimg = gtk.gdk.pixbuf_new_from_file( \ + join(self.model.data['pathimg'], + game_pairs[key].props.bimg)) + else: + bimg = None + + if game_pairs[key].props.asnd != None: + asnd = join(self.model.data['pathsnd'], + game_pairs[key].props.asnd) + else: + asnd = None + + if game_pairs[key].props.bsnd != None: + bsnd = join(self.model.data['pathsnd'], + game_pairs[key].props.bsnd) + else: + bsnd = None + + if game_pairs[key].props.asensor != None: + asensor = game_pairs[key].props.asensor + if game_pairs[key].props.bsensor != None: + bsensor = game_pairs[key].props.bsensor + + self.add_pair(None, game_pairs[key].props.achar, + game_pairs[key].props.bchar, aimg, bimg, asnd, bsnd, + game_pairs[key].props.aspeak, game_pairs[key].props.bspeak, + game_pairs[key].props.asensor, game_pairs[key].props.bsensor, + False) + + def save_game(self, widget, game_name, equal_pairs, grouped): + + tmp_root = join(environ['SUGAR_ACTIVITY_ROOT'], 'instance') + temp_folder = tempfile.mkdtemp(dir=tmp_root) + os.chmod(temp_folder, 0777) + temp_img_folder = join(temp_folder, 'images') + temp_snd_folder = join(temp_folder, 'sounds') + + os.makedirs(temp_img_folder) + os.makedirs(temp_snd_folder) + + game_zip = zipfile.ZipFile(join(temp_folder, 'game.zip'), 'w') + + game_model = model.Model(temp_folder) + game_model.data['name'] = game_name + for pair in range(len(self.pairs)): + pair_card = model.Pair() + + # achar + achar = self.pairs[pair].get_text(1) + if achar != '': + pair_card.set_property('achar', achar) + + # bchar + bchar = self.pairs[pair].get_text(2) + if bchar != '': + pair_card.set_property('bchar', bchar) + + # aspeak + aspeak = self.pairs[pair].get_speak(1) + pair_card.set_property('aspeak', aspeak) + + # bspeak + bspeak = self.pairs[pair].get_speak(2) + pair_card.set_property('bspeak', bspeak) + + # aimg + aimg = self.pairs[pair].get_pixbuf(1) + if aimg != None: + + if equal_pairs: + aimgfile = 'img' + str(pair) + '.jpg' + else: + aimgfile = 'aimg' + str(pair) + '.jpg' + aimg.save(join(temp_img_folder, aimgfile), 'jpeg', + {'quality':'85'}) + game_zip.write(join(temp_img_folder, aimgfile), + join('images', aimgfile)) + pair_card.set_property('aimg', aimgfile) + + # bimg + bimg = self.pairs[pair].get_pixbuf(2) + if bimg != None: + if equal_pairs: + bimgfile = 'img' + str(pair) + '.jpg' + else: + bimgfile = 'bimg' + str(pair) + '.jpg' + bimg.save(join(temp_img_folder, bimgfile), 'jpeg', + {'quality':'85'}) + game_zip.write(join(temp_img_folder, bimgfile), + join('images', bimgfile)) + pair_card.set_property('bimg', bimgfile) + # asnd + asnd = self.pairs[pair].get_sound(1) + if asnd != None: + if equal_pairs: + asndfile = 'snd' + str(pair) + '.ogg' + else: + asndfile = 'asnd' + str(pair) + '.ogg' + _logger.error(asndfile + ': ' + asnd) + game_zip.write(asnd, join('sounds', asndfile)) + pair_card.set_property('asnd', asndfile) + + # bsnd + bsnd = self.pairs[pair].get_sound(2) + if bsnd != None: + if equal_pairs: + bsndfile = 'snd'+str(pair)+'.ogg' + else: + bsndfile = 'bsnd' + str(pair) + '.ogg' + game_zip.write(bsnd, join('sounds', bsndfile)) + _logger.error(bsndfile + ': ' + bsnd) + pair_card.set_property('bsnd', bsndfile) + + game_model.pairs[pair] = pair_card + game_model.write(equal_pairs, grouped) + game_zip.write(join(temp_folder, 'game.xml'), 'game.xml') + game_zip.close() + game_model.save_byte_array(join(temp_folder, 'game.zip'), game_name) + + def clean_list(self, button = None): + if button != None: + self.current_game_key = None + map(lambda x: self.vbox.remove(x), self.pairs) + del self.pairs + self.pairs = [] + + def clean_tmp_folder(self, path): + for root, dirs, files in os.walk(path, topdown=False): + for name in files: + os.remove(join(root, name)) + for name in dirs: + os.rmdir(join(root, name)) + os.rmdir(path) + + def trysensor(self, avg): + for pair in self.pairs: + if(abs(avg-int(pair.asensor)) < 100): + self.bcard1.set_sensor(pair.asensor) + elif(abs(avg-int(pair.bsensor)) < 100): + self.bcard2.set_sensor(pair.bsensor) + + def add_pair(self, widget, achar, bchar, aimg, bimg, asnd, bsnd, + aspeak, bspeak, asensor, bsensor, show = True): + pair = Pair(achar, bchar, aimg, bimg, asnd, bsnd, aspeak, bspeak, asensor, bsensor) + self.vbox.pack_end(pair, False, True) + self.pairs.append(pair) + pair.connect('pair-selected', self.set_selected) + pair.connect('pair-closed', self.rem_pair) + self.emit('update-create-buttons', True, True) + if show: + self.show_all() + + def rem_pair(self, widget, event): + self.vbox.remove(widget) + self.pairs.remove(widget) + del widget + self.emit('update-create-buttons', True, True) + self.emit('pair-selected', False, None, None, None, None, None, None, + False, False, False, False) + + def set_selected(self, widget, event): + if self.current_pair is not None: + current_pair = self.current_pair + current_pair.set_selected(False) + self.current_pair = widget + widget.set_selected(True) + self.emit('pair-selected', True, + self.current_pair.get_text(1), self.current_pair.get_text(2), + self.current_pair.get_pixbuf(1), self.current_pair.get_pixbuf(2), + self.current_pair.get_sound(1), self.current_pair.get_sound(2), + self.current_pair.get_speak(1), self.current_pair.get_speak(2), + self.current_pair.get_sensor(1), self.current_pair.get_sensor(2)) + + def update_selected(self, widget, newtext1, newtext2, aimg, bimg, + asnd, bsnd, aspeak, bspeak, asensor, bsensor): + self.current_pair.change_text(newtext1, newtext2) + self.current_pair.change_pixbuf(aimg, bimg) + self.current_pair.change_sound(asnd, bsnd) + self.current_pair.change_speak(aspeak, bspeak) + self.current_pair.change_sensor(asensor, bsensor) + + self.emit('update-create-buttons', True, True) + +class Pair(gtk.EventBox): + + __gsignals__ = { + 'pair-selected': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), + 'pair-closed': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), + } + + def __init__(self, text1, text2 = None, aimg = None, bimg = None, + asnd = None, bsnd = None, aspeak=None, bspeak=None, asensor=None, bsensor=None): + gtk.EventBox.__init__(self) + self.bg_color = '#000000' + + self.asnd = asnd + self.bsnd = bsnd + self.asensor = asensor + self.bsensor = bsensor + + self.current_game_key = None + + row = gtk.HBox() + row.props.border_width = 10 + row.props.spacing = 10 + + self.bcard1 = svgcard.SvgCard(-1, + { 'front_text' : { 'card_text' : text1, + 'speak' : aspeak, + 'text_color' : '#ffffff' }, + 'front' : { 'fill_color' : '#4c4d4f', + 'stroke_color' : '#ffffff', + 'opacity' : '1' } }, + None, theme.PAIR_SIZE, 1, self.bg_color) + self.bcard1.flip() + self.bcard1.set_pixbuf(aimg) + self.bcard1.set_sensor(asensor) + align = gtk.Alignment(.5, .5, 0, 0) + align.add(self.bcard1) + row.pack_start(align) + + self.bcard2 = svgcard.SvgCard(-1, + { 'front_text' : { 'card_text' : text2, + 'speak' : bspeak, + 'text_color' : '#ffffff' }, + 'front' : { 'fill_color' : '#4c4d4f', + 'stroke_color' : '#ffffff', + 'opacity' : '1' } }, + None, theme.PAIR_SIZE, 1, self.bg_color) + self.bcard2.flip() + self.bcard2.set_pixbuf(bimg) + self.bcard2.set_sensor(bsensor) + align = gtk.Alignment(.5, .5, 0, 0) + align.add(self.bcard2) + row.pack_start(align) + + close_image = Icon( + icon_name='remove', + icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR) + align = gtk.Alignment(.5, .5) + align.add(close_image) + close_button = gtk.ToolButton() + close_button.set_icon_widget(align) + close_button.connect('clicked', self.emit_close) + close_button.set_size_request(style.STANDARD_ICON_SIZE, + style.STANDARD_ICON_SIZE) + align = gtk.Alignment(.5, 0, 0, 0) + align.add(close_button) + row.pack_start(align, False) + + self.connect('button-press-event', self.emit_selected) + self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.bg_color)) + self.add(row) + self.show_all() + + def emit_selected(self, widget, event): + self.emit('pair-selected', self) + + def emit_close(self, widget): + self.emit('pair-closed', self) + + def set_selected(self, status): + if not status: + self.bg_color = '#000000' + else: + self.bg_color = '#b2b3b7' + + self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.bg_color)) + self.bcard1.set_background(self.bg_color) + self.bcard2.set_background(self.bg_color) + + def change_pixbuf(self, aimg, bimg): + self.bcard1.set_pixbuf(aimg) + self.bcard2.set_pixbuf(bimg) + + def change_text(self, text1, text2): + self.bcard1.change_text(text1) + self.bcard2.change_text(text2) + + def change_sound(self, asnd, bsnd): + self.asnd = asnd + self.bsnd = bsnd + + def change_sensor(self, asensor, bsensor): + self.asensor = asensor + self.bcard1.set_sensor(asensor) + self.bsensor = bsensor + self.bcard2.set_sensor(bsensor) + + def get_text(self, card): + if card == 1: + return self.bcard1.get_text() + else: + return self.bcard2.get_text() + + def change_speak(self, aspeak, bspeak): + self.bcard1.change_speak(aspeak) + self.bcard2.change_speak(bspeak) + + def get_speak(self, card): + if card == 1: + return self.bcard1.get_speak() + else: + return self.bcard2.get_speak() + + def get_pixbuf(self, card): + if card == 1: + return self.bcard1.get_pixbuf() + else: + return self.bcard2.get_pixbuf() + + def get_sound(self, card): + if card == 1: + return self.asnd + else: + return self.bsnd + + def get_sensor(self, card): + if card == 1: + return self.asensor + else: + return self.bsensor |