From a998a202ee7afe0ef283bbae8eb338294c004abc Mon Sep 17 00:00:00 2001 From: Rafael Ortiz Date: Tue, 27 Sep 2011 17:23:17 +0000 Subject: matching mainline --- diff --git a/activity.py b/activity.py index 81c36ae..f6d822e 100644 --- a/activity.py +++ b/activity.py @@ -27,13 +27,19 @@ import logging _logger = logging.getLogger('memorize-activity') from gettext import gettext as _ -from os.path import join, dirname +import os + +import zipfile import gtk import telepathy import telepathy.client -from sugar.activity.activity import Activity, ActivityToolbox +from sugar.activity.widgets import ActivityToolbarButton +from sugar.activity.widgets import StopButton +from sugar.graphics.toolbarbox import ToolbarBox +from sugar.graphics.radiotoolbutton import RadioToolButton +from sugar.activity.activity import Activity from sugar.presence import presenceservice from sugar.presence.tubeconn import TubeConnection @@ -52,38 +58,85 @@ SERVICE = 'org.laptop.Memorize' IFACE = SERVICE PATH = '/org/laptop/Memorize' -_TOOLBAR_PLAY = 1 -_TOOLBAR_CREATE = 2 +_MODE_PLAY = 1 +_MODE_CREATE = 2 + class MemorizeActivity(Activity): - + def __init__(self, handle): Activity.__init__(self, handle) - self.create_load = False self.play_mode = None - - toolbox = ActivityToolbox(self) - activity_toolbar = toolbox.get_activity_toolbar() - - self._memorizeToolbar = memorizetoolbar.MemorizeToolbar(self) - toolbox.add_toolbar(_('Play'), self._memorizeToolbar) - self._memorizeToolbar.show() - - self._createToolbar = createtoolbar.CreateToolbar(self) - toolbox.add_toolbar(_('Create'), self._createToolbar) - self._createToolbar.show() - - self.set_toolbox(toolbox) - toolbox.show() - + + toolbar_box = ToolbarBox() + self.set_toolbar_box(toolbar_box) + + self.activity_button = ActivityToolbarButton(self) + toolbar_box.toolbar.insert(self.activity_button, -1) + + tool_group = None + self._play_button = RadioToolButton() + self._play_button.mode = _MODE_PLAY + self._play_button.props.icon_name = 'player_play' + self._play_button.set_tooltip(_('Play game')) + self._play_button.props.group = tool_group + toolbar_box.toolbar.insert(self._play_button, -1) + tool_group = self._play_button + + self._edit_button = RadioToolButton() + self._edit_button.mode = _MODE_CREATE + self._edit_button.props.icon_name = 'view-source' + self._edit_button.set_tooltip(_('Edit game')) + self._edit_button.props.group = tool_group + toolbar_box.toolbar.insert(self._edit_button, -1) + + toolbar_box.toolbar.insert(gtk.SeparatorToolItem(), -1) + + self._memorizeToolbarBuilder = \ + memorizetoolbar.MemorizeToolbarBuilder(self) + + toolbar_box.toolbar.insert(gtk.SeparatorToolItem(), -1) + + self._createToolbarBuilder = \ + createtoolbar.CreateToolbarBuilder(self) + + separator = gtk.SeparatorToolItem() + separator.set_expand(True) + separator.set_draw(False) + separator.set_size_request(0, -1) + toolbar_box.toolbar.insert(separator, -1) + + toolbar_box.toolbar.insert(StopButton(self), -1) + # Play game mode self.table = cardtable.CardTable() self.scoreboard = scoreboard.Scoreboard() + self.cardlist = cardlist.CardList() + self.createcardpanel = createcardpanel.CreateCardPanel() + self.cardlist.connect('pair-selected', + self.createcardpanel.pair_selected) + self.cardlist.connect('update-create-toolbar', + self._createToolbarBuilder.update_create_toolbar) + self.createcardpanel.connect('add-pair', + self.cardlist.add_pair) + self.createcardpanel.connect('update-pair', + self.cardlist.update_selected) + self._createToolbarBuilder.connect('create_new_game', + self.cardlist.clean_list) + self._createToolbarBuilder.connect('create_new_game', + self.createcardpanel.clean) + self._createToolbarBuilder.connect('create_equal_pairs', + self.change_equal_pairs) self.game = game.MemorizeGame() + self._play_button.connect('clicked', self._change_mode_bt) + self._edit_button.connect('clicked', self._change_mode_bt) + self.table.connect('key-press-event', self.table.key_press_event) self.table.connect('card-flipped', self.game.card_flipped) + self.table.connect('card-flipped', + self._memorizeToolbarBuilder.card_flipped) self.table.connect('card-overflipped', self.game.card_overflipped) self.table.connect('card-highlighted', self.game.card_highlighted) @@ -107,11 +160,14 @@ class MemorizeActivity(Activity): self.game.connect('load_game', self.table.load_game) self.game.connect('change_game', self.table.change_game) - self.game.connect('load_game', self._memorizeToolbar.update_toolbar) - self.game.connect('change_game', self._memorizeToolbar.update_toolbar) - - self._memorizeToolbar.connect('game_changed', self.game.change_game) - + self.game.connect('load_game', + self._memorizeToolbarBuilder.update_toolbar) + self.game.connect('change_game', + self._memorizeToolbarBuilder.update_toolbar) + + self._memorizeToolbarBuilder.connect('game_changed', + self.change_game) + self.hbox = gtk.HBox(False) self.set_canvas(self.hbox) @@ -126,80 +182,135 @@ class MemorizeActivity(Activity): # start on the game toolbar, might change this # to the create toolbar later - self.toolbox.connect('current-toolbar-changed', self.change_mode) - self.toolbox.set_current_toolbar(_TOOLBAR_PLAY) + self._change_mode(_MODE_PLAY) # Get the Presence Service self.pservice = presenceservice.get_instance() self.initiating = None - + # Buddy object for you owner = self.pservice.get_owner() self.owner = owner self.current = 0 - - self.game.set_myself(self.owner) + + self.game.set_myself(self.owner) 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() - else: + self._joined_cb(self) + elif not self._jobject.file_path: _logger.debug('buddy joined - __init__: %s', self.owner.props.nick) - game_file = join(dirname(__file__), 'demos', 'addition.zip') + game_file = os.path.join(os.path.dirname(__file__), 'demos', + 'addition.zip') self.game.load_game(game_file, 4, 'demo') - _logger.debug('loading conventional') + self.cardlist.load_game(self.game) + _logger.debug('loading conventional') + self.game.add_buddy(self.owner) + else: self.game.add_buddy(self.owner) self.show_all() - + + def _change_mode_bt(self, button): + if button.get_active(): + self._change_mode(button.mode) + def read_file(self, file_path): - if self.metadata['mime_type'] == 'application/x-memorize-project': - self.toolbox.set_current_toolbar(_TOOLBAR_PLAY) - if self.metadata.has_key('icon-color'): - color = self.metadata['icon-color'] - else: - color = profile.get_color().to_string() - self.game.change_game(None, file_path, 4, 'file', - self.metadata['title'], color) - - def change_mode(self, notebook, index): - if index == _TOOLBAR_CREATE: - if not self.create_load: - # Create game mode - self.cardlist = cardlist.CardList() - self.createcardpanel = createcardpanel.CreateCardPanel() - self.createcardpanel.connect('add-pair', self.cardlist.add_pair) - self.createcardpanel.connect('update-pair', - self.cardlist.update_selected) - self.cardlist.connect('pair-selected', - self.createcardpanel.pair_selected) - self.cardlist.connect('update-create-toolbar', - self._createToolbar.update_create_toolbar) - self.cardlist.connect('update-create-buttons', - self._createToolbar.update_buttons_status) - self._createToolbar.connect('create_new_game', - self.cardlist.clean_list) - self._createToolbar.connect('create_new_game', - self.createcardpanel.clean) - self._createToolbar.connect('create_load_game', - self.cardlist.load_game) - self._createToolbar.connect('create_save_game', - self.cardlist.save_game) - self._createToolbar.connect('create_equal_pairs', \ - self.createcardpanel.change_equal_pairs) - self.create_load = True - - self.hbox.remove(self.scoreboard) - self.hbox.remove(self.table) - self.hbox.pack_start(self.createcardpanel, False) - self.hbox.pack_start(self.cardlist) - self.play_mode = False + if 'icon-color' in self.metadata: + color = self.metadata['icon-color'] + else: + color = profile.get_color().to_string() + self.change_game(None, file_path, 4, 'file', + self.metadata['title'], color) + def close(self, skip_save=False): + if self.game.model.is_demo: + Activity.close(self, skip_save=True) else: + Activity.close(self) + + def write_file(self, file_path): + temp_img_folder = os.path.join(self.game.model.temp_folder, 'images') + temp_snd_folder = os.path.join(self.game.model.temp_folder, 'sounds') + self.game.model.create_temp_directories() + game_zip = zipfile.ZipFile(file_path, 'w') + equal_pairs = self.game.model.data['equal_pairs'] == '1' + for pair in self.game.model.pairs: + # aimg + aimg = self.game.model.pairs[pair].get_property('aimg') + if aimg != None: + if equal_pairs: + aimgfile = 'img' + str(pair) + '.jpg' + else: + aimgfile = 'aimg' + str(pair) + '.jpg' + game_zip.write(os.path.join(temp_img_folder, aimgfile), + os.path.join('images', aimgfile)) + + # bimg + bimg = self.game.model.pairs[pair].get_property('bimg') + if bimg != None: + if equal_pairs: + bimgfile = 'img' + str(pair) + '.jpg' + else: + bimgfile = 'bimg' + str(pair) + '.jpg' + game_zip.write(os.path.join(temp_img_folder, bimgfile), + os.path.join('images', bimgfile)) + # asnd + asnd = self.game.model.pairs[pair].get_property('asnd') + if asnd != None: + game_zip.write(os.path.join(temp_snd_folder, asnd), + os.path.join('sounds', asnd)) + + # bsnd + bsnd = self.game.model.pairs[pair].get_property('bsnd') + if bsnd != None: + game_zip.write(os.path.join(temp_snd_folder, bsnd), + os.path.join('sounds', bsnd)) + + self.game.model.game_path = self.game.model.temp_folder + self.game.model.write() + game_zip.write(os.path.join(self.game.model.temp_folder, 'game.xml'), + 'game.xml') + game_zip.close() + self.metadata['mime_type'] = 'application/x-memorize-project' + + def _complete_close(self): + self._remove_temp_files() + Activity._complete_close(self) + + def _remove_temp_files(self): + tmp_root = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'instance') + for root, dirs, files in os.walk(tmp_root, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + os.rmdir(os.path.join(root, name)) + + def _change_mode(self, mode): + logging.debug("Change mode %s" % mode) + if mode == _MODE_CREATE: + if self.play_mode == True: + self.hbox.remove(self.scoreboard) + self.hbox.remove(self.table) + self.hbox.pack_start(self.createcardpanel, False) + self.hbox.pack_start(self.cardlist) + self.game.model.create_temp_directories() + self.createcardpanel.set_temp_folder( + self.game.model.temp_folder) + self.play_mode = False + else: + if self.game.model.modified: + self.cardlist.update_model(self.game.model) + self.game.reset_game() + self.table.change_game(None, self.game.model.data, + self.game.model.grid) + self.save() + self.game.model.modified = False + if self.play_mode == False: self.hbox.remove(self.createcardpanel) self.hbox.remove(self.cardlist) @@ -207,13 +318,20 @@ class MemorizeActivity(Activity): self.hbox.pack_start(self.scoreboard) self.hbox.pack_start(self.table, False) self.play_mode = True - - def restart(self, widget): - self.game.reset() + self._memorizeToolbarBuilder.update_controls(mode == _MODE_PLAY) + self._createToolbarBuilder.update_controls(mode == _MODE_CREATE) + + def change_game(self, widget, game_name, size, mode, + title=None, color=None): + _logger.debug('Change game %s', game_name) + self.game.change_game(widget, game_name, size, mode, title, color) + if game_name is not None: + self.cardlist.load_game(self.game) + + def change_equal_pairs(self, widget, state): + self.cardlist.update_model(self.game.model) + self.createcardpanel.change_equal_pairs(widget, state) - def change_game(self, game_name, size, title=None, color=None): - self.game.change_game(game_name, size, title, color) - def _shared_cb(self, activity): _logger.debug('My activity was shared') self.initiating = True @@ -230,10 +348,10 @@ class MemorizeActivity(Activity): 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) - + self._shared_activity.connect('buddy-joined', self._buddy_joined_cb) self._shared_activity.connect('buddy-left', self._buddy_left_cb) @@ -263,7 +381,7 @@ class MemorizeActivity(Activity): _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, + reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) def _new_tube_cb(self, identifier, initiator, tube_type, service, @@ -278,7 +396,7 @@ class MemorizeActivity(Activity): self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube( \ identifier) - self.tube_conn = TubeConnection(self.conn, + self.tube_conn = TubeConnection(self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], identifier, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]) @@ -299,8 +417,8 @@ class MemorizeActivity(Activity): assert handle != 0 return self.pservice.get_buddy_by_telepathy_handle( \ self.tp_conn_name, self.tp_conn_path, handle) - - def _buddy_joined_cb (self, activity, buddy): + + def _buddy_joined_cb(self, activity, buddy): if buddy != self.owner: if buddy.props.nick == '': _logger.debug("buddy joined: empty nick=%s. Will not add.", @@ -309,7 +427,7 @@ class MemorizeActivity(Activity): _logger.debug("buddy joined: %s", buddy.props.nick) self.game.add_buddy(buddy) - def _buddy_left_cb (self, activity, buddy): + def _buddy_left_cb(self, activity, buddy): if buddy.props.nick == '': _logger.debug("buddy joined: empty nick=%s. Will not remove", buddy.props.nick) @@ -317,11 +435,11 @@ class MemorizeActivity(Activity): _logger.debug("buddy left: %s", buddy.props.nick) self.game.rem_buddy(buddy) - def _focus_in(self, event, data=None): + def _focus_in(self, event, data=None): self.game.audio.play() - - def _focus_out(self, event, data=None): + + def _focus_out(self, event, data=None): self.game.audio.pause() - - def _cleanup_cb(self, data=None): - self.game.audio.stop() + + def _cleanup_cb(self, data=None): + self.game.audio.stop() diff --git a/audio.py b/audio.py index 09522bb..ddee412 100644 --- a/audio.py +++ b/audio.py @@ -20,6 +20,7 @@ import logging _logger = logging.getLogger('memorize-activity') + class Audio(object): def __init__(self): self._player = gst.element_factory_make('playbin', 'player') diff --git a/cardlist.py b/cardlist.py index 35fcea4..ba126b9 100644 --- a/cardlist.py +++ b/cardlist.py @@ -18,14 +18,11 @@ import gtk import svgcard import logging +from os.path import join, basename +import shutil -import os -from os import environ -from os.path import join +from model import Pair -import model -import zipfile -import tempfile from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT from sugar.graphics import style @@ -35,20 +32,20 @@ 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.model = None self.vbox = gtk.VBox(False) @@ -56,25 +53,22 @@ class CardList(gtk.EventBox): 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, + 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) + + def load_game(self, game): + self.model = game.model 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() + self.clean_list(load=True) for key in game_pairs: if game_pairs[key].props.aimg != None: aimg = gtk.gdk.pixbuf_new_from_file( \ @@ -82,49 +76,43 @@ class CardList(gtk.EventBox): 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: + + 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 + False, load=True) + self.emit('update-create-toolbar', self.model.data['name'], + self.model.data['equal_pairs'], + self.model.data['divided']) + + def update_model(self, game_model): + game_model.pairs = {} + equal_pairs = game_model.data['equal_pairs'] == '1' + game_model.create_temp_directories() + temp_img_folder = join(game_model.temp_folder, 'images') + temp_snd_folder = join(game_model.temp_folder, 'sounds') + for pair in range(len(self.pairs)): - pair_card = model.Pair() - + pair_card = Pair() # achar achar = self.pairs[pair].get_text(1) if achar != '': @@ -146,17 +134,13 @@ class CardList(gtk.EventBox): # 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) - + aimg.save(join(temp_img_folder, aimgfile), 'jpeg', + {'quality': '85'}) # bimg bimg = self.pairs[pair].get_pixbuf(2) if bimg != None: @@ -164,70 +148,49 @@ class CardList(gtk.EventBox): 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) + bimg.save(join(temp_img_folder, bimgfile), 'jpeg', + {'quality': '85'}) + # asnd asnd = self.pairs[pair].get_sound(1) + logging.debug('update_model asnd %s', asnd) 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) - + pair_card.set_property('asnd', basename(asnd)) # bsnd bsnd = self.pairs[pair].get_sound(2) + logging.debug('update_model bsnd %s', bsnd) 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) - + pair_card.set_property('bsnd', basename(bsnd)) + 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): + def clean_list(self, button=None, load=False): 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) - + if not load: + self.model.mark_modified() + 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) + aspeak, bspeak, show=True, load=False): + pair = CardPair(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 not load: + self.model.mark_modified() if show: self.show_all() - + def rem_pair(self, widget, event): - self.vbox.remove(widget) + self.vbox.remove(widget) self.pairs.remove(widget) del widget - self.emit('update-create-buttons', True, True) + self.model.mark_modified() self.emit('pair-selected', False, None, None, None, None, None, None, False, False) @@ -235,13 +198,17 @@ class CardList(gtk.EventBox): if self.current_pair is not None: current_pair = self.current_pair current_pair.set_selected(False) - self.current_pair = widget + 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_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): @@ -249,18 +216,18 @@ class CardList(gtk.EventBox): 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): + self.model.mark_modified() + + +class CardPair(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): + 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' @@ -274,12 +241,12 @@ class Pair(gtk.EventBox): 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' } }, + {'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) @@ -288,12 +255,12 @@ class Pair(gtk.EventBox): 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' } }, + {'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) @@ -331,15 +298,15 @@ class Pair(gtk.EventBox): 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) diff --git a/cardtable.py b/cardtable.py index 1f251e2..b9ab29f 100644 --- a/cardtable.py +++ b/cardtable.py @@ -20,7 +20,6 @@ import pango import svgcard import os import math -import gc from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT import logging @@ -28,6 +27,7 @@ _logger = logging.getLogger('memorize-activity') import theme + class CardTable(gtk.EventBox): __gsignals__ = { @@ -60,7 +60,7 @@ class CardTable(gtk.EventBox): self.load_message = gtk.Label('Loading Game') self.load_message.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff')) - self.load_message.modify_font(pango.FontDescription("10")) + self.load_message.modify_font(pango.FontDescription('10')) self.load_message.show() self.first_load = True self.load_mode = False @@ -105,7 +105,7 @@ class CardTable(gtk.EventBox): self.selected_card = [0, 0] self.flipped_card = -1 self.table_positions = {} - + # Build the table if data['divided'] == '1': text1 = str(self.data.get('face1', '')) @@ -124,25 +124,26 @@ class CardTable(gtk.EventBox): else: jpg = None props = {} - props['front_text'] = {'card_text':card.get('char', ''), + props['front_text'] = {'card_text': card.get('char', ''), 'speak': card.get('speak')} if card['ab'] == 'a': - props['back_text'] = {'card_text':text1} + props['back_text'] = {'card_text': text1} elif card['ab'] == 'b': - props['back_text'] = {'card_text':text2} + props['back_text'] = {'card_text': text2} align = self.data.get('align', '1') card = svgcard.SvgCard(identifier, props, jpg, self.card_size, align) card.connect('enter-notify-event', self.mouse_event, [x, y]) - card.connect("button-press-event", self.flip_card_mouse, identifier) + card.connect('button-press-event', + self.flip_card_mouse, identifier) self.table_positions[(x, y)] = 1 self.cd2id[card] = identifier self.id2cd[identifier] = card self.cards[(x, y)] = card self.dict[identifier] = (x, y) - self.table.attach(card, x, x+1, y, y+1, gtk.SHRINK, gtk.SHRINK) + self.table.attach(card, x, x + 1, y, y + 1, gtk.SHRINK, gtk.SHRINK) x += 1 if x == self.size: @@ -164,7 +165,7 @@ class CardTable(gtk.EventBox): self.load_game(None, data, grid) def get_card_size(self, size_table): - x = (self._workspace_size + theme.CARD_PAD * (size_table-1)) / \ + x = (self._workspace_size + theme.CARD_PAD * (size_table - 1)) / \ size_table - theme.CARD_PAD * 2 return x @@ -181,45 +182,45 @@ class CardTable(gtk.EventBox): y = self.selected_card[1] if event.keyval in (gtk.keysyms.Left, gtk.keysyms.KP_Left): - if self.table_positions.has_key((x-1, y)): - card = self.cards[x-1, y] + if (x - 1, y) in self.table_positions: + card = self.cards[x - 1, y] identifier = self.cd2id.get(card) self.emit('card-highlighted', identifier, False) elif event.keyval in (gtk.keysyms.Right, gtk.keysyms.KP_Right): - if self.table_positions.has_key((x+1, y)): - card = self.cards[x+1, y] + if (x + 1, y) in self.table_positions: + card = self.cards[x + 1, y] identifier = self.cd2id.get(card) self.emit('card-highlighted', identifier, False) elif event.keyval in (gtk.keysyms.Up, gtk.keysyms.KP_Up): - if self.table_positions.has_key((x, y-1)): - card = self.cards[x, y-1] + if (x, y - 1) in self.table_positions: + card = self.cards[x, y - 1] identifier = self.cd2id.get(card) self.emit('card-highlighted', identifier, False) - + elif event.keyval in (gtk.keysyms.Down, gtk.keysyms.KP_Down): - if self.table_positions.has_key((x, y+1)): - card = self.cards[x, y+1] + if (x, y + 1) in self.table_positions: + card = self.cards[x, y + 1] identifier = self.cd2id.get(card) self.emit('card-highlighted', identifier, False) elif event.keyval in (gtk.keysyms.space, gtk.keysyms.KP_Page_Down): card = self.cards[x, y] self.card_flipped(card) - + def flip_card_mouse(self, widget, event, identifier): position = self.dict[identifier] card = self.cards[position] self.card_flipped(card) def card_flipped(self, card): - identifer = self.cd2id[card] + identifer = self.cd2id[card] if card.is_flipped(): self.emit('card-overflipped', identifer) else: self.emit('card-flipped', identifer, False) - + def set_border(self, widget, identifer, stroke_color, fill_color): self.id2cd[identifer].set_border(stroke_color, fill_color) @@ -240,7 +241,7 @@ class CardTable(gtk.EventBox): def reset(self, widget): for identifer in self.id2cd.keys(): self.id2cd[identifer].reset() - + def _set_load_mode(self, mode): if mode: self.remove(self.table) @@ -251,10 +252,10 @@ class CardTable(gtk.EventBox): self.load_mode = mode self.queue_draw() while gtk.events_pending(): - gtk.main_iteration() - + gtk.main_iteration() + def load_msg(self, widget, msg): if not self.load_mode: self._set_load_mode(True) self.load_message.set_text(msg) - self.queue_draw() + self.queue_draw() diff --git a/createcardpanel.py b/createcardpanel.py index d7b94ad..dcf2f19 100644 --- a/createcardpanel.py +++ b/createcardpanel.py @@ -18,12 +18,9 @@ # import gtk -from os import environ from os.path import join, basename -import hippo import shutil -import tempfile from gettext import gettext as _ import svgcard import logging @@ -33,7 +30,7 @@ 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.widgets import ToolComboBox from port import chooser import theme @@ -43,6 +40,7 @@ import speak.face _logger = logging.getLogger('memorize-activity') + class CreateCardPanel(gtk.EventBox): __gsignals__ = { 'add-pair': (SIGNAL_RUN_FIRST, None, 8 * [TYPE_PYOBJECT]), @@ -119,41 +117,45 @@ class CreateCardPanel(gtk.EventBox): def emit_add_pair(self, widget): self._addbutton.set_sensitive(False) if self.equal_pairs: - self.emit('add-pair', self.cardeditor1.get_text(), - self.cardeditor1.get_text(), - self.cardeditor1.get_pixbuf(), - self.cardeditor1.get_pixbuf(), - self.cardeditor1.get_snd(), self.cardeditor1.get_snd(), - self.cardeditor1.get_speak(), self.cardeditor1.get_speak() - ) + self.emit('add-pair', self.cardeditor1.get_text(), + self.cardeditor1.get_text(), + self.cardeditor1.get_pixbuf(), + self.cardeditor1.get_pixbuf(), + 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_speak(), self.cardeditor2.get_speak() - ) + 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_speak(), + self.cardeditor2.get_speak()) self.clean(None) def emit_update_pair(self, widget): self._addbutton.set_sensitive(False) if self.equal_pairs: - self.emit('update-pair', self.cardeditor1.get_text(), - self.cardeditor1.get_text(), - self.cardeditor1.get_pixbuf(), - self.cardeditor1.get_pixbuf(), - self.cardeditor1.get_snd(), self.cardeditor1.get_snd(), - self.cardeditor1.get_speak(), self.cardeditor1.get_speak() - ) + self.emit('update-pair', self.cardeditor1.get_text(), + self.cardeditor1.get_text(), + self.cardeditor1.get_pixbuf(), + self.cardeditor1.get_pixbuf(), + 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_speak(), self.cardeditor2.get_speak() - ) + 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_speak(), + self.cardeditor2.get_speak()) self.clean(None) def pair_selected(self, widget, selected, newtext1, newtext2, aimg, bimg, @@ -215,8 +217,8 @@ class CreateCardPanel(gtk.EventBox): 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._card1_has_sound) and (self._card2_has_text + or self._card2_has_picture or self._card2_has_sound): self._addbutton.set_sensitive(True) self._updatebutton.set_sensitive(self._updatebutton_sensitive) @@ -232,6 +234,11 @@ class CreateCardPanel(gtk.EventBox): self._addbutton.set_sensitive(False) self._updatebutton.set_sensitive(False) + def set_temp_folder(self, temp_folder): + self.cardeditor1.temp_folder = temp_folder + self.cardeditor2.temp_folder = temp_folder + + class CardEditor(gtk.EventBox): __gsignals__ = { @@ -245,8 +252,7 @@ class CardEditor(gtk.EventBox): self.snd = None - tmp_root = join(environ['SUGAR_ACTIVITY_ROOT'], 'instance') - self.temp_folder = tempfile.mkdtemp(dir=tmp_root) + self.temp_folder = None box = gtk.VBox() box.props.spacing = theme.PAD @@ -257,11 +263,11 @@ class CardEditor(gtk.EventBox): box.pack_start(self.previewlabel, False) self.card = svgcard.SvgCard(-1, - { 'front_text' : { 'card_text' : '', - 'text_color' : '#ffffff' }, - 'front_border': { 'fill_color' : '#4c4d4f', - 'stroke_color' : '#ffffff', - 'opacity' : '1' } }, + {'front_text': {'card_text': '', + 'text_color': '#ffffff'}, + 'front_border': {'fill_color': '#4c4d4f', + 'stroke_color': '#ffffff', + 'opacity': '1'}}, None, theme.PAIR_SIZE, 1, '#c0c0c0') self.card.flip() card_align = gtk.Alignment(.5, .5, 0, 0) @@ -300,16 +306,7 @@ class CardEditor(gtk.EventBox): 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) + box.pack_start(toolbar, False) self.add(box) @@ -360,8 +357,8 @@ class CardEditor(gtk.EventBox): 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) + 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) @@ -369,7 +366,7 @@ class CardEditor(gtk.EventBox): pixbuf_t.get_height(), 0, 0, 1, 1, gtk.gdk.INTERP_BILINEAR, 255) self.card.set_pixbuf(pixbuf_z) - _logger.debug('Picture Loaded: '+index) + _logger.debug('Picture Loaded: ' + index) self.emit('has-picture', True) del pixbuf_t del pixbuf_z @@ -384,7 +381,7 @@ class CardEditor(gtk.EventBox): self.set_speak(None) - dst = join(self.temp_folder, basename(index)) + dst = join(self.temp_folder, 'sounds', basename(index)) shutil.copy(index, dst) self.set_snd(dst) icon_theme = gtk.icon_theme_get_default() @@ -392,7 +389,7 @@ class CardEditor(gtk.EventBox): style.XLARGE_ICON_SIZE, 0) self.card.set_pixbuf(pixbuf_t) self.emit('has-sound', True) - _logger.debug('Audio Loaded: '+dst) + _logger.debug('Audio Loaded: ' + dst) chooser.pick(parent=self.get_toplevel(), what=chooser.AUDIO, @@ -429,6 +426,7 @@ class CardEditor(gtk.EventBox): self.usespeak.props.active = False self.usespeak.palette.face.shut_up() + class SpeakPalette(Palette): def __init__(self, editor): Palette.__init__(self, _('Pronounce text during tile flip')) diff --git a/createtoolbar.py b/createtoolbar.py index b5c72fe..9f95553 100644 --- a/createtoolbar.py +++ b/createtoolbar.py @@ -15,154 +15,100 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -import logging from gettext import gettext as _ import gtk -from os.path import join, dirname +import gobject from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT - + from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toggletoolbutton import ToggleToolButton -from sugar.graphics.toolcombobox import ToolComboBox -from sugar.graphics.objectchooser import ObjectChooser +from sugar.graphics.alert import Alert +from sugar.graphics.icon import Icon + + +class CreateToolbarBuilder(gobject.GObject): -class CreateToolbar(gtk.Toolbar): __gtype_name__ = 'CreateToolbar' __gsignals__ = { - 'create_new_game': (SIGNAL_RUN_FIRST, None, []), - 'create_load_game': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), - 'create_save_game': (SIGNAL_RUN_FIRST, None, 3 * [TYPE_PYOBJECT]), - 'create_equal_pairs': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), + 'create_new_game': (SIGNAL_RUN_FIRST, None, []), + 'create_equal_pairs': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), } - + def __init__(self, activity): - gtk.Toolbar.__init__(self) + gobject.GObject.__init__(self) self.activity = activity - self._lock = True - - # New Button - new_icon = join(dirname(__file__), 'images', 'game-new.svg') - new_image = gtk.Image() - new_image.set_from_file(new_icon) - self._new_button = ToolButton() - self._new_button.set_icon_widget(new_image) - self._new_button.set_tooltip(_('New game')) - self._new_button.connect('clicked', self._new_game_bt) - self._add_widget(self._new_button) - - # Load Button - load_icon = join(dirname(__file__), 'images', 'game-load.svg') - load_image = gtk.Image() - load_image.set_from_file(load_icon) - self._load_button = ToolButton() - self._load_button.set_icon_widget(load_image) - self._load_button.set_tooltip(_('Load game')) - self._load_button.connect('clicked', self._load_game) - self._add_widget(self._load_button) - - # Save Button - save_icon = join(dirname(__file__), 'images', 'game-save.svg') - save_image = gtk.Image() - save_image.set_from_file(save_icon) - self._save_button = ToolButton() - self._save_button.set_icon_widget(save_image) - self._save_button.set_tooltip(_('Save game')) - self._save_button.connect('clicked', self._save_game_bt) - self._save_button.set_sensitive(False) - self._add_widget(self._save_button) - - # Separator - separator2 = gtk.SeparatorToolItem() - separator2.set_draw(True) - self.insert(separator2, -1) - - self._add_widget(gtk.Label(_('Game name') + ': ')) - self.game_name_entry = gtk.Entry() - self._add_widget(self.game_name_entry) - - self._equal_pairs = gtk.CheckButton(_('Equal pairs')) - self._add_widget(self._equal_pairs) + self.toolbar = self.activity.get_toolbar_box().toolbar + + self._equal_pairs = ToggleToolButton('pair-non-equals') + self._equal_pairs.set_tooltip(_('Set equal pairs')) self._equal_pairs.connect('toggled', self._emit_equal_pairs) - - self._grouped_icon1 = join(dirname(__file__), 'images', 'equal_pairs1.svg') - self._grouped_icon2 = join(dirname(__file__), 'images', 'equal_pairs2.svg') - self._grouped_image1 = gtk.Image() - self._grouped_image2 = gtk.Image() - self._grouped_image1.set_from_file(self._grouped_icon1) - self._grouped_image2.set_from_file(self._grouped_icon2) - self._grouped = ToggleToolButton() - self._grouped.set_icon_widget(self._grouped_image1) - self._grouped.set_tooltip(_('Click for grouped game')) + self.toolbar.insert(self._equal_pairs, -1) + + self._grouped = ToggleToolButton('grouped_game1') + self._grouped.set_tooltip(_('Set grouped game')) self._grouped.connect('toggled', self._grouped_cb) - self._add_widget(self._grouped) - + self.toolbar.insert(self._grouped, -1) + + self._clear_button = ToolButton('edit-clear') + self._clear_button.set_tooltip(_('Clear current game')) + self._clear_button.connect('clicked', self._clear_game_bt) + self.toolbar.insert(self._clear_button, -1) + + self.toolbar.show_all() + def _add_widget(self, widget, expand=False): tool_item = gtk.ToolItem() tool_item.set_expand(expand) tool_item.add(widget) widget.show() - self.insert(tool_item, -1) + self.toolbar.insert(tool_item, -1) tool_item.show() - - def _game_changed_cb(self, combobox, game_name): - self.game_name_entry.set_text(game_name) - self.emit('create_load_game', game_name) - - def _load_game(self, button): - chooser = ObjectChooser(_('Choose memorize game'), - parent=self.activity, - flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) - jobject = '' - try: - result = chooser.run() - if result == gtk.RESPONSE_ACCEPT: - logging.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.emit('create_load_game', jobject.file_path) - self._save_button.set_sensitive(False) - - def _new_game_bt(self, button): - self.game_name_entry.set_text('') - self._equal_pairs.set_active(False) - self._grouped.set_active(False) - self.emit('create_new_game') - self._new_button.set_sensitive(False) - self._save_button.set_sensitive(False) - - def _save_game_bt(self, button): - self.emit('create_save_game', self.game_name_entry.get_text(), self._equal_pairs.get_active(), self._grouped.get_active()) - self._save_button.set_sensitive(False) - - def _emit_equal_pairs(self, checkbutton): - self.emit('create_equal_pairs', checkbutton.get_active()) - self._save_button.set_sensitive(True) - + + def _clear_game_bt(self, button): + alert = Alert() + alert.props.title = _('Clear all the tiles from the game?') + icon = Icon(icon_name='dialog-ok') + alert.add_button(1, _('Clear'), icon) + icon = Icon(icon_name='dialog-cancel') + alert.add_button(0, _('Do not clear'), icon) + alert.connect('response', self._clear_game_alert_cb) + self.activity.add_alert(alert) + + def _clear_game_alert_cb(self, alert, response_id): + self.activity.remove_alert(alert) + if response_id == 1: + self._equal_pairs.set_active(False) + self._grouped.set_active(False) + self.emit('create_new_game') + + def update_controls(self, active): + self._equal_pairs.set_sensitive(active) + self._grouped.set_sensitive(active) + self._clear_button.set_sensitive(active) + + def _emit_equal_pairs(self, widget): + if self._equal_pairs.get_active(): + self._equal_pairs.set_named_icon('pair-equals') + self._equal_pairs.set_tooltip(_('Set non equal pairs')) + self.activity.game.model.data['equal_pairs'] = '1' + else: + self._equal_pairs.set_named_icon('pair-non-equals') + self._equal_pairs.set_tooltip(_('Set equal pairs')) + self.activity.game.model.data['equal_pairs'] = '0' + self.emit('create_equal_pairs', self._equal_pairs.get_active()) + def _grouped_cb(self, widget): - self._save_button.set_sensitive(True) if self._grouped.get_active(): - self._grouped.set_icon_widget(self._grouped_image2) - self._grouped_image2.show() - self._grouped.set_tooltip(_('Click for ungrouped game')) + self._grouped.set_named_icon('grouped_game2') + self._grouped.set_tooltip(_('Set ungrouped game')) + self.activity.game.model.data['divided'] = '1' else: - self._grouped.set_icon_widget(self._grouped_image1) - self._grouped_image1.show() - self._grouped.set_tooltip(_('Click for grouped game')) - - def update_create_toolbar(self, widget, game_name, equal_pairs, grouped): - self.game_name_entry.set_text(game_name) - self._equal_pairs.set_active(equal_pairs == 'True') + self._grouped.set_named_icon('grouped_game1') + self._grouped.set_tooltip(_('Set grouped game')) + self.activity.game.model.data['divided'] = '0' + + def update_create_toolbar(self, widget, game_name, equal_pairs, grouped): + self._equal_pairs.set_active(equal_pairs == '1') self._grouped.set_active(grouped == '1') - - def update_buttons_status(self, widget, new, save): - self._new_button.set_sensitive(new) - self._save_button.set_sensitive(save) - diff --git a/face.py b/face.py index 64693f6..dd4bf90 100644 --- a/face.py +++ b/face.py @@ -23,6 +23,7 @@ import speak.espeak import speak.face import theme + class Face(gtk.EventBox): def __init__(self): gtk.EventBox.__init__(self) @@ -46,6 +47,7 @@ class Face(gtk.EventBox): pixbuf = card._read_icon_data('front') self.window.draw_pixbuf(None, pixbuf, 0, 0, 0, 0) + def look_at(): if not speak.espeak.supported: return @@ -57,6 +59,7 @@ def look_at(): if i.parent: i.face.look_at(x, y) + def acquire(): if not speak.espeak.supported: return None diff --git a/game.py b/game.py index 4c4b04d..b023e85 100644 --- a/game.py +++ b/game.py @@ -24,7 +24,7 @@ from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT, GObject, timeout_add from gobject import source_remove from model import Model -from audio import Audio +from audio import Audio import theme _logger = logging.getLogger('memorize-activity') @@ -35,7 +35,7 @@ PATH = '/org/laptop/Memorize' class MemorizeGame(GObject): - + __gsignals__ = { 'reset_scoreboard': (SIGNAL_RUN_FIRST, None, []), 'reset_table': (SIGNAL_RUN_FIRST, None, []), @@ -56,7 +56,7 @@ class MemorizeGame(GObject): 'msg_buddy': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]), 'change-turn': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), } - + def __init__(self): gobject.GObject.__init__(self) self.myself = None @@ -77,8 +77,10 @@ class MemorizeGame(GObject): self.audio = Audio() def load_game(self, game_name, size, mode): - self.set_load_mode('Loading game') + self.set_load_mode('Loading game') if self.model.read(game_name) == 0: + logging.debug('load_game set is_demo mode %s', mode) + self.model.is_demo = (mode == 'demo') self.model.def_grid(size) self.model.data['running'] = 'False' self.model.data['mode'] = mode @@ -87,19 +89,16 @@ class MemorizeGame(GObject): self.emit('load_game', self.model.data, self.model.grid) else: logging.error(' Reading setup file %s', game_name) - - def load_remote(self, grid, data, mode, signal = False): + + def load_remote(self, grid, data, mode, signal=False): self.set_load_mode(_('Loading game...')) self.model.grid = grid self.model.data = data self.model.data['mode'] = mode self.emit('reset_scoreboard') if not signal: - self.emit('change_game_signal', - mode, - self.get_grid(), - self.model.data, - self.waiting_players, + self.emit('change_game_signal', mode, self.get_grid(), + self.model.data, self.waiting_players, self.model.data['game_file']) self.emit('change_game', self.model.data, self.get_grid()) for buddy in self.players: @@ -109,28 +108,31 @@ class MemorizeGame(GObject): self.last_highlight = 1 self.change_turn() self.model.data['running'] = 'False' - + for card in self.model.grid: - if card['state'] == '1': + if card['state'] == '1': self.emit('flip-card', self.model.grid.index(card), False) self.last_flipped = self.model.grid.index(card) - elif card['state'] != '0': + elif card['state'] != '0': stroke_color, fill_color = card['state'].split(',') self.emit('flip-card', self.model.grid.index(card), False) self.emit('set-border', self.model.grid.index(card), stroke_color, fill_color) - - def add_buddy(self, buddy, score = 0): + logging.debug('load_remote set is_demo mode %s', mode) + if mode != 'reset': + self.model.is_demo = (mode == 'demo') + + def add_buddy(self, buddy, score=0): _logger.debug('Buddy %r was added to game', buddy.props.nick) self.players.append(buddy) self.players_score[buddy] = score self.emit('add_buddy', buddy, score) logging.debug(str(buddy)) - + if self.current_player == None: self.current_player = buddy self.change_turn() - + def rem_buddy(self, buddy): _logger.debug('Buddy %r was removed from game', buddy.props.nick) if self.current_player == buddy and len(self.players) >= 2: @@ -139,17 +141,17 @@ class MemorizeGame(GObject): self.model.grid[self.last_flipped]['state'] = '0' self.last_flipped = -1 self.change_turn() - index = self.players.index(buddy) + index = self.players.index(buddy) del self.players[index] del (self.players_score[buddy]) self.emit('rem_buddy', buddy) - + def buddy_message(self, buddy, text): self.emit('msg_buddy', buddy, text) def update_turn(self): self.set_sensitive(self.current_player == self.myself) - self.emit('change-turn', self.current_player) + self.emit('change-turn', self.current_player) def change_turn(self): if len(self.players) <= 1: @@ -160,14 +162,15 @@ class MemorizeGame(GObject): self.current_player = self.players[0] else: next_player = self.players.index(self.current_player) + 1 - self.current_player = self.players[next_player] + self.current_player = self.players[next_player] self.update_turn() - def card_overflipped(self, widget, identifier): + def card_overflipped(self, widget, identifier): if self._flop_cards and identifier in self._flop_cards: self.card_flipped(widget, identifier) - def card_flipped(self, widget, identifier, signal = False): + def card_flipped(self, widget, identifier, signal=False): + self.model.count = self.model.count + 1 if self._flop_cards: source_remove(self._flop_card_timeout) self.flop_card(self._flop_cards[0], self._flop_cards[1]) @@ -176,22 +179,22 @@ class MemorizeGame(GObject): if (not self.sentitive and not signal) or \ self.last_flipped == identifier: return - + # Handle groups if needed if self.model.data.get('divided') == '1': if self.last_flipped == -1 and identifier \ - >= (len(self.model.grid)/2): + >= (len(self.model.grid) / 2): return if self.last_flipped != -1 and identifier \ - < (len(self.model.grid)/2): + < (len(self.model.grid) / 2): return - + # do not process flips when flipping back if self.flip_block: return else: self.flip_block = True - + self.model.data['running'] = 'True' def flip_card(full_animation): @@ -203,13 +206,13 @@ class MemorizeGame(GObject): if snd != None: sound_file = join(self.model.data.get('pathsnd'), snd) self.audio.play(sound_file) - + # First card case if self.last_flipped == -1: flip_card(full_animation=True) self.last_flipped = identifier - self.model.grid[identifier]['state'] = '1' + self.model.grid[identifier]['state'] = '1' self.flip_block = False # Second card case @@ -217,22 +220,22 @@ class MemorizeGame(GObject): # Pair matched pair_key_1 = self.model.grid[self.last_flipped]['pairkey'] pair_key_2 = self.model.grid[identifier]['pairkey'] - + if pair_key_1 == pair_key_2: flip_card(full_animation=False) stroke_color, fill_color = \ self.current_player.props.color.split(',') self.emit('set-border', identifier, stroke_color, fill_color) - self.emit('set-border', self.last_flipped, + self.emit('set-border', self.last_flipped, stroke_color, fill_color) - + self.increase_point(self.current_player) self.model.grid[identifier]['state'] = \ self.current_player.props.color self.model.grid[self.last_flipped]['state'] = \ self.current_player.props.color - self.flip_block = False + self.flip_block = False self.emit('cement-card', identifier) self.emit('cement-card', self.last_flipped) @@ -247,7 +250,7 @@ class MemorizeGame(GObject): self._flop_card_timeout = timeout_add(theme.FLOP_BACK_TIMEOUT, self.flop_card, identifier, self.last_flipped) self.last_flipped = -1 - + def flop_card(self, identifier, identifier2): self._flop_card_timeout = -1 self._flop_cards = None @@ -256,7 +259,7 @@ class MemorizeGame(GObject): self.model.grid[identifier]['state'] = '0' self.emit('flop-card', identifier2) self.model.grid[identifier2]['state'] = '0' - + #if self.model.data['divided'] == '1': # self.card_highlighted(widget, -1, False) self.set_sensitive(True) @@ -266,27 +269,26 @@ class MemorizeGame(GObject): def card_highlighted(self, widget, identifier, mouse): self.emit('highlight-card', self.last_highlight, False) self.last_highlight = identifier - + if identifier == -1 or not self.sentitive: return if self.model.data['divided'] == '1': if self.last_flipped == -1 and identifier \ - >= (len(self.model.grid)/2): + >= (len(self.model.grid) / 2): return if self.last_flipped != -1 and identifier \ - < (len(self.model.grid)/2): + < (len(self.model.grid) / 2): return if mouse and self.model.grid[identifier]['state'] == '0' or not mouse: self.emit('highlight-card', identifier, True) - def increase_point(self, buddy, inc=1): self.players_score[buddy] += inc for i_ in range(inc): self.emit('increase-score', buddy) - + def get_grid(self): return self.model.grid @@ -296,35 +298,38 @@ class MemorizeGame(GObject): score = self.players_score[player] self.model.data[str(index)] = str(score) return self.model.data - + def change_game(self, widget, game_name, size, mode, - title = None, color= None): + title=None, color=None): if mode in ['file', 'demo']: + logging.debug('change_game set is_demo mode %s', mode) + self.model.is_demo = (mode == 'demo') if self.model.read(game_name) != 0: logging.error(' Reading setup file %s', game_name) return if size == None: size = int(self.model.data['size']) self.model.def_grid(size) - + if title != None: self.model.data['title'] = title if color != None: self.model.data['color'] = color self.load_remote(self.model.grid, self.model.data, mode, False) - - def reset_game(self, size = None): + + def reset_game(self, size=None): if size == None: size = int(self.model.data['size']) - self.model.def_grid(size) - self.load_remote(self.model.grid, self.model.data, False) - + self.model.count = 0 + self.model.def_grid(size) + self.load_remote(self.model.grid, self.model.data, False) + def set_load_mode(self, msg): - self.emit('load_mode', msg) - + self.emit('load_mode', msg) + def set_messenger(self, messenger): self.messenger = messenger - + def set_sensitive(self, status): self.sentitive = status if not status: @@ -332,10 +337,10 @@ class MemorizeGame(GObject): def get_sensitive(self): return self.sentitive - + def get_current_player(self): return self.current_player - + def get_players_data(self): data = [] for player, score in self.players_score.items(): @@ -364,11 +369,11 @@ class MemorizeGame(GObject): self.waiting_players.remove(buddy) self.players.append(buddy) self.emit('wait_mode_buddy', buddy, False) - + def load_waiting_list(self, wait_list): for buddy in wait_list: self.add_to_waiting_list(buddy) - + def empty_waiting_list(self): for buddy in self.waiting_players: self.rem_to_waiting_list(buddy) diff --git a/memorizetoolbar.py b/memorizetoolbar.py index 782f818..98ddf0f 100644 --- a/memorizetoolbar.py +++ b/memorizetoolbar.py @@ -15,70 +15,46 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -import gtk +import gobject from os.path import join, dirname from gettext import gettext as _ from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toolcombobox import ToolComboBox -from sugar.graphics.objectchooser import ObjectChooser -from sugar import profile +from sugar.graphics.alert import Alert +from sugar.graphics.icon import Icon +from sugar.activity.widgets import RadioMenuButton +from sugar.graphics.menuitem import MenuItem import logging from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT _logger = logging.getLogger('memorize-activity') -class MemorizeToolbar(gtk.Toolbar): - __gtype_name__ = 'MemoryToolbar' - - standard_game_names = ['Load demo games', - 'addition', + +class MemorizeToolbarBuilder(gobject.GObject): + + __gtype_name__ = 'MemoryToolbarBuilder' + + standard_game_names = ['addition', 'letters', 'sounds' ] - translated_game_names = [_('Load demo games'), - _('addition'), - _('letters'), - _('sounds') + translated_game_names = [_('Addition'), + _('Letters'), + _('Sounds') ] __gsignals__ = { 'game_changed': (SIGNAL_RUN_FIRST, None, 5 * [TYPE_PYOBJECT]) } - + def __init__(self, activity): - gtk.Toolbar.__init__(self) + gobject.GObject.__init__(self) self.activity = activity - self._lock = True + self.toolbar = self.activity.get_toolbar_box().toolbar self.jobject = None - - # Reset Button - restart_icon = join(dirname(__file__), 'images', 'game-restart.svg') - restart_image = gtk.Image() - restart_image.set_from_file(restart_icon) - self._restart_button = ToolButton() - self._restart_button.set_icon_widget(restart_image) - self._restart_button.connect('clicked', self._game_reset_cb) - self._restart_button.set_tooltip(_('Restart Game')) - self.insert(self._restart_button, -1) - self._restart_button.show() - - # Load Button - load_icon = join(dirname(__file__), 'images', 'game-load.svg') - load_image = gtk.Image() - load_image.set_from_file(load_icon) - self._load_button = ToolButton() - self._load_button.set_icon_widget(load_image) - self._load_button.set_tooltip(_('Load game')) - self._load_button.connect('clicked', self._load_game) - self._add_widget(self._load_button) - - # Separator - separator = gtk.SeparatorToolItem() - separator.set_draw(True) - self.insert(separator, -1) - + # Change size combobox self._size_combo = ToolComboBox() self._sizes = ['4 X 4', '5 X 5', '6 X 6'] @@ -86,87 +62,78 @@ class MemorizeToolbar(gtk.Toolbar): self._size_combo.combo.append_item(i, f) self.size_handle_id = self._size_combo.combo.connect( \ 'changed', self._game_size_cb) - self._add_widget(self._size_combo) + self.toolbar.insert(self._size_combo, -1) self._size_combo.combo.set_active(0) - - separator = gtk.SeparatorToolItem() - separator.set_draw(True) - self.insert(separator, -1) - self._lock = False - - # Change demo games combobox - self._game_combo = ToolComboBox() - for i, f in enumerate(self.standard_game_names): - f = _(f) - self._game_combo.combo.append_item(i, f) - self._game_combo.combo.set_active(0) - self._game_combo.combo.connect('changed', self._game_changed_cb) - self._add_widget(self._game_combo) - - def _add_widget(self, widget, expand=False): - tool_item = gtk.ToolItem() - tool_item.set_expand(expand) - tool_item.add(widget) - widget.show() - self.insert(tool_item, -1) - tool_item.show() - + + # Change demo games button + self._demo_games = RadioMenuButton(icon_name='memorize-collection') + self._demo_games.props.tooltip = _('Load demo games') + + for i, game in enumerate(self.translated_game_names): + menu_item = MenuItem(game) + menu_item.connect('activate', self.__activate_game_cb, i) + self._demo_games.props.palette.menu.append(menu_item) + menu_item.show() + self.toolbar.insert(self._demo_games, -1) + + # Reset Button + self._restart_button = ToolButton('game-new') + self._restart_button.connect('clicked', self._game_reset_cb) + self._restart_button.set_tooltip(_('Restart Game')) + self._restart_button.set_sensitive(False) + self.toolbar.insert(self._restart_button, -1) + self._restart_button.show() + def _game_reset_cb(self, widget): + self._restart_button.set_sensitive(False) + self.activity.game.model.count = 0 self.emit('game_changed', None, None, 'reset', None, None) - - def _load_game(self, button): - chooser = ObjectChooser(_('Choose memorize game'), - parent=self.activity, - flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) - jobject = '' - try: - result = chooser.run() - if result == gtk.RESPONSE_ACCEPT: - logging.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: - title = jobject.metadata['title'] - if jobject.metadata.has_key('icon-color'): - color = jobject.metadata['icon-color'] - else: - color = profile.get_color().to_string() - self.emit('game_changed', jobject.file_path, 4, - 'file', title, color) - - if self.jobject != None: - self.jobject.destroy() - self.jobject = jobject - + + def update_controls(self, active): + self._size_combo.set_sensitive(active) + self._demo_games.set_sensitive(active) + self._restart_button.set_sensitive(active and + self.activity.game.model.count > 0) + + def card_flipped(self, widget, identifier, signal=False): + self._restart_button.set_sensitive(self.activity.game.model.count > 0) + def _game_size_cb(self, widget): game_size = int(self._sizes[self._size_combo.combo.get_active()][0]) self.emit('game_changed', None, game_size, 'size', None, None) - - def _game_changed_cb(self, combobox): - if combobox.get_active() == 0: - return - current_game = self._game_combo.combo.get_active() - game_name = self.standard_game_names[current_game] - title = game_name + + def __activate_game_cb(self, menu, i): + self._game_selected_index = i + if self.activity.game.model.is_demo: + self._change_game() + else: + alert = Alert() + alert.props.title = _('Discard your modified game?') + icon = Icon(icon_name='dialog-ok') + alert.add_button(1, _('Discard'), icon) + icon = Icon(icon_name='dialog-cancel') + alert.add_button(0, _('Do not discard'), icon) + alert.connect('response', self._change_game_alert_cb) + self.activity.add_alert(alert) + + def _change_game_alert_cb(self, alert, response_id): + if alert is not None: + self.activity.remove_alert(alert) + if response_id == 1: + self._change_game() + + def _change_game(self): + title = self.translated_game_names[self._game_selected_index] game_size = int(self._sizes[self._size_combo.combo.get_active()][0]) - - if game_name in self.translated_game_names: - index = self.translated_game_names.index(game_name) - game_name = self.standard_game_names[index] - - game_file = join(dirname(__file__), 'demos', game_name+'.zip') + + game_name = self.standard_game_names[self._game_selected_index] + + game_file = join(dirname(__file__), 'demos', game_name + '.zip') self.emit('game_changed', game_file, game_size, 'demo', title, None) - self._game_combo.combo.set_active(0) - + def update_toolbar(self, widget, data, grid): size = data.get('size') self._size_combo.combo.handler_block(self.size_handle_id) - size_index = self._sizes.index(size+' X '+size) + size_index = self._sizes.index(size + ' X ' + size) self._size_combo.combo.set_active(int(size_index)) self._size_combo.combo.handler_unblock(self.size_handle_id) diff --git a/messenger.py b/messenger.py index 91b07da..3cbd7e7 100644 --- a/messenger.py +++ b/messenger.py @@ -30,8 +30,9 @@ SERVICE = 'org.laptop.Memorize' IFACE = SERVICE PATH = '/org/laptop/Memorize' + class Messenger(ExportedGObject): - + def __init__(self, tube, is_initiator, get_buddy, game): ExportedGObject.__init__(self, tube, PATH) self._tube = tube @@ -39,7 +40,7 @@ class Messenger(ExportedGObject): self._get_buddy = get_buddy self.game = game self.ordered_bus_names = [] - self.entered = False + self.entered = False self._tube.watch_participants(self.participant_change_cb) self.files = {} @@ -56,20 +57,20 @@ class Messenger(ExportedGObject): else: self._hello_signal() self.entered = True - - # hello methods - + + # hello methods + @signal(IFACE, signature='') def _hello_signal(self): pass - + def _hello_handler(self): - self._tube.add_signal_receiver(self._hello_receiver, - '_hello_signal', - IFACE, - path=PATH, + self._tube.add_signal_receiver(self._hello_receiver, + '_hello_signal', + IFACE, + path=PATH, sender_keyword='sender') - + def _hello_receiver(self, sender=None): self.ordered_bus_names.append(sender) data = self.game.model.data @@ -80,13 +81,10 @@ class Messenger(ExportedGObject): self.file_sender(sender, path, title, color) remote_object = self._tube.get_object(sender, PATH) - remote_object.load_game(self.ordered_bus_names, - self.game.get_grid(), - self.game.collect_data(), - self.game.players.index(self.game.current_player), - #self.game.waiting_players, - path) - + remote_object.load_game(self.ordered_bus_names, + self.game.get_grid(), self.game.collect_data(), + self.game.players.index(self.game.current_player), path) + @method(dbus_interface=IFACE, in_signature='asaa{ss}a{ss}ns', out_signature='', byte_arrays=True) def load_game(self, bus_names, grid, data, current_player, path): @@ -104,28 +102,28 @@ class Messenger(ExportedGObject): self._flip_handler() self._change_game_handler() - + def change_game(self, sender, mode, grid, data, waiting_list, zip): path = self.game.model.data['game_file'] - + if mode == 'file': title = data.get('title', 'Received game') - color = data.get('color', '') - self.file_sender('all', path, title, color) + color = data.get('color', '') + self.file_sender('all', path, title, color) self._change_game_signal(mode, grid, data, path) - + def _change_game_handler(self): - self._tube.add_signal_receiver(self._change_game_receiver, - '_change_game_signal', - IFACE, path=PATH, - sender_keyword='sender', + self._tube.add_signal_receiver(self._change_game_receiver, + '_change_game_signal', + IFACE, path=PATH, + sender_keyword='sender', byte_arrays=True) - + @signal(IFACE, signature='saa{ss}a{ss}s') def _change_game_signal(self, mode, grid, data, path): pass - + def _change_game_receiver(self, mode, grid, data, path, sender=None): # ignore my own signal if sender == self._tube.get_unique_name(): @@ -137,13 +135,13 @@ class Messenger(ExportedGObject): self.game.model.read(game_file) if mode == 'file': self.game.model.read(self.files[path]) - - if self.game.model.data.has_key('path'): + + if 'path' in self.game.model.data: data['path'] = self.game.model.data['path'] data['pathimg'] = self.game.model.data['pathimg'] data['pathsnd'] = self.game.model.data['pathsnd'] self.game.load_remote(grid, data, mode, True) - + # File transfer methods def file_sender(self, target, filename, title, color): @@ -156,20 +154,20 @@ class Messenger(ExportedGObject): self._file_part_signal(target, filename, part + 1, num_parts, bytes, title, color) f.close() - + @signal(dbus_interface=IFACE, signature='ssuuayss') def _file_part_signal(self, target, filename, part, numparts, bytes, title, color): pass - + def _file_part_handler(self): - self._tube.add_signal_receiver(self._file_part_receiver, - '_file_part_signal', - IFACE, - path=PATH, - sender_keyword='sender', + self._tube.add_signal_receiver(self._file_part_receiver, + '_file_part_signal', + IFACE, + path=PATH, + sender_keyword='sender', byte_arrays=True) - + def _file_part_receiver(self, target, filename, part, numparts, bytes, title=None, color=None, sender=None): # ignore my own signal @@ -178,7 +176,7 @@ class Messenger(ExportedGObject): if target != self._tube.get_unique_name() and target != 'all': return - + # first chunk if part == 1: tmp_root = join(environ['SUGAR_ACTIVITY_ROOT'], 'instance') @@ -187,16 +185,16 @@ class Messenger(ExportedGObject): self.temp_file = join(temp_dir, 'game.zip') self.files[filename] = self.temp_file self.f = open(self.temp_file, 'a+b') - + self.f.write(bytes) - + percentage = int(float(part) / float(numparts) * 100.0) self.game.set_load_mode(_('Receiving game') + ': ' + str(percentage) + '% ' + _('done') + '.') # last chunk if part == numparts: - self.f.close() + self.f.close() #file = self.files[filename] # Saves the zip in datastore gameObject = datastore.create() @@ -207,19 +205,17 @@ class Messenger(ExportedGObject): datastore.write(gameObject) #gameObject.destroy() - - # flip card methods - + # flip card methods def flip_sender(self, widget, id): self._flip_signal(id) - + def _flip_handler(self): - self._tube.add_signal_receiver(self._flip_receiver, - '_flip_signal', - IFACE, - path=PATH, + self._tube.add_signal_receiver(self._flip_receiver, + '_flip_signal', + IFACE, + path=PATH, sender_keyword='sender') - + @signal(IFACE, signature='n') def _flip_signal(self, card_number): pass diff --git a/model.py b/model.py index dd4afdb..63992a2 100644 --- a/model.py +++ b/model.py @@ -17,38 +17,37 @@ import libxml2 from os import environ, makedirs, chmod -from os.path import join, basename, isdir, split, normpath +from os.path import join, basename, isdir, split, normpath, exists import logging import random import gobject import zipfile import tempfile -from sugar import profile -from sugar.datastore import datastore from sugar.activity.activity import get_bundle_path, get_activity_root _logger = logging.getLogger('model') + class Pair(gobject.GObject): __gproperties__ = { - 'aimg' : (str, None, None, None, gobject.PARAM_READWRITE), - 'asnd' : (str, None, None, None, gobject.PARAM_READWRITE), + 'aimg': (str, None, None, None, gobject.PARAM_READWRITE), + 'asnd': (str, None, None, None, gobject.PARAM_READWRITE), 'achar': (str, None, None, None, gobject.PARAM_READWRITE), - 'bimg' : (str, None, None, None, gobject.PARAM_READWRITE), - 'bsnd' : (str, None, None, None, gobject.PARAM_READWRITE), + 'bimg': (str, None, None, None, gobject.PARAM_READWRITE), + 'bsnd': (str, None, None, None, gobject.PARAM_READWRITE), 'bchar': (str, None, None, None, gobject.PARAM_READWRITE), 'aspeak': (str, None, None, None, gobject.PARAM_READWRITE), 'bspeak': (str, None, None, None, gobject.PARAM_READWRITE), - 'color' : (gobject.TYPE_INT, 'Base', 'Base', 0, 10, 0, \ + 'color': (gobject.TYPE_INT, 'Base', 'Base', 0, 10, 0, \ gobject.PARAM_READWRITE) } def __init__(self): gobject.GObject.__init__(self) - self._properties = {'aimg':None, 'asnd':None, 'achar':None, 'bimg':None, - 'bsnd':None, 'bchar':None, 'color':100, - 'aspeak':None, 'bspeak':None} + self._properties = {'aimg': None, 'asnd': None, 'achar': None, + 'bimg': None, 'bsnd': None, 'bchar': None, + 'color': 100, 'aspeak': None, 'bspeak': None} def do_get_property(self, pspec): """Retrieve a particular property from our property dictionary @@ -100,6 +99,10 @@ class Model(object): ''' def __init__(self, game_path=None): + tmp_root = join(environ['SUGAR_ACTIVITY_ROOT'], 'instance') + self.temp_folder = tempfile.mkdtemp(dir=tmp_root) + chmod(self.temp_folder, 0777) + self.data = {} if game_path is None: @@ -113,18 +116,25 @@ class Model(object): self.data['face'] = '' self.data['align'] = '1' + self.data['divided'] = '0' + self.data['equal_pairs'] = '0' try: self.dtd = libxml2.parseDTD(None, join(get_bundle_path(), 'memorize.dtd')) except libxml2.parserError, e: - _logger.error('Init: no memorize.dtd found ' +str(e)) + _logger.error('Init: no memorize.dtd found ' + str(e)) self.dtd = None self.ctxt = libxml2.newValidCtxt() self.pairs = {} self.grid = [] + # used to know if the game should be saved and reloaded + self.modified = False + logging.debug('Model init is_demo False') + self.is_demo = False + # used by the leader of the game to keep track of the game state self.players = {} self.player_active = 0 @@ -133,16 +143,20 @@ class Model(object): self.started = 0 self.count = 0 + def mark_modified(self): + logging.debug('Model mark_modified is_demo False') + self.is_demo = False + self.modified = True + def read(self, game_file): - tmp_root = join(environ['SUGAR_ACTIVITY_ROOT'], 'instance') - temp_folder = tempfile.mkdtemp(dir=tmp_root) - chmod(temp_folder, 0777) + self.modified = False + self.count = 0 self.data['key'] = basename(game_file) self.data['game_file'] = game_file - self.data['path'] = temp_folder + self.data['path'] = self.temp_folder self.data['pathimg'] = join(self.data['path'], 'images') self.data['pathsnd'] = join(self.data['path'], 'sounds') - + ''' extracts files in the zip file ''' game_name = basename(game_file)[:-4] zipFile = zipfile.ZipFile(game_file, "r") @@ -155,14 +169,14 @@ class Model(object): file(join(directory, name), 'wb').write(zipFile.read(each)) self.pairs = {} - + ''' reads the configuration from an xml file ''' try: xml_file = join(environ['SUGAR_ACTIVITY_ROOT'], self.data['path'], 'game.xml') doc = libxml2.parseFile(xml_file) if doc.validateDtd(self.ctxt, self.dtd): - + # get the requested nodes xpa = doc.xpathNewContext() res = xpa.xpathEval("//*") @@ -176,7 +190,7 @@ class Model(object): for attribute in attributes: if(attribute.name == 'text'): pass - else: + else: pair.set_property(attribute.name, attribute.content) self.pairs[str(idpair)] = pair @@ -185,19 +199,19 @@ class Model(object): for attribute in attributes: if(attribute.name == 'text'): pass - elif(attribute.name == 'name'): + elif(attribute.name == 'name'): self.data['name'] = attribute.content elif(attribute.name == 'scoresnd'): self.data['scoresnd'] = attribute.content - elif(attribute.name == 'winsnd'): + elif(attribute.name == 'winsnd'): self.data['winsnd'] = attribute.content - elif(attribute.name == 'divided'): + elif(attribute.name == 'divided'): self.data['divided'] = attribute.content - elif(attribute.name == 'face'): + elif(attribute.name == 'face'): self.data['face'] = attribute.content - elif(attribute.name == 'face1'): + elif(attribute.name == 'face1'): self.data['face1'] = attribute.content - elif(attribute.name == 'face2'): + elif(attribute.name == 'face2'): self.data['face2'] = attribute.content elif(attribute.name == 'align'): self.data['align'] = attribute.content @@ -211,43 +225,43 @@ class Model(object): doc.freeDoc() return 0 except libxml2.parserError, e: - _logger.error('Read: Error parsing file ' +str(e)) + _logger.error('Read: Error parsing file ' + str(e)) return 2 - - def write(self, equal_pairs, divided): + + def write(self): ''' writes the configuration to an xml file ''' doc = libxml2.newDoc("1.0") root = doc.newChild(None, "memorize", None) - - if(self.data.get('name', None) != None): + + if(self.data.get('name', None) != None): root.setProp("name", self.data['name']) - - if divided: + + if(self.data.get('divided', None) != None): root.setProp('divided', '1') root.setProp('face1', '1') root.setProp('face2', '2') else: root.setProp('divided', '0') - - if equal_pairs: - root.setProp('equal_pairs', str(equal_pairs)) - - if(self.data.get('scoresnd', None) != None): + + if(self.data.get('equal_pairs', None) != None): + root.setProp('equal_pairs', self.data['equal_pairs']) + + if(self.data.get('scoresnd', None) != None): root.setProp("scoresnd", self.data['scoresnd']) - if(self.data.get('winsnd', None) != None): + if(self.data.get('winsnd', None) != None): root.setProp("winsnd", self.data['winsnd']) - if(self.data.get('divided', None) != None): + if(self.data.get('divided', None) != None): root.setProp("divided", self.data['divided']) - if(self.data.get('face', None) != None): + if(self.data.get('face', None) != None): root.setProp("face", self.data['face']) - if(self.data.get('face1', None) != None): + if(self.data.get('face1', None) != None): root.setProp("face1", self.data['face1']) - if(self.data.get('face2', None) != None): + if(self.data.get('face2', None) != None): root.setProp("face2", self.data['face2']) - if(self.data.get('align', None) != None): + if(self.data.get('align', None) != None): root.setProp("align", self.data['align']) - for key in self.pairs: + for key in self.pairs: elem = root.newChild(None, "pair", None) if self.pairs[key].props.aimg != None: elem.setProp("aimg", self.pairs[key].props.aimg) @@ -275,12 +289,11 @@ class Model(object): return 2 doc.freeDoc() return 0 - def def_grid(self, size): ''' create the grid for the play from the pairs information and shuffles the grid so they always appear in a different - place + place ''' psize = (size * size / 2) _logger.debug('Size requested: %d', psize) @@ -326,8 +339,8 @@ class Model(object): i += 1 else: break - - numpairs = len(self.pairs) + + numpairs = len(self.pairs) if numpairs < psize: _logger.debug('Defgrid: Not enough pairs, requested=%s had=%s' % (psize, numpairs)) @@ -348,16 +361,12 @@ class Model(object): def set_data_grid(self, data, grid): self.data = data self.grid = grid - - def save_byte_array(self, path, title= None, color= None): - if color == None: - color = profile.get_color().to_string() - _logger.debug('Save new game in datastore') - - # Saves the zip in datastore - gameObject = datastore.create() - gameObject.metadata['title'] = title - gameObject.metadata['mime_type'] = 'application/x-memorize-project' - gameObject.metadata['icon-color'] = color - gameObject.file_path = path - datastore.write(gameObject) + + def create_temp_directories(self): + temp_img_folder = join(self.temp_folder, 'images') + temp_snd_folder = join(self.temp_folder, 'sounds') + + if not exists(temp_img_folder): + makedirs(temp_img_folder) + if not exists(temp_snd_folder): + makedirs(temp_snd_folder) diff --git a/playerscoreboard.py b/playerscoreboard.py index 99b11bb..5c8db14 100644 --- a/playerscoreboard.py +++ b/playerscoreboard.py @@ -27,11 +27,12 @@ import theme _logger = logging.getLogger('memorize-activity') -class PlayerScoreboard(gtk.EventBox): - - def __init__(self, nick, fill_color, stroke_color, score = 0): + +class PlayerScoreboard(gtk.EventBox): + + def __init__(self, nick, fill_color, stroke_color, score=0): gtk.EventBox.__init__(self) - + self.default_color = '#4c4d4f' self.selected_color = '#818286' self.current_color = '#4c4d4f' @@ -43,24 +44,24 @@ class PlayerScoreboard(gtk.EventBox): self.stroke_color = stroke_color self.connect('size-allocate', self._allocate_cb) - + # Set table self.table = gtk.Table(2, 2, False) self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.current_color)) - self.table.set_row_spacings(theme.PAD/2) - self.table.set_col_spacings(theme.PAD/2) + self.table.set_row_spacings(theme.PAD / 2) + self.table.set_col_spacings(theme.PAD / 2) self.table.set_border_width(theme.PAD) - + # Score table self.score_table = gtk.Table() - self.score_table.set_row_spacings(theme.PAD/2) - self.score_table.set_col_spacings(theme.PAD/2) + self.score_table.set_row_spacings(theme.PAD / 2) + self.score_table.set_col_spacings(theme.PAD / 2) self.scores = [] self.current_x = 0 self.current_y = 0 - + # Set buddy icon self.xo_buddy = join(dirname(__file__), 'images', 'stock-buddy.svg') self.icon = svglabel.SvgLabel(self.xo_buddy, fill_color, stroke_color, @@ -70,12 +71,12 @@ class PlayerScoreboard(gtk.EventBox): self.waiting_icon = svglabel.SvgLabel(self.xo_buddy, \ self.default_color, '#ffffff', False, self.current_color, theme.BODY_WIDTH, theme.BODY_HEIGHT) - + # Set nick label self.nick = gtk.Label(nick) self.nick.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff')) self.nick.set_alignment(0, 0.5) - + # Set message label self.msg = gtk.Label('Waiting for next game...') self.msg.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff')) @@ -102,7 +103,7 @@ class PlayerScoreboard(gtk.EventBox): if self._score_cols == 0: return - rows = int(math.ceil(float(size/2) / self._score_cols)) + rows = int(math.ceil(float(size / 2) / self._score_cols)) self.score_table.resize(rows, self._score_cols) self.score_table.set_size_request(-1, (theme.SCORE_SIZE + theme.PAD / 2) * (rows) - theme.PAD / 2) @@ -116,19 +117,19 @@ class PlayerScoreboard(gtk.EventBox): else: score_pixbuf_unsel = None score_pixbuf_sel = None - + new_score = Score(self.fill_color, self.stroke_color, score_pixbuf_sel, score_pixbuf_unsel, self.status) self.scores.append(new_score) new_score.show() - self.score_table.attach(new_score, self.current_x , self.current_x + 1, + self.score_table.attach(new_score, self.current_x, self.current_x + 1, self.current_y, self.current_y + 1, gtk.SHRINK, gtk.SHRINK) self.current_x += 1 if self.current_x == self._score_cols: self.current_x = 0 self.current_y += 1 self.queue_draw() - + def set_selected(self, sel): self.status = sel if sel: @@ -150,7 +151,7 @@ class PlayerScoreboard(gtk.EventBox): del self.scores self.scores = [] self.queue_draw() - + def set_wait_mode(self, status): if status: self.table.remove(self.icon) @@ -164,6 +165,6 @@ class PlayerScoreboard(gtk.EventBox): if len(self.scores) == 0: self.table.remove(self.msg) self.queue_draw() - + def set_message(self, msg): self.msg.set_text(msg) diff --git a/score.py b/score.py index 947c1e9..ef84d87 100644 --- a/score.py +++ b/score.py @@ -21,12 +21,13 @@ import os import theme + class Score(svglabel.SvgLabel): - + selected_color = "#818286" default_color = "#4c4d4f" status = False - + def __init__(self, fill_color, stroke_color, pixbuf=None, pixbuf_sel=None, status=False): filename = os.path.join(os.path.dirname(__file__), "images/score.svg") @@ -46,12 +47,12 @@ class Score(svglabel.SvgLabel): self.pixbuf = self.pixbuf_sel else: self.pixbuf = self.pixbuf_un - + svglabel.SvgLabel.__init__(self, filename, fill_color, stroke_color, self.pixbuf, self.default_color, theme.SCORE_SIZE, theme.SCORE_SIZE) self.set_selected(status) - + def set_selected(self, status): self.status = status if status: @@ -62,10 +63,10 @@ class Score(svglabel.SvgLabel): self.pixbuf = self.pixbuf_un self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.default_color)) - self.queue_draw() - + self.queue_draw() + def get_pixbuf_un(self): return self.pixbuf_un - + def get_pixbuf_sel(self): return self.pixbuf_sel diff --git a/scoreboard.py b/scoreboard.py index e11d3dd..4aa6997 100644 --- a/scoreboard.py +++ b/scoreboard.py @@ -21,6 +21,7 @@ from playerscoreboard import PlayerScoreboard _logger = logging.getLogger('memorize-activity') + class Scoreboard(gtk.EventBox): def __init__(self): gtk.EventBox.__init__(self) @@ -28,15 +29,15 @@ class Scoreboard(gtk.EventBox): self.players = {} self.current_buddy = None - self.vbox = gtk.VBox(False) - + self.vbox = gtk.VBox(False) + fill_box = gtk.EventBox() fill_box.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#4c4d4f')) fill_box.show() self.vbox.pack_end(fill_box, True, True) - + scroll = gtk.ScrolledWindow() - scroll.props.shadow_type = gtk.SHADOW_NONE + scroll.props.shadow_type = gtk.SHADOW_NONE scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) scroll.add_with_viewport(self.vbox) scroll.set_border_width(0) @@ -47,41 +48,40 @@ class Scoreboard(gtk.EventBox): def change_game(self, widget, data, grid): for buddy in self.players.keys(): self.players[buddy].change_game(len(grid)) - + def add_buddy(self, widget, buddy, score): ### FIXME: this breaks when the body is empty nick = buddy.props.nick stroke_color, fill_color = buddy.props.color.split(',') player = PlayerScoreboard(nick, fill_color, stroke_color, score) player.show() - self.players[buddy] = player + self.players[buddy] = player self.vbox.pack_start(player, False, False) if score == -1: player.set_wait_mode(True) self.show_all() - + def rem_buddy(self, widget, buddy): - self.vbox.remove(self.players[buddy]) - del self.players[buddy] ### fix for self.players[id] - + self.vbox.remove(self.players[buddy]) + del self.players[buddy] # fix for self.players[id] + def set_selected(self, widget, buddy): if self.current_buddy is not None: old = self.players[self.current_buddy] old.set_selected(False) - self.current_buddy = buddy + self.current_buddy = buddy player = self.players[buddy] player.set_selected(True) - + def set_buddy_message(self, widget, buddy, msg): self.players[buddy].set_message(msg) - + def increase_score(self, widget, buddy): self.players[buddy].increase_score() def reset(self, widget): for buddy in self.players.keys(): self.players[buddy].reset() - + def set_wait_mode(self, widget, buddy, status): self.players[buddy].set_wait_mode(status) - diff --git a/svgcard.py b/svgcard.py index d408ca6..7500f3f 100644 --- a/svgcard.py +++ b/svgcard.py @@ -18,7 +18,6 @@ # from os.path import join, dirname -import gc import rsvg import re import gtk @@ -33,22 +32,27 @@ import speak.voice _logger = logging.getLogger('memorize-activity') + class SvgCard(gtk.EventBox): border_svg = join(dirname(__file__), 'images', 'card.svg') # Default properties default_props = {} - default_props['back'] = {'fill_color':'#b2b3b7', 'stroke_color':'#b2b3b7', - 'opacity':'1'} - default_props['back_h'] = {'fill_color':'#b2b3b7', - 'stroke_color':'#ffffff', 'opacity':'1'} - default_props['back_text'] = {'text_color':'#c7c8cc'} - default_props['front'] = {'fill_color':'#4c4d4f', 'stroke_color':'#ffffff', - 'opacity':'1'} - default_props['front_h'] = {'fill_color':'#555555', - 'stroke_color':'#888888', 'opacity':'1'} - default_props['front_text'] = {'text_color':'#ffffff'} + default_props['back'] = {'fill_color': '#b2b3b7', + 'stroke_color': '#b2b3b7', + 'opacity': '1'} + default_props['back_h'] = {'fill_color': '#b2b3b7', + 'stroke_color': '#ffffff', + 'opacity': '1'} + default_props['back_text'] = {'text_color': '#c7c8cc'} + default_props['front'] = {'fill_color': '#4c4d4f', + 'stroke_color': '#ffffff', + 'opacity': '1'} + default_props['front_h'] = {'fill_color': '#555555', + 'stroke_color': '#888888', + 'opacity': '1'} + default_props['front_text'] = {'text_color': '#ffffff'} cache = {} @@ -118,15 +122,15 @@ class SvgCard(gtk.EventBox): self.create_text_layout(props['card_text']) width, height = layout.get_pixel_size() - y = (self.size - height)/2 + y = (self.size - height) / 2 if self.flipped: - if self.align == '2': # top + if self.align == '2': # top y = 0 - elif self.align == '3': # bottom + elif self.align == '3': # bottom y = self.size - height widget.window.draw_layout(self.gc, layout=layout, - x=(self.size - width)/2, y=y, + x=(self.size - width) / 2, y=y, foreground=gtk.gdk.color_parse(props['text_color'])) return False @@ -135,7 +139,7 @@ class SvgCard(gtk.EventBox): icon_data = self.props[view] key = str(self.size) + icon_data.get('fill_color') + \ icon_data.get('stroke_color') - if self.cache.has_key(key): + if key in self.cache: return self.cache[key] icon_file = open(self.border_svg, 'r') @@ -154,15 +158,15 @@ class SvgCard(gtk.EventBox): data = re.sub('', entity, data) data = re.sub('size_card1', str(self.size), data) - data = re.sub('size_card2', str(self.size-6), data) - data = re.sub('size_card3', str(self.size-17), data) + data = re.sub('size_card2', str(self.size - 6), data) + data = re.sub('size_card3', str(self.size - 17), data) pixbuf = rsvg.Handle(data=data).get_pixbuf() self.cache[key] = pixbuf return pixbuf def set_border(self, stroke_color, fill_color): - self.props['front'].update({'fill_color' : fill_color, - 'stroke_color' : stroke_color}) + self.props['front'].update({'fill_color': fill_color, + 'stroke_color': stroke_color}) self.queue_draw() while gtk.events_pending(): gtk.main_iteration() @@ -186,7 +190,7 @@ class SvgCard(gtk.EventBox): def get_pixbuf(self): return self.jpeg - def set_highlight(self, status, mouse = False): + def set_highlight(self, status, mouse=False): if self.flipped: if mouse: return @@ -236,14 +240,12 @@ class SvgCard(gtk.EventBox): speaking_face.face.say(self.get_text()) self.current_face = 'front' - self.flipped = True + self.flipped = True self.queue_draw() while gtk.events_pending(): gtk.main_iteration() - #gc.collect() - def cement(self): if not self.get_speak(): return @@ -336,6 +338,7 @@ class SvgCard(gtk.EventBox): def get_speak(self): return self.props['front_text'].get('speak') + def PIXELS_PANGO(x): return x * 1000 diff --git a/svglabel.py b/svglabel.py index ef2ab74..9991765 100644 --- a/svglabel.py +++ b/svglabel.py @@ -15,20 +15,20 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -import gtk, pygtk +import gtk import rsvg -import cairo import re + class SvgLabel(gtk.DrawingArea): - + filename = '' fill_color = '' stroke_color = '' background_color = '' - - - def __init__(self, filename, fill_color, stroke_color, pixbuf = False, background_color = '', request_x = 45, request_y = 45): + + def __init__(self, filename, fill_color, stroke_color, pixbuf=False, + background_color='', request_x=45, request_y=45): gtk.DrawingArea.__init__(self) self.set_size_request(request_x, request_y) self.filename = filename @@ -38,15 +38,16 @@ class SvgLabel(gtk.DrawingArea): self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(background_color)) if pixbuf: self.pixbuf = pixbuf - else: - self.pixbuf = self._read_icon_data(self.filename, self.fill_color, self.stroke_color) - + else: + self.pixbuf = self._read_icon_data(self.filename, self.fill_color, + self.stroke_color) + self.connect('expose-event', self._expose_cb) - + def _expose_cb(self, widget, event): widget.window.draw_pixbuf(None, self.pixbuf, 0, 0, 0, 0) return False - + def _read_icon_data(self, filename, fill_color, stroke_color): icon_file = open(filename, 'r') data = icon_file.read() @@ -62,38 +63,41 @@ class SvgLabel(gtk.DrawingArea): self.data_size = len(data) return rsvg.Handle(data=data).get_pixbuf() - + def set_color(self, fill_color, stroke_color): self.fill_color = fill_color self.stroke_color = stroke_color - self.pixmap = self._read_icon_data(self.filename, self.fill_color, self.stroke_color) - self.queue_draw() - + self.pixmap = self._read_icon_data(self.filename, self.fill_color, + self.stroke_color) + self.queue_draw() + def set_fill_color(self, fill_color): self.fill_color = fill_color - self.pixmap = self._read_icon_data(self.filename, self.fill_color, self.stroke_color) - self.queue_draw() - + self.pixmap = self._read_icon_data(self.filename, self.fill_color, + self.stroke_color) + self.queue_draw() + def get_fill_color(self): return self.fill_color - + def set_stroke_color(self, stroke_color): self.stroke_color = stroke_color - self.pixmap = self._read_icon_data(self.filename, self.fill_color, self.stroke_color) - self.queue_draw() - + self.pixmap = self._read_icon_data(self.filename, self.fill_color, + self.stroke_color) + self.queue_draw() + def get_stroke_color(self): return self.stroke_color - + def get_pixbuf(self): return self.pixbuf - + def set_pixbuf(self, pixbuf): self.pixbuf = pixbuf - self.queue_draw() - + self.queue_draw() + def set_background(self, background_color): self.background_color = background_color - self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.background_color)) - self.queue_draw() - + self.modify_bg(gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.background_color)) + self.queue_draw() -- cgit v0.9.1