From 7ed15ed98ee5f2a53a5dac8a75381bac6196c19e Mon Sep 17 00:00:00 2001 From: Gonzalo Odiard Date: Mon, 16 Apr 2012 19:00:09 +0000 Subject: Add combos to enable the user to change the font used in the cards. v2 This work is based in the contributions of Flavio Danesse and Ariel Calzada The fonts are saved in the game file. v2: Solve error in add-pair, and initialization of card font in the CardEditor Signed-of-by: Gonzalo Odiard --- diff --git a/activity.py b/activity.py index 8a472d6..1fdf8ac 100644 --- a/activity.py +++ b/activity.py @@ -116,6 +116,8 @@ class MemorizeActivity(Activity): self.cardlist.add_pair) self.createcardpanel.connect('update-pair', self.cardlist.update_selected) + self.createcardpanel.connect('change-font', + self.cardlist.change_font) self._createToolbarBuilder.connect('create_new_game', self.cardlist.clean_list) self._createToolbarBuilder.connect('create_new_game', @@ -155,6 +157,8 @@ class MemorizeActivity(Activity): self._memorizeToolbarBuilder.update_toolbar) self.game.connect('change_game', self._memorizeToolbarBuilder.update_toolbar) + self.game.connect('change_game', + self.createcardpanel.update_font_combos) self._memorizeToolbarBuilder.connect('game_changed', self.change_game) diff --git a/cardlist.py b/cardlist.py index 66e5f56..6bc781c 100644 --- a/cardlist.py +++ b/cardlist.py @@ -71,6 +71,8 @@ class CardList(gtk.EventBox): self.get_window().freeze_updates() self.model = game.model self.current_game_key = self.model.data['game_file'] + font_name1 = self.model.data['font_name1'] + font_name2 = self.model.data['font_name2'] game_pairs = self.model.pairs game_data = self.model.data self.clean_list(load=True) @@ -104,7 +106,7 @@ class CardList(gtk.EventBox): 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, load=True) + font_name1, font_name2, False, load=True) self.get_window().thaw_updates() self.emit('update-create-toolbar', self.model.data['name'], self.model.data['equal_pairs'], @@ -184,8 +186,9 @@ class CardList(gtk.EventBox): self.model.mark_modified() def add_pair(self, widget, achar, bchar, aimg, bimg, asnd, bsnd, - aspeak, bspeak, show=True, load=False): - pair = CardPair(achar, bchar, aimg, bimg, asnd, bsnd, aspeak, bspeak) + aspeak, bspeak, font_name1, font_name2, show=True, load=False): + pair = CardPair(achar, bchar, aimg, bimg, asnd, bsnd, aspeak, bspeak, + font_name1, font_name2) self.vbox.pack_end(pair, False, True) self.pairs.append(pair) pair.connect('pair-selected', self.set_selected) @@ -196,6 +199,15 @@ class CardList(gtk.EventBox): if show: self.show_all() + def change_font(self, widget, group, font_name): + for pair in self.pairs: + pair.change_font(group, font_name) + if group == 1: + self.model.data['font_name1'] = font_name + if group == 2: + self.model.data['font_name2'] = font_name + self.model.mark_modified() + def rem_pair(self, widget, event): self.vbox.remove(widget) self.pairs.remove(widget) @@ -238,7 +250,8 @@ class CardPair(gtk.EventBox): } def __init__(self, text1, text2=None, aimg=None, bimg=None, - asnd=None, bsnd=None, aspeak=None, bspeak=None): + asnd=None, bsnd=None, aspeak=None, bspeak=None, + font_name1=None, font_name2=None): gtk.EventBox.__init__(self) self.bg_color = '#000000' @@ -258,7 +271,7 @@ class CardPair(gtk.EventBox): 'front': {'fill_color': '#4c4d4f', 'stroke_color': '#ffffff', 'opacity': '1'}}, - None, theme.PAIR_SIZE, 1, self.bg_color) + None, theme.PAIR_SIZE, 1, self.bg_color, font_name1) self.bcard1.flip() self.bcard1.set_pixbuf(aimg) align = gtk.Alignment(.5, .5, 0, 0) @@ -272,7 +285,7 @@ class CardPair(gtk.EventBox): 'front': {'fill_color': '#4c4d4f', 'stroke_color': '#ffffff', 'opacity': '1'}}, - None, theme.PAIR_SIZE, 1, self.bg_color) + None, theme.PAIR_SIZE, 1, self.bg_color, font_name2) self.bcard2.flip() self.bcard2.set_pixbuf(bimg) align = gtk.Alignment(.5, .5, 0, 0) @@ -326,6 +339,12 @@ class CardPair(gtk.EventBox): self.asnd = asnd self.bsnd = bsnd + def change_font(self, card, font_name): + if card == 1: + self.bcard1.change_font(font_name) + else: + self.bcard2.change_font(font_name) + def get_text(self, card): if card == 1: return self.bcard1.get_text() diff --git a/cardtable.py b/cardtable.py index b9ab29f..97428cc 100644 --- a/cardtable.py +++ b/cardtable.py @@ -88,7 +88,8 @@ class CardTable(gtk.EventBox): def load_game(self, widget, data, grid): self.data = data self.cards_data = grid - + font_name1 = data['font_name1'] + font_name2 = data['font_name2'] if self._workspace_size == 0: # widow is not allocated, thus postpone loading return @@ -129,12 +130,14 @@ class CardTable(gtk.EventBox): if card['ab'] == 'a': props['back_text'] = {'card_text': text1} + font_name = font_name1 elif card['ab'] == 'b': props['back_text'] = {'card_text': text2} + font_name = font_name2 align = self.data.get('align', '1') card = svgcard.SvgCard(identifier, props, jpg, - self.card_size, align) + self.card_size, align, '#000000', font_name) card.connect('enter-notify-event', self.mouse_event, [x, y]) card.connect('button-press-event', self.flip_card_mouse, identifier) diff --git a/createcardpanel.py b/createcardpanel.py index e654b1c..1da561f 100644 --- a/createcardpanel.py +++ b/createcardpanel.py @@ -31,6 +31,7 @@ from sugar.graphics.icon import Icon from sugar.graphics.palette import Palette from sugar.graphics.toggletoolbutton import ToggleToolButton from sugar.graphics.toolcombobox import ToolComboBox +from fontcombobox import FontComboBox from port import chooser import theme @@ -38,14 +39,16 @@ import speak.espeak import speak.widgets import speak.face from port.roundbox import RoundBox +import model _logger = logging.getLogger('memorize-activity') class CreateCardPanel(gtk.EventBox): __gsignals__ = { - 'add-pair': (SIGNAL_RUN_FIRST, None, 8 * [TYPE_PYOBJECT]), + 'add-pair': (SIGNAL_RUN_FIRST, None, 10 * [TYPE_PYOBJECT]), 'update-pair': (SIGNAL_RUN_FIRST, None, 8 * [TYPE_PYOBJECT]), + 'change-font': (SIGNAL_RUN_FIRST, None, 2 * [TYPE_PYOBJECT]), } def __init__(self): @@ -92,8 +95,8 @@ class CreateCardPanel(gtk.EventBox): # Set card editors - self.cardeditor1 = CardEditor() - self.cardeditor2 = CardEditor() + self.cardeditor1 = CardEditor(1) + self.cardeditor2 = CardEditor(2) self.clean(None) self.cardeditor1.connect('has-text', self.receive_text_signals) self.cardeditor2.connect('has-text', self.receive_text_signals) @@ -101,6 +104,8 @@ class CreateCardPanel(gtk.EventBox): self.cardeditor2.connect('has-picture', self.receive_picture_signals) self.cardeditor1.connect('has-sound', self.receive_sound_signals) self.cardeditor2.connect('has-sound', self.receive_sound_signals) + self.cardeditor1.connect('change-font', self.receive_font_signals) + self.cardeditor2.connect('change-font', self.receive_font_signals) # edit panel @@ -115,6 +120,15 @@ class CreateCardPanel(gtk.EventBox): self.show_all() + def update_font_combos(self, widget, data, grid): + logging.error('update font %s', data) + if 'font_name1' in data: + self.cardeditor1.set_font_name(data['font_name1']) + self.cardeditor1.card.change_font(data['font_name1']) + if 'font_name2' in data: + self.cardeditor2.set_font_name(data['font_name2']) + self.cardeditor2.card.change_font(data['font_name2']) + def emit_add_pair(self, widget): self._addbutton.set_sensitive(False) if self.equal_pairs: @@ -125,7 +139,9 @@ class CreateCardPanel(gtk.EventBox): self.cardeditor1.get_snd(), self.cardeditor1.get_snd(), self.cardeditor1.get_speak(), - self.cardeditor1.get_speak()) + self.cardeditor1.get_speak(), + self.cardeditor1.get_font_name(), + self.cardeditor1.get_font_name()) else: self.emit('add-pair', self.cardeditor1.get_text(), self.cardeditor2.get_text(), @@ -134,7 +150,9 @@ class CreateCardPanel(gtk.EventBox): self.cardeditor1.get_snd(), self.cardeditor2.get_snd(), self.cardeditor1.get_speak(), - self.cardeditor2.get_speak()) + self.cardeditor2.get_speak(), + self.cardeditor1.get_font_name(), + self.cardeditor2.get_font_name()) self.clean(None) def emit_update_pair(self, widget): @@ -215,6 +233,16 @@ class CreateCardPanel(gtk.EventBox): self._card2_has_sound = has_sound self._update_buttom_status() + def receive_font_signals(self, widget, font_name): + if self.equal_pairs: + self.emit('change-font', 1, font_name) + self.emit('change-font', 2, font_name) + else: + if widget == self.cardeditor1: + self.emit('change-font', 1, font_name) + if widget == self.cardeditor2: + self.emit('change-font', 2, font_name) + def _update_buttom_status(self): if not self.equal_pairs: if (self._card1_has_text or self._card1_has_picture \ @@ -246,13 +274,14 @@ class CardEditor(gtk.EventBox): 'has-text': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), 'has-picture': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), 'has-sound': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), + 'change-font': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]), } - def __init__(self): + def __init__(self, editor_index): gtk.EventBox.__init__(self) self.snd = None - + self.editor_index = editor_index self.temp_folder = None box = gtk.VBox() @@ -307,10 +336,27 @@ class CardEditor(gtk.EventBox): else: self.usespeak = None - box.pack_start(toolbar, False) + self.font_combo = FontComboBox() + self.id_font_changed = self.font_combo.connect("changed", + self.__font_changed_cb) + self.font_combo.set_font_name(model.DEFAULT_FONT) + + box.pack_start(self.font_combo, True, True, 0) self.add(box) + def __font_changed_cb(self, widget): + font = widget.get_font_name() + logging.error('Selected font %s', font) + if font: + self.card.change_font(font) + self.emit('change-font', font) + + def set_font_name(self, font_name): + self.font_combo.handler_block(self.id_font_changed) + self.font_combo.set_font_name(font_name) + self.font_combo.handler_unblock(self.id_font_changed) + def update_text(self, entry): self.card.change_text(entry.get_text()) if len(entry.get_text()) == 0: @@ -416,6 +462,9 @@ class CardEditor(gtk.EventBox): def get_snd(self): return self.snd + def get_font_name(self): + return self.font_combo.get_font_name() + def clean(self): self.textentry.set_text('') self.card.set_pixbuf(None) @@ -423,7 +472,7 @@ class CardEditor(gtk.EventBox): self.emit('has-text', False) self.emit('has-picture', False) self.emit('has-sound', False) - if self.usespeak is not None: + if self.usespeak is not None and self.usespeak.palette is not None: self.usespeak.props.active = False self.usespeak.palette.face.shut_up() diff --git a/fontcombobox.py b/fontcombobox.py new file mode 100644 index 0000000..58f9140 --- /dev/null +++ b/fontcombobox.py @@ -0,0 +1,65 @@ +# Copyright (C) 2012 Gonzalo Odiard +# Based in code form Flavio Danesse +# and Ariel Calzada +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import gtk + +FONT_BLACKLIST = ['cmex10', 'cmmi10', 'cmr10', 'cmsy10', 'esint10', 'eufm10', + 'msam10', 'msbm10', 'rsfs10', 'wasy10'] + + +class FontComboBox(gtk.ComboBox): + + def __init__(self): + gtk.ComboBox.__init__(self) + font_renderer = gtk.CellRendererText() + self.pack_start(font_renderer) + self.add_attribute(font_renderer, 'text', 0) + self.add_attribute(font_renderer, 'font', 0) + font_model = gtk.ListStore(str) + + context = self.get_pango_context() + font_index = 0 + self.faces = {} + + for family in context.list_families(): + name = family.get_name() + if name not in FONT_BLACKLIST: + font_model.append([name]) + font_faces = [] + for face in family.list_faces(): + face_name = face.get_face_name() + font_faces.append(face_name) + self.faces[name] = font_faces + + sorter = gtk.TreeModelSort(font_model) + sorter.set_sort_column_id(0, gtk.SORT_ASCENDING) + self.set_model(sorter) + self.show() + + def set_font_name(self, font_name): + count = 0 + tree_iter = self.get_model().get_iter_first() + while tree_iter is not None: + value = self.get_model().get_value(tree_iter, 0) + if value == font_name: + self.set_active(count) + count = count + 1 + tree_iter = self.get_model().iter_next(tree_iter) + + def get_font_name(self): + tree_iter = self.get_active_iter() + return self.get_model().get_value(tree_iter, 0) diff --git a/memorize.dtd b/memorize.dtd index 3c1fc15..d361d47 100644 --- a/memorize.dtd +++ b/memorize.dtd @@ -10,7 +10,9 @@ face1 CDATA #IMPLIED face2 CDATA #IMPLIED align CDATA #IMPLIED - equal_pairs CDATA #IMPLIED + equal_pairs CDATA #IMPLIED + font_name1 CDATA #IMPLIED + font_name2 CDATA #IMPLIED > diff --git a/model.py b/model.py index cc0e608..2567ed2 100644 --- a/model.py +++ b/model.py @@ -28,6 +28,8 @@ from sugar.activity.activity import get_bundle_path, get_activity_root _logger = logging.getLogger('model') +DEFAULT_FONT = 'Sans' + class Pair(gobject.GObject): __gproperties__ = { @@ -118,6 +120,8 @@ class Model(object): self.data['align'] = '1' self.data['divided'] = '0' self.data['equal_pairs'] = '0' + self.data['font_name1'] = DEFAULT_FONT + self.data['font_name2'] = DEFAULT_FONT try: self.dtd = libxml2.parseDTD(None, join(get_bundle_path(), @@ -218,6 +222,10 @@ class Model(object): self.data['align'] = attribute.content elif(attribute.name == 'equal_pairs'): self.data['equal_pairs'] = attribute.content + elif(attribute.name == 'font_name1'): + self.data['font_name1'] = attribute.content + elif(attribute.name == 'font_name2'): + self.data['font_name2'] = attribute.content xpa.xpathFreeContext() else: _logger.error('Read: Error in validation of the file') @@ -246,7 +254,10 @@ class Model(object): if(self.data.get('equal_pairs', None) != None): root.setProp('equal_pairs', self.data['equal_pairs']) - + if(self.data.get('font_name1', None) != None): + root.setProp('font_name1', self.data['font_name1']) + if(self.data.get('font_name2', None) != None): + root.setProp('font_name2', self.data['font_name2']) if(self.data.get('scoresnd', None) != None): root.setProp("scoresnd", self.data['scoresnd']) if(self.data.get('winsnd', None) != None): diff --git a/svgcard.py b/svgcard.py index 7500f3f..631640e 100644 --- a/svgcard.py +++ b/svgcard.py @@ -29,6 +29,7 @@ from sugar.util import LRU import theme import face import speak.voice +import model _logger = logging.getLogger('memorize-activity') @@ -57,7 +58,7 @@ class SvgCard(gtk.EventBox): cache = {} def __init__(self, identifier, pprops, jpeg, size, - align, bg_color='#000000'): + align, bg_color='#000000', font_name=model.DEFAULT_FONT): gtk.EventBox.__init__(self) self.bg_color = bg_color @@ -70,6 +71,7 @@ class SvgCard(gtk.EventBox): self.size = size self.align = align self.text_layouts = [None, None] + self.font_name = font_name self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bg_color)) self.set_size_request(size, size) @@ -300,7 +302,7 @@ class SvgCard(gtk.EventBox): layout = self.create_pango_layout(text) layout.set_width(PIXELS_PANGO(card_size)) layout.set_wrap(pango.WRAP_WORD) - desc = pango.FontDescription('Deja Vu Sans bold ' + str(size)) + desc = pango.FontDescription(self.font_name + " " + str(size)) layout.set_font_description(desc) if layout.get_line_count() <= max_lines_count and \ @@ -317,6 +319,17 @@ class SvgCard(gtk.EventBox): return layout + def change_font(self, font_name): + # remove from local cache + self.text_layouts[self.flipped] = False + text = self.props['front_text']['card_text'] + key = (self.size, text) + if key in _text_layout_cache: + del _text_layout_cache[key] + + self.font_name = font_name + self.queue_draw() + def set_background(self, color): self.bg_color = color self.draw.modify_bg(gtk.STATE_NORMAL, -- cgit v0.9.1