Codebase list sugar-memorize-activity / debian/34+git20091021.837e6c6b-1 cardlist.py
debian/34+git20091021.837e6c6b-1

Tree @debian/34+git20091021.837e6c6b-1 (Download .tar.gz)

cardlist.py @debian/34+git20091021.837e6c6b-1raw · history · blame

#    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, 9 * [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
                
            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,
                    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 add_pair(self, widget, achar, bchar, aimg, bimg, asnd, bsnd,
            aspeak, bspeak, show = True):
        pair = Pair(achar, bchar, aimg, bimg, asnd, bsnd, aspeak, bspeak)
        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)

    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))

    def update_selected(self, widget, newtext1, newtext2, aimg, bimg,
            asnd, bsnd, aspeak, bspeak):
        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.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):
        gtk.EventBox.__init__(self)
        self.bg_color = '#000000'

        self.asnd = asnd
        self.bsnd = bsnd

        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)
        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)
        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 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