From 2244bb4d29527fd6937373f4f040301b6b423469 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Fri, 27 Apr 2012 23:10:00 +0000 Subject: refactoring to address OOM issues --- diff --git a/AbacusActivity.py b/AbacusActivity.py index 068f6ec..bc3beb6 100644 --- a/AbacusActivity.py +++ b/AbacusActivity.py @@ -13,35 +13,48 @@ from gi.repository import Gtk from gi.repository import Gdk +from gi.repository import GObject +from gi.repository import Pango from sugar3.activity import activity from sugar3 import profile -try: # 0.86+ toolbar widgets - from sugar3.graphics.toolbarbox import ToolbarBox - HAS_TOOLBARBOX = True -except ImportError: - HAS_TOOLBARBOX = False -if HAS_TOOLBARBOX: - from sugar3.activity.widgets import ActivityToolbarButton - from sugar3.activity.widgets import StopButton - from sugar3.graphics.toolbarbox import ToolbarButton +from sugar3.graphics.toolbarbox import ToolbarBox +from sugar3.activity.widgets import ActivityToolbarButton +from sugar3.activity.widgets import StopButton +from sugar3.graphics.toolbarbox import ToolbarButton +from sugar3.graphics.alert import NotifyAlert from gettext import gettext as _ import logging _logger = logging.getLogger('abacus-activity') -from abacus_window import Abacus +from abacus_window import Abacus, Custom from toolbar_utils import separator_factory, radio_factory, label_factory, \ button_factory, spin_factory +NAMES = {'suanpan': _('Suanpan'), + 'soroban': _('Soroban'), + 'decimal': _('Decimal'), + 'nepohualtzintzin': _('Nepohualtzintzin'), + 'hexadecimal': _('Hexadecimal'), + 'binary': _('Binary'), + 'schety': _('Schety'), + 'fraction': _('Fraction'), + 'caacupe': _('Caacupé'), + 'cuisenaire': _('Rods'), + 'custom': _('Custom') + } + + class AbacusActivity(activity.Activity): def __init__(self, handle): ''' Initiate activity. ''' super(AbacusActivity, self).__init__(handle) + self._setting_up = True self.bead_colors = profile.get_color().to_string().split(',') # no sharing @@ -51,128 +64,116 @@ class AbacusActivity(activity.Activity): custom_toolbar = Gtk.Toolbar() edit_toolbar = Gtk.Toolbar() - if HAS_TOOLBARBOX: - # Use 0.86 toolbar design - toolbox = ToolbarBox() - - activity_button = ActivityToolbarButton(self) - toolbox.toolbar.insert(activity_button, 0) - activity_button.show() - - edit_toolbar_button = ToolbarButton(label=_('Edit'), - page=edit_toolbar, - icon_name='toolbar-edit') - edit_toolbar_button.show() - toolbox.toolbar.insert(edit_toolbar_button, -1) - edit_toolbar_button.show() - - abacus_toolbar_button = ToolbarButton( - page=abacus_toolbar, - icon_name='abacus-list') - abacus_toolbar.show() - toolbox.toolbar.insert(abacus_toolbar_button, -1) - abacus_toolbar_button.show() + toolbox = ToolbarBox() - custom_toolbar_button = ToolbarButton( - page=custom_toolbar, - icon_name='view-source') - custom_toolbar.show() - toolbox.toolbar.insert(custom_toolbar_button, -1) - custom_toolbar_button.show() + activity_button = ActivityToolbarButton(self) + toolbox.toolbar.insert(activity_button, 0) + activity_button.show() - separator_factory(toolbox.toolbar, False, True) + edit_toolbar_button = ToolbarButton(label=_('Edit'), + page=edit_toolbar, + icon_name='toolbar-edit') + edit_toolbar_button.show() + toolbox.toolbar.insert(edit_toolbar_button, -1) + edit_toolbar_button.show() - button_factory('edit-delete', toolbox.toolbar, - self._reset_cb, tooltip=_('Reset')) + abacus_toolbar_button = ToolbarButton( + page=abacus_toolbar, + icon_name='abacus-list') + abacus_toolbar.show() + toolbox.toolbar.insert(abacus_toolbar_button, -1) + abacus_toolbar_button.show() - separator_factory(toolbox.toolbar, True, False) + custom_toolbar_button = ToolbarButton( + page=custom_toolbar, + icon_name='view-source') + custom_toolbar.show() + toolbox.toolbar.insert(custom_toolbar_button, -1) + custom_toolbar_button.show() - stop_button = StopButton(self) - stop_button.props.accelerator = _('Q') - toolbox.toolbar.insert(stop_button, -1) - stop_button.show() + separator_factory(toolbox.toolbar, False, True) - self.set_toolbar_box(toolbox) - toolbox.show() + button_factory('edit-delete', toolbox.toolbar, + self._reset_cb, tooltip=_('Reset')) - else: - # Use pre-0.86 toolbar design - toolbox = activity.ActivityToolbox(self) - self.set_toolbox(toolbox) - - toolbox.add_toolbar(_('Project'), abacus_toolbar) - toolbox.add_toolbar(_('Custom'), custom_toolbar) - toolbox.add_toolbar(_('Edit'), edit_toolbar) + separator_factory(toolbox.toolbar, False, True) - button_factory('edit-delete', edit_toolbar, - self._reset_cb, tooltip=_('Reset')) + self._label = label_factory(NAMES['suanpan'], toolbox.toolbar) + ''' + # FIXME: Temporary fix to style problem + attr = Pango.AttrList() + # fg_color = Pango.AttrForeground(65535, 65535, 65535, 0, -1) + fg_color = Pango.pango_attr_foreground_new(65535, 65535, 65535) + attr.insert(fg_color) + self._label.set_attributes(attr) + ''' - separator_factory(edit_toolbar, False, True) + separator_factory(toolbox.toolbar, True, False) - toolbox.set_current_toolbar(1) + stop_button = StopButton(self) + stop_button.props.accelerator = _('Q') + toolbox.toolbar.insert(stop_button, -1) + stop_button.show() - # no sharing - if hasattr(toolbox, 'share'): - toolbox.share.hide() - elif hasattr(toolbox, 'props'): - toolbox.props.visible = False + self.set_toolbar_box(toolbox) + toolbox.show() # TRANS: simple decimal abacus self.decimal = radio_factory('decimal', abacus_toolbar, self._radio_cb, cb_arg='decimal', - tooltip=_('Decimal'), + tooltip=NAMES['decimal'], group=None) # TRANS: http://en.wikipedia.org/wiki/Soroban (Japanese abacus) self.japanese = radio_factory('soroban', abacus_toolbar, - self._radio_cb, cb_arg='japanese', + self._radio_cb, cb_arg='soroban', tooltip=_('Soroban'), group=self.decimal) # TRANS: http://en.wikipedia.org/wiki/Suanpan (Chinese abacus) self.chinese = radio_factory('suanpan', abacus_toolbar, - self._radio_cb, cb_arg='chinese', - tooltip=_('Suanpan'), + self._radio_cb, cb_arg='suanpan', + tooltip=NAMES['suanpan'], group=self.decimal) separator_factory(abacus_toolbar) # TRANS: http://en.wikipedia.org/wiki/Abacus#Native_American_abaci self.mayan = radio_factory('nepohualtzintzin', abacus_toolbar, - self._radio_cb, cb_arg='mayan', - tooltip=_('Nepohualtzintzin'), + self._radio_cb, cb_arg='nepohualtzintzin', + tooltip=NAMES['nepohualtzintzin'], group=self.decimal) # TRANS: hexidecimal abacus self.hex = radio_factory('hexadecimal', abacus_toolbar, - self._radio_cb, cb_arg='hex', - tooltip=_('Hexadecimal'), + self._radio_cb, cb_arg='hexadecimal', + tooltip=NAMES['hexadecimal'], group=self.decimal) # TRANS: binary abacus self.binary = radio_factory('binary', abacus_toolbar, self._radio_cb, cb_arg='binary', - tooltip=_('Binary'), + tooltip=NAMES['binary'], group=self.decimal) separator_factory(abacus_toolbar) # TRANS: http://en.wikipedia.org/wiki/Abacus#Russian_abacus self.russian = radio_factory('schety', abacus_toolbar, - self._radio_cb, cb_arg='russian', - tooltip=_('Schety'), + self._radio_cb, cb_arg='schety', + tooltip=NAMES['schety'], group=self.decimal) # TRANS: abacus for adding fractions self.fraction = radio_factory('fraction', abacus_toolbar, self._radio_cb, cb_arg='fraction', - tooltip=_('Fraction'), + tooltip=NAMES['fraction'], group=self.decimal) # TRANS: Abacus invented by teachers in Caacupé, Paraguay self.caacupe = radio_factory('caacupe', abacus_toolbar, self._radio_cb, cb_arg='caacupe', - tooltip=_('Caacupé'), + tooltip=NAMES['caacupe'], group=self.decimal) separator_factory(abacus_toolbar) @@ -181,14 +182,15 @@ class AbacusActivity(activity.Activity): self.cuisenaire = radio_factory('cuisenaire', abacus_toolbar, self._radio_cb, cb_arg='cuisenaire', - tooltip=_('Rods'), group=self.decimal) + tooltip=NAMES['cuisenaire'], + group=self.decimal) separator_factory(abacus_toolbar) self.custom = radio_factory('custom', abacus_toolbar, self._radio_cb, cb_arg='custom', - tooltip=_('Custom'), group=self.decimal) + tooltip=NAMES['custom'], group=self.decimal) # TRANS: Number of rods on the abacus self._rods_label = label_factory(_('Rods:') + ' ', custom_toolbar) @@ -223,11 +225,8 @@ class AbacusActivity(activity.Activity): button_factory('edit-paste', edit_toolbar, self._paste_cb, tooltip=_('Paste'), accelerator='v') - if HAS_TOOLBARBOX: - # start with abacus toolbar expanded - abacus_toolbar_button.set_expanded(True) - else: - self.toolbox.show() + # start with abacus toolbar expanded + abacus_toolbar_button.set_expanded(True) self.chinese.set_active(True) @@ -242,6 +241,8 @@ class AbacusActivity(activity.Activity): # Initialize the canvas self.abacus = Abacus(canvas, self) + self._setting_up = False + # Read the current mode from the Journal if 'rods' in self.metadata: self._rods_spin.set_value(int(self.metadata['rods'])) @@ -257,19 +258,19 @@ class AbacusActivity(activity.Activity): # Default is Chinese _logger.debug('restoring %s', self.metadata['abacus']) if self.metadata['abacus'] == 'soroban': - self._select_abacus('japanese') + self._select_abacus('soroban') self.japanese.set_active(True) elif self.metadata['abacus'] == 'schety': - self._select_abacus('russian') + self._select_abacus('schety') self.russian.set_active(True) elif self.metadata['abacus'] == 'nepohualtzintzin': - self._select_abacus('mayan') + self._select_abacus('nepohualtzintzin') self.mayan.set_active(True) elif self.metadata['abacus'] == 'binary': self._select_abacus('binary') self.binary.set_active(True) elif self.metadata['abacus'] == 'hexadecimal': - self._select_abacus('hex') + self._select_abacus('hexadecimal') self.hex.set_active(True) elif self.metadata['abacus'] == 'fraction': self._select_abacus('fraction') @@ -298,13 +299,45 @@ class AbacusActivity(activity.Activity): self.abacus.mode.reset_abacus() self.abacus.mode.label(self.abacus.generate_label()) + def _notify_new_abacus(self, prompt): + ''' Loading a new abacus can be slooow, so alert the user. ''' + alert = NotifyAlert(3) + alert.props.title = prompt + alert.props.msg = _('A new abacus is loading.') + + # FIXME: set color of text for alert due to style bug + def _notification_alert_response_cb(alert, response_id, self): + self.remove_alert(alert) + + alert.connect('response', _notification_alert_response_cb, self) + self.add_alert(alert) + alert.show() + def _select_abacus(self, abacus): ''' Display the selected abacus; hide the others ''' if not hasattr(self, 'abacus'): return - if abacus == 'custom' and self.abacus.custom is None: + if self._setting_up: + return + if self.abacus.mode.name == abacus: + return + + self._notify_new_abacus(NAMES[abacus]) + # Give the alert time to load + GObject.timeout_add(1000, self._switch_modes, abacus) + + def _switch_modes(self, abacus): + # Save current value + value = int(float(self.abacus.mode.value())) + if abacus == 'custom': self._custom_cb() - self.abacus.select_abacus(abacus) + self.abacus.mode = self.abacus.custom + else: + self.abacus.select_abacus(abacus) + # Load saved value + self.abacus.mode.set_value_from_number(value) + self.abacus.mode.label(self.abacus.generate_label()) + self._label.set_text(NAMES[abacus]) def _rods_spin_cb(self, button=None): return @@ -321,20 +354,26 @@ class AbacusActivity(activity.Activity): def _base_spin_cb(self, button=None): return + def _custom_cb(self, button=None): ''' Display the custom abacus; hide the others ''' value = float(self.abacus.mode.value(count_beads=False)) + self.abacus.mode.hide() if self.abacus.custom is not None: self.abacus.custom.hide() - self.abacus.custom = Custom(self.abacus, - self._rods_spin.get_value_as_int(), - self._top_spin.get_value_as_int(), - self._bottom_spin.get_value_as_int(), - self._value_spin.get_value_as_int(), - self._base_spin.get_value_as_int(), - self.bead_colors) + self.abacus.custom = Custom(self.abacus, self.abacus.bead_colors) + self.abacus.custom.set_custom_parameters( + rods=self._rods_spin.get_value_as_int(), + top=self._top_spin.get_value_as_int(), + bot=self._bottom_spin.get_value_as_int(), + factor=self._value_spin.get_value_as_int(), + base=self._base_spin.get_value_as_int()) + self.abacus.custom.create() + self.abacus.custom.draw_rods_and_beads() + self.abacus.custom.show() + self.abacus.mode = self.abacus.custom self.custom.set_active(True) - self.abacus.select_abacus('custom') + self._label.set_text(NAMES['custom']) def _copy_cb(self, arg=None): ''' Copy a number to the clipboard from the active abacus. ''' diff --git a/abacus_window.py b/abacus_window.py index 83887b3..028b80f 100644 --- a/abacus_window.py +++ b/abacus_window.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -#Copyright (c) 2010,11 Walter Bender +#Copyright (c) 2010-12, Walter Bender #Copyright (c) 2010, Tuukka Hastrup # # This program is free software; you can redistribute it and/or modify @@ -12,6 +12,29 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. +import gi +from gi.repository import Gtk, Gdk, GdkPixbuf +from math import floor, ceil + +import locale + +import traceback +import logging +_logger = logging.getLogger('abacus-activity') + +try: + from sugar3.graphics import style + GRID_CELL_SIZE = style.GRID_CELL_SIZE +except ImportError: + GRID_CELL_SIZE = 0 + +from sprites import Sprites, Sprite + + +MAX_RODS = 18 +MAX_TOP = 4 +MAX_BOT = 14 +MAX_BEADS = MAX_RODS * (MAX_TOP + MAX_BOT) BEAD_WIDTH = 40 BEAD_HEIGHT = 30 BEAD_OFFSET = 10 @@ -33,24 +56,6 @@ COLORS = ('#FFFFFF', '#FF0000', '#88FF00', '#FF00FF', '#FFFF00', LABELS = ('#000000', '#FFFFFF', '#000000', '#FFFFFF', '#000000', '#000000', '#FFFFFF', '#FFFFFF', '#000000', '#000000') -import gi -from gi.repository import Gtk, Gdk, GdkPixbuf -from math import floor, ceil - -import locale - -import traceback -import logging -_logger = logging.getLogger('abacus-activity') - -try: - from sugar3.graphics import style - GRID_CELL_SIZE = style.GRID_CELL_SIZE -except ImportError: - GRID_CELL_SIZE = 0 - -from sprites import Sprites, Sprite - def dec2frac(d): ''' Convert float to its approximate fractional representation. ''' @@ -188,10 +193,22 @@ def _calc_fade(bead_color, fade_color, i, n): class Bead(): ''' The Bead class is used to define the individual beads. ''' - def __init__(self, sprite, offset, value, max_fade=MAX_FADE_LEVEL, + def __init__(self): + self.spr = None + self.state = 0 + self.fade_level = 0 + self.value = 0 + self.offset = 0 + + def update(self, sprites, pixbuf, offset, value, max_fade=MAX_FADE_LEVEL, tristate=False): ''' We store a sprite, an offset, and a value for each bead. ''' - self.spr = sprite + if self.spr is None: + self.spr = Sprite(sprites, 0, 0, pixbuf) + else: + self.spr.set_image(pixbuf) + self.spr.set_label('') + self.spr.set_label_color('black') self.offset = offset # Decimals will be converted to fractions; # and we want to avoid decimal points in our whole numbers. @@ -207,15 +224,20 @@ class Bead(): def hide(self): ''' Hide the sprite associated with the bead. ''' - self.spr.hide() + if self.spr is not None: + self.spr.hide() def show(self): ''' Show the sprite associated with the bead. ''' - self.spr.set_layer(BEAD_LAYER) + if self.spr is not None: + self.spr.set_layer(BEAD_LAYER) - def move(self, offset): + def move(self, offset, move_the_bead=True): ''' Generic move method: sets state and level. ''' - self.spr.move_relative((0, offset)) + if self.spr is None: + return + if move_the_bead: + self.spr.move_relative((0, offset)) if not self.tristate: self.state = 1 - self.state elif self.state == 1: # moving bead back to center @@ -248,12 +270,16 @@ class Bead(): def set_color(self, color): ''' Set the color of the bead. ''' + if self.spr is None: + return self.spr.set_image(color) self.spr.inval() self.show() def set_label_color(self, color): ''' Set the label color for a bead (default is black). ''' + if self.spr is None: + return self.spr.set_label_color(color) def get_fade_level(self): @@ -266,6 +292,8 @@ class Bead(): def update_label(self): ''' Label active beads. ''' + if self.spr is None: + return value = self.get_value() if self.state == 1 and value < 10000 and value > 0.05: value = self.get_value() @@ -286,9 +314,17 @@ class Bead(): class Rod(): ''' The Rod class is used to define a rod to hold beads. ''' - def __init__(self, sprites, color, frame_height, i, x, y, scale, - cuisenaire=False, bead_color=None): + def __init__(self, beads): ''' We store a sprite for each rod and allocate its beads. ''' + self.spr = None + self.label = None + self.beads = beads + + def update(self, sprites, color, frame_height, i, x, y, scale, + bead_count, cuisenaire=False, bead_color=None): + self._bead_count = bead_count + self.sprites = sprites + rod = _svg_header(10, frame_height - (FRAME_STROKE_WIDTH * 2), scale) + \ _svg_rect(10, frame_height - (FRAME_STROKE_WIDTH * 2), @@ -297,10 +333,13 @@ class Rod(): self.index = i self.scale = scale - self.sprites = sprites - self.spr = Sprite(sprites, x, y, _svg_str_to_pixbuf(rod)) + if self.spr is None: + self.spr = Sprite(sprites, x, y, _svg_str_to_pixbuf(rod)) + else: + self.spr.set_image(_svg_str_to_pixbuf(rod)) + self.spr.move((x, y)) + self.spr.type = 'frame' - self.beads = [] self.lozenge = False self.white_beads = [] self.color_beads = [] @@ -337,15 +376,18 @@ class Rod(): bo = (BEAD_WIDTH - BEAD_OFFSET) * self.scale / 2 ro = (BEAD_WIDTH + 5) * self.scale / 2 - self.label = Sprite(self.sprites, x - bo, y + self.spr.rect[3], - _svg_str_to_pixbuf( - _svg_header(BEAD_WIDTH, BEAD_HEIGHT, self.scale, - stretch=1.0) + \ - _svg_rect(BEAD_WIDTH, BEAD_HEIGHT, 0, 0, 0, 0, - 'none', 'none') + \ - _svg_footer())) + if self.label is None: + self.label = Sprite(self.sprites, x - bo, y + self.spr.rect[3], + _svg_str_to_pixbuf( + _svg_header(BEAD_WIDTH, BEAD_HEIGHT, self.scale, + stretch=1.0) + \ + _svg_rect(BEAD_WIDTH, BEAD_HEIGHT, 0, 0, 0, 0, + 'none', 'none') + \ + _svg_footer())) + else: + self.label.move((x - bo, y + self.spr.rect[3])) self.label.type = 'frame' - self.label.set_label_color('#FFFFFF') + self.label.set_label_color('white') self.label.set_layer(MARK_LAYER) def allocate_beads(self, top_beads, bot_beads, top_factor, @@ -388,21 +430,23 @@ class Rod(): else: max_fade_level = 0 - for b in range(top_beads): - self.beads.append(Bead(Sprite( - self.sprites, x - ro + bo, y + b * BEAD_HEIGHT * self.scale, - bead_color), bead_displacement, - top_factor * bead_value, max_fade=max_fade_level)) - for b in range(bot_beads): + for i in range(top_beads): + self.beads[i + self._bead_count].update( + self.sprites, bead_color, bead_displacement, + top_factor * bead_value, max_fade=max_fade_level) + self.beads[i + self._bead_count].spr.move( + (x - ro + bo, y + i * BEAD_HEIGHT * self.scale)) + + for i in range(bot_beads): displacement = bead_displacement if top_beads > 0: - yy = y + (top_beads + 5 + b) * BEAD_HEIGHT * self.scale + yy = y + (top_beads + 5 + i) * BEAD_HEIGHT * self.scale else: - yy = y + (2 + b) * BEAD_HEIGHT * self.scale + yy = y + (2 + i) * BEAD_HEIGHT * self.scale if all_black: bead_color = self.black_bead elif middle_black: - if b in middle: + if i in middle: bead_color = self.black_bead else: bead_color = self.white_beads[0] @@ -423,65 +467,87 @@ class Rod(): BEAD_HEIGHT * self.scale / 2 yy -= offset displacement -= offset - self.beads.append(Bead(Sprite(self.sprites, x - ro + bo, - yy, bead_color), displacement, - bead_value, tristate=tristate, - max_fade=max_fade_level)) + self.beads[i + self._bead_count + top_beads].update( + self.sprites, bead_color, displacement, + bead_value, tristate=tristate, max_fade=max_fade_level) + self.beads[i + self._bead_count + top_beads].spr.move( + (x - ro + bo, yy)) + if bead_color == self.black_bead: - self.beads[-1].set_label_color('#ffffff') - # Lozenged-shaped beads need to be spaced out more - if self.beads[-1].spr.rect[3] > BEAD_HEIGHT * self.scale: - self.beads[-1].spr.move_relative((0, b * ( - self.beads[-1].spr.rect[3] - (BEAD_HEIGHT * self.scale)))) + self.beads[i + self._bead_count + top_beads].set_label_color( + '#ffffff') + # FIXME + # Lozenged-shaped beads need to be spaced out more + if self.beads[i + self._bead_count + top_beads].spr.rect[3] > \ + BEAD_HEIGHT * self.scale: + self.beads[i + self._bead_count + top_beads].spr.move_relative( + (0, i * ( + self.beads[i + self._bead_count + top_beads].spr.rect[3] - \ + (BEAD_HEIGHT * self.scale)))) + + # self._bead_count -= (self.top_beads + self.bot_beads) if color: - for bead in self.beads: - bead.set_label_color(LABELS[self.index]) + for i in range(self.top_beads + self.bot_beads): + self.beads[i + self._bead_count].set_label_color( + LABELS[self.index]) def hide(self): - for bead in self.beads: - bead.hide() + if self.spr is None: + return + for i in range(self.top_beads + self.bot_beads): + self.beads[i + self._bead_count].hide() self.spr.hide() self.label.hide() def show(self): - for bead in self.beads: - bead.show() + if self.spr is None: + return + for i in range(self.top_beads + self.bot_beads): + self.beads[i + self._bead_count].show() self.spr.set_layer(ROD_LAYER) self.label.set_layer(MARK_LAYER) def get_max_value(self): ''' Returns maximum numeric value for this rod ''' + if self.spr is None: + return 0 max = 0 - for bead in self.beads: - max += bead.value + for i in range(self.top_beads + self.bot_beads): + max += self.beads[i + self._bead_count].value return max def get_value(self): + if self.spr is None: + return 0 sum = 0 - for bead in self.beads: - sum += bead.get_value() + for i in range(self.top_beads + self.bot_beads): + sum += self.beads[i + self._bead_count].get_value() return sum def get_bead_count(self): ''' Returns number of active bottom-bead equivalents on this rod''' + if self.spr is None: + return 0 count = 0 - for i, bead in enumerate(self.beads): - if bead.get_state() == 1: + for i in range(self.top_beads + self.bot_beads): + if self.beads[i + self._bead_count].get_state() == 1: if i < self.top_beads: count += self.top_factor else: count += 1 - if bead.get_state() == -1: + if self.beads[i + self._bead_count].get_state() == -1: count -= 1 return count def set_number(self, number): ''' Try to set a value equal to number; return any remainder ''' + if self.spr is None: + return 0 count = 0 - for i, bead in enumerate(self.beads): - if number >= bead.value: - number -= bead.value + for i in range(self.top_beads + self.bot_beads): + if number >= self.beads[i + self._bead_count].value: + number -= self.beads[i + self._bead_count].value if i < self.top_beads: count += self.top_factor else: @@ -491,6 +557,8 @@ class Rod(): def set_value(self, value): ''' Move beads to represent a numeric value ''' + if self.spr is None: + return if self.top_beads > 0: bot = value % self.top_factor top = (value - bot) / self.top_factor @@ -500,10 +568,10 @@ class Rod(): self.reset() # Set the top. for i in range(top): - self.beads[self.top_beads - i - 1].move_down() + self.beads[self._bead_count + self.top_beads - i - 1].move_down() # Set the bottom for i in range(bot): - self.beads[self.top_beads + i].move_up() + self.beads[self._bead_count + self.top_beads + i].move_up() if value > 0: self.set_label(self.get_bead_count()) @@ -511,108 +579,122 @@ class Rod(): self.label.set_label('') def reset(self): + if self.spr is None: + return # Clear the top. for i in range(self.top_beads): - if self.beads[i].get_state() == 1: + if self.beads[i + self._bead_count].get_state() == 1: self.beads[i].move_up() # Clear the bottom. for i in range(self.bot_beads): - if self.beads[self.top_beads + i].get_state() == 1: - self.beads[self.top_beads + i].move_down() + if self.beads[self.top_beads + i + self._bead_count].get_state() \ + == 1: + self.beads[self.top_beads + i + self._bead_count].move_down() # Fade beads - for bead in self.beads: - if bead.fade_level > 0: - bead.fade_level = 0 - bead.set_color(self.white_beads[0]) + for i in range(self.top_beads + self.bot_beads): + if self.beads[self._bead_count + i].fade_level > 0: + self.beads[self._bead_count + i].fade_level = 0 + self.beads[self._bead_count + i].set_color(self.white_beads[0]) self.label.set_label('') def fade_colors(self): ''' Reduce the saturation level of every bead. ''' + if self.spr is None: + return if self.fade: - for bead in self.beads: - if bead.get_fade_level() > 0: - bead.set_color(self.white_beads[bead.get_fade_level() - 1]) - bead.set_fade_level(bead.get_fade_level() - 1) + for i in range(self.top_beads + self.bot_beads): + if self.beads[self._bead_count + i].get_fade_level() > 0: + self.beads[self._bead_count + i].set_color( + self.white_beads[self.beads[ + self._bead_count + i].get_fade_level() - 1]) + self.beads[self._bead_count + i].set_fade_level( + self.beads[self._bead_count + i].get_fade_level() - 1) def move_bead(self, sprite, dy): ''' Move a bead (or beads) up or down a rod. ''' - + if self.spr is None: + return False # Find the bead associated with the sprite. i = -1 - for bead in self.beads: - if sprite == bead.spr: - i = self.beads.index(bead) + for j in range(self.top_beads + self.bot_beads): + if sprite == self.beads[self._bead_count + j].spr: + i = j break if i == -1: - # _logger.debug('bead not found') return False + if self.fade and self.beads[self._bead_count + i].max_fade_level > 0: + self.beads[self._bead_count + i].set_color(self.white_beads[3]) if i < self.top_beads: - if dy > 0 and bead.get_state() == 0: - if self.fade and bead.max_fade_level > 0: - bead.set_color(self.white_beads[3]) - bead.move_down() + if dy > 0 and self.beads[self._bead_count + i].get_state() == 0: + self.beads[self._bead_count + i].move_down() # Make sure beads below this bead are also moved. for ii in range(self.top_beads - i): - if self.beads[i + ii].state == 0: - if self.fade and bead.max_fade_level > 0: - self.beads[i + ii].set_color(self.white_beads[3]) - self.beads[i + ii].move_down() - elif dy < 0 and bead.state == 1: - if self.fade and bead.max_fade_level > 0: - bead.set_color(self.white_beads[3]) - bead.move_up() + if self.beads[self._bead_count + i + ii].state == 0: + if self.fade and \ + self.beads[self._bead_count + i].max_fade_level > 0: + self.beads[self._bead_count + i + ii].set_color( + self.white_beads[3]) + self.beads[self._bead_count + i + ii].move_down() + elif dy < 0 and self.beads[self._bead_count + i].state == 1: + self.beads[self._bead_count + i].move_up() # Make sure beads above this bead are also moved. for ii in range(i + 1): - if self.beads[i - ii].state == 1: - if self.fade and bead.max_fade_level > 0: - self.beads[i - ii].set_color(self.white_beads[3]) - self.beads[i - ii].move_up() + if self.beads[self._bead_count + i - ii].state == 1: + if self.fade and \ + self.beads[self._bead_count + i].max_fade_level > 0: + self.beads[self._bead_count + i - ii].set_color( + self.white_beads[3]) + self.beads[self._bead_count + i - ii].move_up() else: - if dy < 0 and bead.state == 0: - if self.fade and bead.max_fade_level > 0: - bead.set_color(self.white_beads[3]) - bead.move_up() + if dy < 0 and self.beads[self._bead_count + i].state == 0: + self.beads[self._bead_count + i].move_up() # Make sure beads above this bead are also moved. for ii in range(i - self.top_beads + 1): - if self.beads[i - ii].state == 0: - if self.fade and bead.max_fade_level > 0: - self.beads[i - ii].set_color(self.white_beads[3]) - self.beads[i - ii].move_up() - elif dy < 0 and bead.state == -1: - if self.fade and bead.max_fade_level > 0: - bead.set_color(self.white_beads[3]) - bead.move_up() + if self.beads[self._bead_count + i - ii].state == 0: + if self.fade and \ + self.beads[self._bead_count + i].max_fade_level > 0: + self.beads[self._bead_count + i - ii].set_color( + self.white_beads[3]) + self.beads[self._bead_count + i - ii].move_up() + elif dy < 0 and self.beads[self._bead_count + i].state == -1: + self.beads[self._bead_count + i].move_up() for ii in range(i - self.top_beads + 1): - if self.beads[i - ii].state == -1: - if self.fade and bead.max_fade_level > 0: - self.beads[i - ii].set_color(self.white_beads[3]) - self.beads[i - ii].move_up() - elif dy > 0 and bead.state == 1: - if self.fade and bead.max_fade_level > 0: - bead.set_color(self.white_beads[3]) - bead.move_down() + if self.beads[self._bead_count + i - ii].state == -1: + if self.fade and \ + self.beads[self._bead_count + i].max_fade_level > 0: + self.beads[self._bead_count + i - ii].set_color( + self.white_beads[3]) + self.beads[self._bead_count + i - ii].move_up() + elif dy > 0 and self.beads[self._bead_count + i].state == 1: + self.beads[self._bead_count + i].move_down() # Make sure beads below this bead are also moved. for ii in range(self.top_beads + self.bot_beads - i): - if self.beads[i + ii].state == 1: - if self.fade and bead.max_fade_level > 0: - self.beads[i + ii].set_color(self.white_beads[3]) - self.beads[i + ii].move_down() - elif dy > 0 and bead.state == 0 and bead.tristate: - if self.fade and bead.max_fade_level > 0: - bead.set_color(self.white_beads[3]) - bead.move_down() + if self.beads[self._bead_count + i + ii].state == 1: + if self.fade and \ + self.beads[self._bead_count + i].max_fade_level > 0: + self.beads[self._bead_count + i + ii].set_color( + self.white_beads[3]) + self.beads[self._bead_count + i + ii].move_down() + elif dy > 0 and self.beads[self._bead_count + i].state == 0 and \ + self.beads[self._bead_count + i].tristate: + self.beads[self._bead_count + i].move_down() # Make sure beads below this bead are also moved. for ii in range(self.top_beads + self.bot_beads - i): - if self.beads[i + ii].state == 0: - if self.fade and bead.max_fade_level > 0: - self.beads[i + ii].set_color(self.white_beads[3]) - self.beads[i + ii].move_down() + if self.beads[self._bead_count + i + ii].state == 0: + if self.fade and \ + self.beads[self._bead_count + i].max_fade_level > 0: + self.beads[self._bead_count + i + ii].set_color( + self.white_beads[3]) + self.beads[self._bead_count + i + ii].move_down() self.set_label(self.get_bead_count()) + def set_label(self, n): ''' Different abaci use different labeling schemes. ''' + if self.spr is None: + return # Use hex notation on hex abacus if self.top_beads == 1 and self.bot_beads == 7 and \ self.top_factor == 8: @@ -622,7 +704,7 @@ class Rod(): self.label.set_label('') else: self.label.set_label(n) - return True + return class Abacus(): @@ -642,8 +724,6 @@ class Abacus(): self.bead_colors = parent.bead_colors parent.show_all() - _logger.debug('bead colors %s %s', self.bead_colors[0], - self.bead_colors[1]) self.canvas.set_can_focus(True) self.canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) self.canvas.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK) @@ -674,72 +754,54 @@ class Abacus(): _svg_str_to_pixbuf(background_svg)) background.set_layer(1) + self.decimal = None self.japanese = None - self.russian = None + self.chinese = None self.mayan = None - self.binary = None self.hex = None - self.decimal = None + self.binary = None + self.russian = None self.fraction = None self.caacupe = None self.cuisenaire = None self.custom = None + self.mode_dict = {'decimal': [self.decimal, Decimal], + 'soroban': [self.japanese, Soroban], + 'suanpan': [self.chinese, Suanpan], + 'nepohualtzintzin': [self.mayan, Nepohualtzintzin], + 'hexadecimal': [self.hex, Hex], + 'binary': [self.binary, Binary], + 'schety': [self.russian, Schety], + 'fraction': [self.fraction, Fractions], + 'caacupe': [self.caacupe, Caacupe], + 'cuisenaire': [self.cuisenaire, Cuisenaire], + 'custom': [self.custom, Custom] + } + + self.bead_cache = [] + for i in range(MAX_BEADS): + self.bead_cache.append(Bead()) + + self.rod_cache = [] + for i in range(MAX_BEADS): + self.rod_cache.append(Rod(self.bead_cache)) + self.chinese = Suanpan(self, self.bead_colors) self.mode = self.chinese self.mode.show() def select_abacus(self, abacus): self.mode.hide() - value = int(float(self.mode.value())) - if abacus == 'chinese': - if self.chinese is None: - self.chinese = Suanpan(self, self.bead_colors) - self.mode = self.chinese - elif abacus == 'japanese': - if self.japanese is None: - self.japanese = Soroban(self, self.bead_colors) - self.mode = self.japanese - elif abacus == 'decimal': - if self.decimal is None: - self.decimal = Decimal(self, self.bead_colors) - self.mode = self.decimal - elif abacus == 'mayan': - if self.mayan is None: - self.mayan = Nepohualtzintzin(self, self.bead_colors) - self.mode = self.mayan - elif abacus == 'hex': - if self.hex is None: - self.hex = Hex(self, self.bead_colors) - self.mode = self.hex - elif abacus == 'binary': - if self.binary is None: - self.binary = Binary(self, self.bead_colors) - self.mode = self.binary - elif abacus == 'custom': - if self.custom is None: - self.custom = Custom(self, self.bead_colors) - self.mode = self.custom - elif abacus == 'russian': - if self.russian is None: - self.russian = Schety(self, self.bead_colors) - self.mode = self.russian - elif abacus == 'fraction': - if self.fraction is None: - self.fraction = Fractions(self, self.bead_colors) - self.mode = self.fraction - elif abacus == 'caacupe': - if self.caacupe is None: - self.caacupe = Caacupe(self, self.bead_colors) - self.mode = self.caacupe - elif abacus == 'cuisenaire': - if self.cuisenaire is None: - self.cuisenaire = Cuisenaire(self) - self.mode = self.cuisenaire - self.mode.set_value_from_number(value) + + if self.mode_dict[abacus][0] is None: + self.mode_dict[abacus][0] = self.mode_dict[abacus][1]( + self, self.bead_colors) + else: + self.mode_dict[abacus][0].draw_rods_and_beads() + self.mode = self.mode_dict[abacus][0] self.mode.show() self.mode.label(self.generate_label()) - _logger.debug('Setting mode to %s' % (self.mode.name)) def _button_press_cb(self, win, event): ''' Callback to handle the button presses ''' @@ -860,7 +922,7 @@ class Abacus(): def _destroy_cb(self, win, event): ''' Callback to handle quit ''' - Gtk.main_quit() + gtk.main_quit() def generate_label(self, sum_only=False): ''' The complexity below is to make the label as simple as possible ''' @@ -941,14 +1003,14 @@ class AbacusGeneric(): self.set_parameters() self.create() - def set_parameters(self): + def set_parameters(self, rods=15, top=2, bot=5, factor=5, base=10): ''' Define the physical paramters. ''' self.name = 'suanpan' - self.num_rods = 15 - self.bot_beads = 5 - self.top_beads = 2 - self.base = 10 - self.top_factor = 5 + self.num_rods = rods + self.bot_beads = top + self.top_beads = bot + self.top_factor = factor + self.base = base def create(self, dots=False): ''' Create and position the sprites that compose the abacus ''' @@ -1040,8 +1102,7 @@ class AbacusGeneric(): x += FRAME_STROKE_WIDTH * self.abacus.scale y += FRAME_STROKE_WIDTH * self.abacus.scale - self.rods = [] - self.beads = [] + self.rods = self.abacus.rod_cache self.draw_rods_and_beads(x, y) @@ -1072,29 +1133,38 @@ class AbacusGeneric(): _svg_str_to_pixbuf(mark)) self.mark.type = 'mark' - def draw_rods_and_beads(self, x, y): + def draw_rods_and_beads(self, x=None, y=None): ''' Draw the rods and beads ''' + if x is None: + x = self.rod_x + y = self.rod_y + else: + self.rod_x = x + self.rod_y = y + dx = (BEAD_WIDTH + BEAD_OFFSET) * self.abacus.scale ro = (BEAD_WIDTH + 5) * self.abacus.scale / 2 + bead_count = 0 for i in range(self.num_rods): if self.bead_colors is not None: bead_color = self.bead_colors[i % 2] else: bead_color = None bead_value = pow(self.base, self.num_rods - i - 1) - self.rods.append(Rod(self.abacus.sprites, - ROD_COLORS[i % len(ROD_COLORS)], - self.frame_height, - i, x + i * dx + ro, y, self.abacus.scale, - bead_color=bead_color)) - self.rods[-1].allocate_beads(self.top_beads, self.bot_beads, + self.rods[i].update(self.abacus.sprites, + ROD_COLORS[i % len(ROD_COLORS)], + self.frame_height, + i, x + i * dx + ro, y, self.abacus.scale, + bead_count, bead_color=bead_color) + bead_count += (self.top_beads + self.bot_beads) + self.rods[i].allocate_beads(self.top_beads, self.bot_beads, self.top_factor, bead_value, self.bot_beads) def hide(self): ''' Hide the rod, beads, mark, and frame. ''' - for rod in self.rods: - rod.hide() + for i in range(self.num_rods): + self.rods[i].hide() self.bar.hide() self.label_bar.hide() self.frame.hide() @@ -1106,8 +1176,8 @@ class AbacusGeneric(): def show(self): ''' Show the rod, beads, mark, and frame. ''' self.frame.set_layer(FRAME_LAYER) - for rod in self.rods: - rod.show() + for i in range(self.num_rods): + self.rods[i].show() self.bar.set_layer(BAR_LAYER) self.label_bar.set_layer(BAR_LAYER) if hasattr(self, 'dots'): @@ -1120,8 +1190,8 @@ class AbacusGeneric(): value = string.split() # Move the beads to correspond to column values. try: - for i, rod in enumerate(self.rods): - rod.set_value(int(value[i])) + for i in range(self.num_rods): + self.rods[i].set_value(int(value[i])) except IndexError: _logger.debug('bad saved string length %s (%d != 2 * %d)', string, len(string), self.num_rods) @@ -1132,45 +1202,44 @@ class AbacusGeneric(): def max_value(self): ''' Maximum value possible on abacus ''' max = 0 - for rod in self.rods: - max += rod.get_max_value() + for i in range(self.num_rods): + max += self.rods[i].get_max_value() return max def set_value_from_number(self, number): ''' Set abacus to value in string ''' self.reset_abacus() if number <= self.max_value(): - for rod in self.rods: - number = rod.set_number(number) + for i in range(self.num_rods): + number = self.rods[i].set_number(number) if number == 0: break def reset_abacus(self): ''' Reset beads to original position ''' - for rod in self.rods: - rod.reset() + for i in range(self.num_rods): + self.rods[i].reset() def value(self, count_beads=False): ''' Return a string representing the value of each rod. ''' - if count_beads: # Save the value associated with each rod as a 2-byte integer. string = '' value = [] - for r in range(self.num_rods + 1): # +1 for overflow + for i in range(self.num_rods + 1): # +1 for overflow value.append(0) # Tally the values on each rod. - for r, rod in enumerate(self.rods): - value[r + 1] = rod.get_bead_count() + for i in range(self.num_rods): + value[i + 1] = self.rods[i].get_bead_count() # Save the value associated with each rod as a 2-byte integer. - for j in value[1:]: - string += '%2d ' % (j) + for i in value[1:]: + string += '%2d ' % (i) else: rod_sum = 0 - for rod in self.rods: - rod_sum += rod.get_value() + for i in range(self.num_rods): + rod_sum += self.rods[i].get_value() string = str(rod_sum) return(string) @@ -1184,40 +1253,47 @@ class AbacusGeneric(): def fade_colors(self): ''' Reduce the saturation level of every bead. ''' - for rod in self.rods: - rod.fade_colors() + for i in range(self.num_rods): + self.rods[i].fade_colors() def move_bead(self, sprite, dy): ''' Move a bead (or beads) up or down a rod. ''' self.fade_colors() - for rod in self.rods: - if rod.move_bead(sprite, dy): + for i in range(self.num_rods): + if self.rods[i].move_bead(sprite, dy): break def get_rod_values(self): ''' Return the sum of the values per rod as an array ''' v = [0] * (self.num_rods + 1) - for r, rod in enumerate(self.rods): - v[r + 1] = rod.get_value() + for i in range(self.num_rods): + v[i + 1] = self.rods[i].get_value() return v[1:] class Custom(AbacusGeneric): ''' A custom-made abacus ''' - def __init__(self, abacus, rods, top, bottom, factor, base, - bead_colors=None): + def __init__(self, abacus, bead_colors=None): ''' Specify parameters that define the abacus ''' self.abacus = abacus + self.name = 'custom' + self.num_rods = 15 + self.bot_beads = 5 + self.top_beads = 2 + self.top_factor = 5 + self.base = 10 self.bead_colors = bead_colors + + def set_custom_parameters(self, rods=15, top=2, bot=5, factor=5, base=10): + ''' Specify parameters that define the abacus ''' self.name = 'custom' self.num_rods = rods - self.bot_beads = bottom + self.bot_beads = bot self.top_beads = top - self.base = base self.top_factor = factor - self.create() + self.base = base class Nepohualtzintzin(AbacusGeneric): @@ -1279,22 +1355,31 @@ class Soroban(AbacusGeneric): self.base = 10 self.top_factor = 5 - def draw_rods_and_beads(self, x, y): + def draw_rods_and_beads(self, x=None, y=None): ''' Draw the rods and beads: units offset to center''' + if x is None: + x = self.rod_x + y = self.rod_y + else: + self.rod_x = x + self.rod_y = y + dx = (BEAD_WIDTH + BEAD_OFFSET) * self.abacus.scale ro = (BEAD_WIDTH + 5) * self.abacus.scale / 2 + bead_count = 0 for i in range(self.num_rods): if self.bead_colors is not None: bead_color = self.bead_colors[i % 2] else: bead_color = None bead_value = pow(self.base, int(self.num_rods / 2) - i) - self.rods.append(Rod(self.abacus.sprites, - ROD_COLORS[i % len(ROD_COLORS)], - self.frame_height, - i, x + i * dx + ro, y, self.abacus.scale, - bead_color=bead_color)) - self.rods[-1].allocate_beads(self.top_beads, self.bot_beads, + self.rods[i].update(self.abacus.sprites, + ROD_COLORS[i % len(ROD_COLORS)], + self.frame_height, + i, x + i * dx + ro, y, self.abacus.scale, + bead_count, bead_color=bead_color) + bead_count += (self.top_beads + self.bot_beads) + self.rods[i].allocate_beads(self.top_beads, self.bot_beads, self.top_factor, bead_value, self.bot_beads) @@ -1338,21 +1423,29 @@ class Decimal(AbacusGeneric): self.base = 10 self.top_factor = 1 - def draw_rods_and_beads(self, x, y): + def draw_rods_and_beads(self, x=None, y=None): ''' Draw the rods and beads: override bead color''' + if x is None: + x = self.rod_x + y = self.rod_y + else: + self.rod_x = x + self.rod_y = y dx = (BEAD_WIDTH + BEAD_OFFSET) * self.abacus.scale ro = (BEAD_WIDTH + 5) * self.abacus.scale / 2 + bead_count = 0 for i in range(self.num_rods): if self.bead_colors is not None: bead_color = self.bead_colors[i % 2] else: bead_color = None bead_value = pow(self.base, self.num_rods - i - 1) - self.rods.append(Rod(self.abacus.sprites, '#404040', - self.frame_height, - i, x + i * dx + ro, y, self.abacus.scale, - bead_color=bead_color)) - self.rods[-1].allocate_beads(self.top_beads, self.bot_beads, + self.rods[i].update(self.abacus.sprites, '#404040', + self.frame_height, + i, x + i * dx + ro, y, self.abacus.scale, + bead_count, bead_color=bead_color) + bead_count += (self.top_beads + self.bot_beads) + self.rods[i].allocate_beads(self.top_beads, self.bot_beads, self.top_factor, bead_value, self.bot_beads, color=True) @@ -1401,22 +1494,30 @@ class Schety(AbacusGeneric): self.base = 10 self.top_factor = 1 - def draw_rods_and_beads(self, x, y): + def draw_rods_and_beads(self, x=None, y=None): ''' Draw the rods and beads: short column for 1/4 ''' + if x is None: + x = self.rod_x + y = self.rod_y + else: + self.rod_x = x + self.rod_y = y dx = (BEAD_WIDTH + BEAD_OFFSET) * self.abacus.scale ro = (BEAD_WIDTH + 5) * self.abacus.scale / 2 + bead_count = 0 for i in range(self.num_rods): if self.bead_colors is not None: bead_color = self.bead_colors[i % 2] else: bead_color = None - self.rods.append(Rod(self.abacus.sprites, '#404040', - self.frame_height, - i, x + i * dx + ro, y, self.abacus.scale, - bead_color=bead_color)) - self.rods[-1].allocate_beads(self.top_beads, self.bead_count[i], + self.rods[i].update(self.abacus.sprites, '#404040', + self.frame_height, + i, x + i * dx + ro, y, self.abacus.scale, + bead_count, bead_color=bead_color) + bead_count += (self.top_beads + self.bot_beads) + self.rods[i].allocate_beads(self.top_beads, self.bead_count[i], self.top_factor, self.bead_value[i], - self.bead_count[0], middle_black=True) + self.bead_count[-1], middle_black=True) class Fractions(Schety): @@ -1442,24 +1543,32 @@ class Fractions(Schety): self.base = 10 self.top_factor = 1 - def draw_rods_and_beads(self, x, y): - ''' Draw the rods and beads: short column for 1/4 ''' + def draw_rods_and_beads(self, x=None, y=None): + ''' Draw the rods and beads: short columns for fractions ''' + if x is None: + x = self.rod_x + y = self.rod_y + else: + self.rod_x = x + self.rod_y = y dx = (BEAD_WIDTH + BEAD_OFFSET) * self.abacus.scale ro = (BEAD_WIDTH + 5) * self.abacus.scale / 2 + bead_count = 0 for i in range(self.num_rods): if self.bead_colors is not None: bead_color = self.bead_colors[i % 2] else: bead_color = None - self.rods.append(Rod(self.abacus.sprites, '#404040', - self.frame_height, - i, x + i * dx + ro, y, self.abacus.scale, - bead_color=bead_color)) + self.rods[i].update(self.abacus.sprites, '#404040', + self.frame_height, + i, x + i * dx + ro, y, self.abacus.scale, + bead_count, bead_color=bead_color) + bead_count += (self.top_beads + self.bot_beads) if i < 6: all_black = False else: all_black = True - self.rods[-1].allocate_beads(self.top_beads, self.bead_count[i], + self.rods[i].allocate_beads(self.top_beads, self.bead_count[i], self.top_factor, self.bead_value[i], self.bead_count[-1], @@ -1489,24 +1598,32 @@ class Caacupe(Fractions): self.base = 10 self.top_factor = 1 - def draw_rods_and_beads(self, x, y): - ''' Draw the rods and beads: short column for 1/4 ''' + def draw_rods_and_beads(self, x=None, y=None): + ''' Draw the rods and beads: short columns for fractions ''' + if x is None: + x = self.rod_x + y = self.rod_y + else: + self.rod_x = x + self.rod_y = y dx = (BEAD_WIDTH + BEAD_OFFSET) * self.abacus.scale ro = (BEAD_WIDTH + 5) * self.abacus.scale / 2 + bead_count = 0 for i in range(self.num_rods): if self.bead_colors is not None: bead_color = self.bead_colors[i % 2] else: bead_color = None - self.rods.append(Rod(self.abacus.sprites, '#404040', - self.frame_height, - i, x + i * dx + ro, y, self.abacus.scale, - bead_color=bead_color)) + self.rods[i].update(self.abacus.sprites, '#404040', + self.frame_height, + i, x + i * dx + ro, y, self.abacus.scale, + bead_count, bead_color=bead_color) + bead_count += (self.top_beads + self.bot_beads) if i < 6: all_black = False else: all_black = True - self.rods[-1].allocate_beads(self.top_beads, self.bead_count[i], + self.rods[i].allocate_beads(self.top_beads, self.bead_count[i], self.top_factor, self.bead_value[i], self.bead_count[-1], @@ -1536,20 +1653,29 @@ class Cuisenaire(Caacupe): self.base = 10 self.top_factor = 1 - def draw_rods_and_beads(self, x, y): - ''' Draw the rods and beads: short column for 1/4 ''' + def draw_rods_and_beads(self, x=None, y=None): + ''' Draw the rods and beads: short columns for fractions ''' + if x is None: + x = self.rod_x + y = self.rod_y + else: + self.rod_x = x + self.rod_y = y dx = (BEAD_WIDTH + BEAD_OFFSET) * self.abacus.scale ro = (BEAD_WIDTH + 5) * self.abacus.scale / 2 + bead_count = 0 for i in range(self.num_rods): if self.bead_colors is not None: bead_color = self.bead_colors[i % 2] else: bead_color = None - self.rods.append(Rod(self.abacus.sprites, '#404040', - self.frame_height, - i, x + i * dx + ro, y, self.abacus.scale, - cuisenaire=True, bead_color=bead_color)) - self.rods[-1].allocate_beads(self.top_beads, self.bead_count[i], + self.rods[i].update(self.abacus.sprites, '#404040', + self.frame_height, + i, x + i * dx + ro, y, self.abacus.scale, + bead_count, cuisenaire=True, + bead_color=bead_color) + bead_count += (self.top_beads + self.bot_beads) + self.rods[i].allocate_beads(self.top_beads, self.bead_count[i], self.top_factor, self.bead_value[i], self.bead_count[-1], -- cgit v0.9.1