Пример #1
0
class Card:

    ''' Individual cards '''

    def __init__(self, scale=1.0):
        ''' Create the card and store its attributes '''
        self.spr = None
        self.index = None  # Calculated index
        self._scale = scale

    def create(self, string, attributes=None, sprites=None, file_path=None):
        if attributes is None:
            if self.spr is None:
                self.spr = Sprite(sprites, 0, 0, svg_str_to_pixbuf(string))
            else:
                self.spr.set_image(svg_str_to_pixbuf(string))
            self.index = None
        else:
            self.shape = attributes[0]
            self.color = attributes[1]
            self.num = attributes[2]
            self.fill = attributes[3]
            self.index = self.shape * COLORS * NUMBER * FILLS + \
                self.color * NUMBER * FILLS + \
                self.num * FILLS + \
                self.fill
            if self.spr is None:
                self.spr = Sprite(sprites, 0, 0, svg_str_to_pixbuf(string))
            else:
                self.spr.set_image(svg_str_to_pixbuf(string, True))

            if file_path is not None:
                self.spr.set_image(load_image(file_path, self._scale), i=1,
                                   dx=int(self._scale * CARD_WIDTH * .125),
                                   dy=int(self._scale * CARD_HEIGHT * .125))
        self.spr.set_label_attributes(self._scale * 24)
        self.spr.set_label('')

    def show_card(self, layer=2000):
        ''' Show the card '''
        if self.spr is not None:
            self.spr.set_layer(layer)
            self.spr.draw()

    def hide_card(self):
        ''' Hide a card '''
        if self.spr is not None:
            self.spr.hide()
Пример #2
0
class Card:

    ''' Individual cards '''

    def __init__(self, scale=1.0):
        ''' Create the card and store its attributes '''
        self.spr = None
        self.index = None  # Calculated index
        self._scale = scale

    def create(self, string, attributes=None, sprites=None, file_path=None):
        if attributes is None:
            if self.spr is None:
                self.spr = Sprite(sprites, 0, 0, svg_str_to_pixbuf(string))
            else:
                self.spr.set_image(svg_str_to_pixbuf(string))
            self.index = None
        else:
            self.shape = attributes[0]
            self.color = attributes[1]
            self.num = attributes[2]
            self.fill = attributes[3]
            self.index = self.shape * COLORS * NUMBER * FILLS + \
                self.color * NUMBER * FILLS + \
                self.num * FILLS + \
                self.fill
            if self.spr is None:
                self.spr = Sprite(sprites, 0, 0, svg_str_to_pixbuf(string))
            else:
                self.spr.set_image(svg_str_to_pixbuf(string))

            if file_path is not None:
                self.spr.set_image(load_image(file_path, self._scale), i=1,
                                   dx=int(self._scale * CARD_WIDTH * .125),
                                   dy=int(self._scale * CARD_HEIGHT * .125))
        self.spr.set_label_attributes(self._scale * 24)
        self.spr.set_label('')

    def show_card(self, layer=2000):
        ''' Show the card '''
        if self.spr is not None:
            self.spr.set_layer(layer)
            self.spr.draw()

    def hide_card(self):
        ''' Hide a card '''
        if self.spr is not None:
            self.spr.hide()
Пример #3
0
class Card:
    # Spade   = 1,-1
    # Heart   = 2,-2
    # Club    = 3,-3
    # Diamond = 4,-4
    def __init__(self, game, c, i, x, y):
        self.north = c[0]
        self.east = c[1]
        self.south = c[2]
        self.west = c[3]
        self.orientation = 0
        self.images = []
        self.images.append(load_image(
            os.path.join(game.path, 'card%d.svg' % (i)),
            game.card_dim * game.scale, game.card_dim * game.scale))
        for j in range(3):
            self.images.append(self.images[j].rotate_simple(90))
        # create sprite from svg file
        self.spr = Sprite(game.sprites, x, y, self.images[0])
        self.spr.set_label(i)

    def reset_image(self, game, i):
        while self.orientation != 0:
            self.rotate_ccw()

    def set_orientation(self, r, rotate_spr=True):
        while r != self.orientation:
            self.rotate_ccw(rotate_spr)

    def rotate_ccw(self, rotate_spr=True):
        # print "rotating card " + str(self.spr.label)
        tmp = self.north
        self.north = self.east
        self.east = self.south
        self.south = self.west
        self.west = tmp
        self.orientation += 90
        if self.orientation == 360:
            self.orientation = 0
        if rotate_spr is True:
            self.spr.set_shape(self.images[int(self.orientation / 90)])

    def print_card(self):
        print "(" + str(self.north) + "," + str(self.east) + \
              "," + str(self.south) + "," + str(self.west) + \
              ") " + str(self.rotate) + "ccw" + \
              " x:" + str(self.spr.x) + " y:" + str(self.spr.y)
Пример #4
0
class Card:
    # Spade   = 1,-1
    # Heart   = 2,-2
    # Club    = 3,-3
    # Diamond = 4,-4
    def __init__(self, game, c, i, x, y):
        self.north = c[0]
        self.east = c[1]
        self.south = c[2]
        self.west = c[3]
        self.orientation = 0
        self.images = []
        self.images.append(
            load_image(os.path.join(game.path, 'card%d.svg' % (i)),
                       game.card_dim * game.scale, game.card_dim * game.scale))
        for j in range(3):
            self.images.append(self.images[j].rotate_simple(90))
        # create sprite from svg file
        self.spr = Sprite(game.sprites, x, y, self.images[0])
        self.spr.set_label(i)

    def reset_image(self, game, i):
        while self.orientation != 0:
            self.rotate_ccw()

    def set_orientation(self, r, rotate_spr=True):
        while r != self.orientation:
            self.rotate_ccw(rotate_spr)

    def rotate_ccw(self, rotate_spr=True):
        # print "rotating card " + str(self.spr.label)
        tmp = self.north
        self.north = self.east
        self.east = self.south
        self.south = self.west
        self.west = tmp
        self.orientation += 90
        if self.orientation == 360:
            self.orientation = 0
        if rotate_spr is True:
            self.spr.set_shape(self.images[int(self.orientation / 90)])

    def print_card(self):
        print "(" + str(self.north) + "," + str(self.east) + \
              "," + str(self.south) + "," + str(self.west) + \
              ") " + str(self.rotate) + "ccw" + \
              " x:" + str(self.spr.x) + " y:" + str(self.spr.y)
Пример #5
0
    def _test(self, easter_egg=False):
        ''' Test to see if we estimated correctly '''
        self._timeout = None

        if self._expert:
            delta = self.ball.width() / 6
        else:
            delta = self.ball.width() / 3

        x = self.ball.ball_x() + self.ball.width() / 2
        f = int(self._fraction * self.bar.width())
        self.bar.mark.move((int(f - self.bar.mark_width() / 2),
                            int(self.bar.bar_y() + self._mark_offset(f))))
        if self._challenges[self._n][2] == 0:  # label the column
            spr = Sprite(self._sprites, 0, 0, self.blank_graphic)
            spr.set_label(self._label)
            spr.move((int(self._n * 27), 0))
            spr.set_layer(-1)
        self._challenges[self._n][2] += 1
        if x > f - delta and x < f + delta:
            spr = Sprite(self._sprites, 0, 0, self.smiley_graphic)
            self._correct += 1
            GObject.idle_add(play_audio_from_file, self, self._path_to_success)
        else:
            spr = Sprite(self._sprites, 0, 0, self.frown_graphic)
            GObject.idle_add(play_audio_from_file, self, self._path_to_failure)

        spr.move((int(self._n * 27), int(self._challenges[self._n][2] * 27)))
        spr.set_layer(-1)

        # after enough correct answers, up the difficulty
        if self._correct == len(self._challenges) * 2:
            self._challenge += 1
            if self._challenge < len(CHALLENGES):
                for challenge in CHALLENGES[self._challenge]:
                    self._challenges.append(challenge)
            else:
                self._expert = True

        self.count += 1
        self._dx = 0.  # stop horizontal movement between bounces
Пример #6
0
    def _test(self, easter_egg=False):
        ''' Test to see if we estimated correctly '''
        self.timeout = None
        delta = self.ball.width() / 4
        x = self.ball.ball_x() + self.ball.width() / 2
        f = self.ball.width() / 2 + int(self.fraction * self.bar.width())
        self.bar.mark.move(
            (int(f - self.bar.mark_width() / 2), self.bar.bar_y() - 2))
        if self.challenges[self.n][2] == 0:  # label the column
            spr = Sprite(self.sprites, 0, 0, self.blank_graphic)
            spr.set_label(self.label)
            spr.move((int(self.n * 25), 0))
            spr.set_layer(-1)
        self.challenges[self.n][2] += 1
        if x > f - delta and x < f + delta:
            if not easter_egg:
                spr = Sprite(self.sprites, 0, 0, self.smiley_graphic)
            self.correct += 1
            gobject.idle_add(play_audio_from_file, self, self.path_to_success)
        else:
            if not easter_egg:
                spr = Sprite(self.sprites, 0, 0, self.frown_graphic)
            gobject.idle_add(play_audio_from_file, self, self.path_to_failure)

        if easter_egg:
            spr = Sprite(self.sprites, 0, 0, self.egg_graphic)

        spr.move((int(self.n * 25), int(self.challenges[self.n][2] * 25)))
        spr.set_layer(-1)

        # after enough correct answers, up the difficulty
        if self.correct == len(self.challenges) * 2:
            self.challenge += 1
            if self.challenge < len(CHALLENGES):
                for challenge in CHALLENGES[self.challenge]:
                    self.challenges.append(challenge)
            else:
                self.expert = True

        self.count += 1
        self.dx = 0.  # stop horizontal movement between bounces
Пример #7
0
    def _test(self, easter_egg=False):
        ''' Test to see if we estimated correctly '''
        if self._expert:
            delta = self.ball.width() / 6
        else:
            delta = self.ball.width() / 3

        x = self.ball.ball_x() + self.ball.width() / 2
        f = int(self._fraction * self.bar.width())
        self.bar.mark.move((int(f - self.bar.mark_width() / 2),
                            int(self.bar.bar_y() + self._mark_offset(f))))
        if self._challenges[self._n][2] == 0:  # label the column
            spr = Sprite(self._sprites, 0, 0, self.blank_graphic)
            spr.set_label(self._label)
            spr.move((int(self._n * 27), 0))
            spr.set_layer(-1)
        self._challenges[self._n][2] += 1
        if x > f - delta and x < f + delta:
            spr = Sprite(self._sprites, 0, 0, self.smiley_graphic)
            self._correct += 1
            aplay.play(self._path_to_success)
        else:
            spr = Sprite(self._sprites, 0, 0, self.frown_graphic)
            aplay.play(self._path_to_failure)

        spr.move((int(self._n * 27), int(self._challenges[self._n][2] * 27)))
        spr.set_layer(-1)

        # after enough correct answers, up the difficulty
        if self._correct == len(self._challenges) * 2:
            self._challenge += 1
            if self._challenge < len(CHALLENGES):
                for challenge in CHALLENGES[self._challenge]:
                    self._challenges.append(challenge)
            else:
                self._expert = True

        self.count += 1
        self._dx = 0.  # stop horizontal movement between bounces
Пример #8
0
class PortfolioActivity(activity.Activity):
    ''' Make a slideshow from starred Journal entries. '''
    def __init__(self, handle):
        ''' Initialize the toolbars and the work surface '''
        super(PortfolioActivity, self).__init__(handle)

        self._tmp_path = get_path(activity, 'instance')

        self._hw = get_hardware()

        self._setup_toolbars()
        self._setup_canvas()
        self._setup_workspace()

        self._thumbs = []
        self._thumbnail_mode = False

    def _setup_canvas(self):
        ''' Create a canvas '''
        self._canvas = gtk.DrawingArea()
        self._canvas.set_size_request(gtk.gdk.screen_width(),
                                      gtk.gdk.screen_height())
        self.set_canvas(self._canvas)
        self._canvas.show()
        self.show_all()

        self._canvas.set_flags(gtk.CAN_FOCUS)
        self._canvas.add_events(gtk.gdk.BUTTON_PRESS_MASK)
        self._canvas.add_events(gtk.gdk.POINTER_MOTION_MASK)
        self._canvas.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
        self._canvas.add_events(gtk.gdk.KEY_PRESS_MASK)
        self._canvas.connect("expose-event", self._expose_cb)
        self._canvas.connect("button-press-event", self._button_press_cb)
        self._canvas.connect("button-release-event", self._button_release_cb)
        self._canvas.connect("motion-notify-event", self._mouse_move_cb)

    def _setup_workspace(self):
        ''' Prepare to render the datastore entries. '''
        self._colors = profile.get_color().to_string().split(',')

        # Use the lighter color for the text background
        if lighter_color(self._colors) == 0:
            tmp = self._colors[0]
            self._colors[0] = self._colors[1]
            self._colors[1] = tmp

        self._width = gtk.gdk.screen_width()
        self._height = gtk.gdk.screen_height()
        self._scale = gtk.gdk.screen_height() / 900.

        if self._hw[0:2] == 'xo':
            titlef = 18
            descriptionf = 12
        else:
            titlef = 36
            descriptionf = 24

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)

        self._title = Sprite(
            self._sprites, 0, 0,
            svg_str_to_pixbuf(
                genblank(self._width, int(TITLEH * self._scale),
                         self._colors)))
        self._title.set_label_attributes(int(titlef * self._scale),
                                         rescale=False)
        self._preview = Sprite(
            self._sprites, int(
                (self._width - int(PREVIEWW * self._scale)) / 2),
            int(PREVIEWY * self._scale),
            svg_str_to_pixbuf(
                genblank(int(PREVIEWW * self._scale),
                         int(PREVIEWH * self._scale), self._colors)))

        self._full_screen = Sprite(
            self._sprites, int((self._width - int(FULLW * self._scale)) / 2),
            int(PREVIEWY * self._scale),
            svg_str_to_pixbuf(
                genblank(int(FULLW * self._scale), int(FULLH * self._scale),
                         self._colors)))

        self._description = Sprite(
            self._sprites, int(DESCRIPTIONX * self._scale),
            int(DESCRIPTIONY * self._scale),
            svg_str_to_pixbuf(
                genblank(int(self._width - (2 * DESCRIPTIONX * self._scale)),
                         int(DESCRIPTIONH * self._scale), self._colors)))
        self._description.set_label_attributes(int(descriptionf * self._scale))

        self._description2 = Sprite(
            self._sprites, int(SHORTX * self._scale),
            int(SHORTY * self._scale),
            svg_str_to_pixbuf(
                genblank(int(self._width - (2 * SHORTX * self._scale)),
                         int(SHORTH * self._scale), self._colors)))
        self._description2.set_label_attributes(int(descriptionf *
                                                    self._scale))

        self._my_canvas = Sprite(
            self._sprites, 0, 0,
            gtk.gdk.Pixmap(self._canvas.window, self._width, self._height, -1))
        self._my_gc = self._my_canvas.images[0].new_gc()
        self._my_canvas.set_layer(BOTTOM)

        self._clear_screen()

        self._find_starred()
        self.i = 0
        self._show_slide()

        self._playing = False
        self._rate = 10

    def _setup_toolbars(self):
        ''' Setup the toolbars. '''

        self.max_participants = 1  # no sharing

        if HAVE_TOOLBOX:
            toolbox = ToolbarBox()

            # Activity toolbar
            activity_button = ActivityToolbarButton(self)

            toolbox.toolbar.insert(activity_button, 0)
            activity_button.show()

            self.set_toolbar_box(toolbox)
            toolbox.show()
            self.toolbar = toolbox.toolbar

            adjust_toolbar = gtk.Toolbar()
            adjust_toolbar_button = ToolbarButton(
                label=_('Adjust'),
                page=adjust_toolbar,
                icon_name='preferences-system')
            adjust_toolbar.show_all()
            adjust_toolbar_button.show()
        else:
            # Use pre-0.86 toolbar design
            primary_toolbar = gtk.Toolbar()
            toolbox = activity.ActivityToolbox(self)
            self.set_toolbox(toolbox)
            toolbox.add_toolbar(_('Page'), primary_toolbar)
            adjust_toolbar = gtk.Toolbar()
            toolbox.add_toolbar(_('Adjust'), adjust_toolbar)
            toolbox.show()
            toolbox.set_current_toolbar(1)
            self.toolbar = primary_toolbar

        self._prev_button = button_factory('go-previous-inactive',
                                           _('Prev slide'),
                                           self._prev_cb,
                                           self.toolbar,
                                           accelerator='<Ctrl>P')

        self._next_button = button_factory('go-next',
                                           _('Next slide'),
                                           self._next_cb,
                                           self.toolbar,
                                           accelerator='<Ctrl>N')

        separator_factory(self.toolbar)

        self._auto_button = button_factory('media-playlist-repeat',
                                           _('Autoplay'), self._autoplay_cb,
                                           self.toolbar)

        if HAVE_TOOLBOX:
            toolbox.toolbar.insert(adjust_toolbar_button, -1)

        label = label_factory(_('Adjust playback speed'), adjust_toolbar)
        label.show()

        self._unit_combo = combo_factory(UNITS, TEN,
                                         _('Adjust playback speed'),
                                         self._unit_combo_cb, adjust_toolbar)
        self._unit_combo.show()

        separator_factory(self.toolbar)

        self._thumb_button = button_factory('thumbs-view', _('Thumbnail view'),
                                            self._thumbs_cb, self.toolbar)

        button_factory('view-fullscreen',
                       _('Fullscreen'),
                       self.do_fullscreen_cb,
                       self.toolbar,
                       accelerator='<Alt>Return')

        separator_factory(self.toolbar)

        self._save_button = button_factory('save-as-html', _('Save as HTML'),
                                           self._save_as_html_cb, self.toolbar)

        if HAVE_TOOLBOX:
            separator_factory(toolbox.toolbar, False, True)

            stop_button = StopButton(self)
            stop_button.props.accelerator = '<Ctrl>q'
            toolbox.toolbar.insert(stop_button, -1)
            stop_button.show()

    def _expose_cb(self, win, event):
        ''' Have to refresh after a change in window status. '''
        self._sprites.redraw_sprites()
        return True

    def _destroy_cb(self, win, event):
        ''' Clean up on the way out. '''
        gtk.main_quit()

    def _find_starred(self):
        ''' Find all the favorites in the Journal. '''
        self._dsobjects, self._nobjects = datastore.find({'keep': '1'})
        return

    def _prev_cb(self, button=None):
        ''' The previous button has been clicked; goto previous slide. '''
        if self.i > 0:
            self.i -= 1
            self._show_slide()

    def _next_cb(self, button=None):
        ''' The next button has been clicked; goto next slide. '''
        if self.i < self._nobjects - 1:
            self.i += 1
            self._show_slide()

    def _autoplay_cb(self, button=None):
        ''' The autoplay button has been clicked; step through slides. '''
        if self._playing:
            self._stop_autoplay()
        else:
            if self._thumbnail_mode:
                self._set_view_mode(self._current_slide)
            self._playing = True
            self._auto_button.set_icon('media-playback-pause')
            self._loop()

    def _stop_autoplay(self):
        ''' Stop autoplaying. '''
        self._playing = False
        self._auto_button.set_icon('media-playlist-repeat')
        if hasattr(self, '_timeout_id') and self._timeout_id is not None:
            gobject.source_remove(self._timeout_id)

    def _loop(self):
        ''' Show a slide and then call oneself with a timeout. '''
        self.i += 1
        if self.i == self._nobjects:
            self.i = 0
        self._show_slide()
        self._timeout_id = gobject.timeout_add(int(self._rate * 1000),
                                               self._loop)

    def _bump_test(self):
        ''' Test for accelerometer event (XO 1.75 only). '''
        fh = open('/sys/devices/platform/lis3lv02d/position')
        string = fh.read()
        xyz = string[1:-2].split(',')
        dx = int(xyz[0])
        fh.close()

        if dx > 250:
            self.i += 1
            if self.i == self._nobjects:
                self.i = 0
            self._show_slide()
        elif dx < -250:
            self.i -= 1
            if self.i < 0:
                self.i = self._nobjects - 1
            self._show_slide()
        elif not self._thumbnail_mode:
            self._bump_id = gobject.timeout_add(int(100), self._bump_test)

    def _save_as_html_cb(self, button=None):
        ''' Export an HTML version of the slideshow to the Journal. '''
        self._save_button.set_icon('save-in-progress')
        results = save_html(self._dsobjects, profile.get_nick_name(),
                            self._colors, self._tmp_path)
        html_file = os.path.join(self._tmp_path, 'tmp.html')
        tmp_file = open(html_file, 'w')
        tmp_file.write(results)
        tmp_file.close()

        dsobject = datastore.create()
        dsobject.metadata['title'] = profile.get_nick_name() + ' ' + \
                                     _('Portfolio')
        dsobject.metadata['icon-color'] = profile.get_color().to_string()
        dsobject.metadata['mime_type'] = 'text/html'
        dsobject.set_file_path(html_file)
        dsobject.metadata['activity'] = 'org.laptop.WebActivity'
        datastore.write(dsobject)
        dsobject.destroy()

        gobject.timeout_add(250, self._save_button.set_icon, 'save-as-html')
        return

    def _clear_screen(self):
        ''' Clear the screen to the darker of the two XO colors. '''
        self._my_gc.set_foreground(self._my_gc.get_colormap().alloc_color(
            self._colors[0]))
        self._my_canvas.images[0].draw_rectangle(self._my_gc, True, 0, 0,
                                                 self._width, self._height)
        self._title.hide()
        self._full_screen.hide()
        self._preview.hide()
        self._description.hide()
        if hasattr(self, '_thumbs'):
            for thumbnail in self._thumbs:
                thumbnail[0].hide()
        self.invalt(0, 0, self._width, self._height)

        # Reset drag settings
        self._press = None
        self._release = None
        self._dragpos = [0, 0]
        self._total_drag = [0, 0]
        self.last_spr_moved = None

    def _show_slide(self):
        ''' Display a title, preview image, and decription for slide i. '''
        self._clear_screen()

        if self._nobjects == 0:
            self._prev_button.set_icon('go-previous-inactive')
            self._next_button.set_icon('go-next-inactive')
            self._description.set_label(
                _('Do you have any items in your Journal starred?'))
            self._description.set_layer(MIDDLE)
            return

        if self.i == 0:
            self._prev_button.set_icon('go-previous-inactive')
        else:
            self._prev_button.set_icon('go-previous')
        if self.i == self._nobjects - 1:
            self._next_button.set_icon('go-next-inactive')
        else:
            self._next_button.set_icon('go-next')

        pixbuf = None
        media_object = False
        try:
            pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
                self._dsobjects[self.i].file_path, int(PREVIEWW * self._scale),
                int(PREVIEWH * self._scale))
            media_object = True
        except:
            pixbuf = get_pixbuf_from_journal(self._dsobjects[self.i], 300, 225)

        if pixbuf is not None:
            if not media_object:
                self._preview.images[0] = pixbuf.scale_simple(
                    int(PREVIEWW * self._scale), int(PREVIEWH * self._scale),
                    gtk.gdk.INTERP_TILES)
                self._full_screen.hide()
                self._preview.set_layer(MIDDLE)
            else:
                self._full_screen.images[0] = pixbuf.scale_simple(
                    int(FULLW * self._scale), int(FULLH * self._scale),
                    gtk.gdk.INTERP_TILES)
                self._full_screen.set_layer(MIDDLE)
                self._preview.hide()
        else:
            if self._preview is not None:
                self._preview.hide()
                self._full_screen.hide()

        self._title.set_label(self._dsobjects[self.i].metadata['title'])
        self._title.set_layer(MIDDLE)

        if 'description' in self._dsobjects[self.i].metadata:
            if media_object:
                self._description2.set_label(
                    self._dsobjects[self.i].metadata['description'])
                self._description2.set_layer(MIDDLE)
                self._description.set_label('')
                self._description.hide()
            else:
                self._description.set_label(
                    self._dsobjects[self.i].metadata['description'])
                self._description.set_layer(MIDDLE)
                self._description2.set_label('')
                self._description2.hide()
        else:
            self._description.set_label('')
            self._description.hide()
            self._description2.set_label('')
            self._description2.hide()
        if self._hw == XO175:
            self._bump_id = gobject.timeout_add(int(500), self._bump_test)

    def _thumbs_cb(self, button=None):
        ''' Toggle between thumbnail view and slideshow view. '''
        if self._thumbnail_mode:
            self._set_view_mode(self._current_slide)
            self._show_slide()
        else:
            self._stop_autoplay()
            self._current_slide = self.i
            self._thumbnail_mode = True
            self._clear_screen()

            self._prev_button.set_icon('go-previous-inactive')
            self._next_button.set_icon('go-next-inactive')
            self._thumb_button.set_icon('slide-view')
            self._thumb_button.set_tooltip(_('Slide view'))

            n = int(sqrt(self._nobjects) + 0.5)
            w = int(self._width / n)
            h = int(w * 0.75)  # maintain 4:3 aspect ratio
            x_off = int((self._width - n * w) / 2)
            x = x_off
            y = 0
            for i in range(self._nobjects):
                self.i = i
                self._show_thumb(x, y, w, h)
                x += w
                if x + w > self._width:
                    x = x_off
                    y += h
            self.i = 0  # Reset position in slideshow to the beginning
        return False

    def _show_thumb(self, x, y, w, h):
        ''' Display a preview image and title as a thumbnail. '''

        if len(self._thumbs) < self.i + 1:
            # Create a Sprite for this thumbnail
            pixbuf = None
            try:
                pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
                    self._dsobjects[self.i].file_path, int(w), int(h))
            except:
                pixbuf = get_pixbuf_from_journal(self._dsobjects[self.i],
                                                 int(w), int(h))
            pixbuf_thumb = pixbuf.scale_simple(int(w), int(h),
                                               gtk.gdk.INTERP_TILES)

            self._thumbs.append(
                [Sprite(self._sprites, x, y, pixbuf_thumb), x, y, self.i])
            self._thumbs[-1][0].set_label(str(self.i + 1))
        self._thumbs[self.i][0].set_layer(TOP)

    def do_fullscreen_cb(self, button):
        ''' Hide the Sugar toolbars. '''
        self.fullscreen()

    def invalt(self, x, y, w, h):
        ''' Mark a region for refresh '''
        self._canvas.window.invalidate_rect(
            gtk.gdk.Rectangle(int(x), int(y), int(w), int(h)), False)

    def _spr_to_thumb(self, spr):
        ''' Find which entry in the thumbnails table matches spr. '''
        for i, thumb in enumerate(self._thumbs):
            if spr == thumb[0]:
                return i
        return -1

    def _spr_is_thumbnail(self, spr):
        ''' Does spr match an entry in the thumbnails table? '''
        if self._spr_to_thumb(spr) == -1:
            return False
        else:
            return True

    def _button_press_cb(self, win, event):
        ''' The mouse button was pressed. Is it on a thumbnail sprite? '''
        win.grab_focus()
        x, y = map(int, event.get_coords())

        self._dragpos = [x, y]
        self._total_drag = [0, 0]

        spr = self._sprites.find_sprite((x, y))
        self._press = None
        self._release = None

        # Are we clicking on a thumbnail?
        if not self._spr_is_thumbnail(spr):
            return False

        _logger.debug('found a thumbnail')
        self.last_spr_moved = spr
        self._press = spr
        self._press.set_layer(DRAG)
        return False

    def _mouse_move_cb(self, win, event):
        """ Drag a thumbnail with the mouse. """
        spr = self._press
        if spr is None:
            self._dragpos = [0, 0]
            return False
        win.grab_focus()
        x, y = map(int, event.get_coords())
        dx = x - self._dragpos[0]
        dy = y - self._dragpos[1]
        spr.move_relative([dx, dy])
        self._dragpos = [x, y]
        self._total_drag[0] += dx
        self._total_drag[1] += dy
        return False

    def _button_release_cb(self, win, event):
        ''' Button event is used to swap slides or goto next slide. '''
        win.grab_focus()
        self._dragpos = [0, 0]
        x, y = map(int, event.get_coords())

        if self._thumbnail_mode:
            # Drop the dragged thumbnail below the other thumbnails so
            # that you can find the thumbnail beneath it.
            self._press.set_layer(UNDRAG)
            i = self._spr_to_thumb(self._press)
            spr = self._sprites.find_sprite((x, y))
            if self._spr_is_thumbnail(spr):
                self._release = spr
                # If we found a thumbnail and it is not the one we
                # dragged, swap their positions.
                if not self._press == self._release:
                    j = self._spr_to_thumb(self._release)
                    self._thumbs[i][0] = self._release
                    self._thumbs[j][0] = self._press
                    tmp = self._dsobjects[i]
                    self._dsobjects[i] = self._dsobjects[j]
                    self._dsobjects[j] = tmp
                    self._thumbs[j][0].move(
                        (self._thumbs[j][1], self._thumbs[j][2]))
            self._thumbs[i][0].move((self._thumbs[i][1], self._thumbs[i][2]))
            self._press.set_layer(TOP)
            self._press = None
            self._release = None
        else:
            self._next_cb()
        return False

    def _set_view_mode(self, i):
        ''' Switch to slide-viewing mode. '''
        self._thumbnail_mode = False
        self.i = i
        self._thumb_button.set_icon('thumbs-view')
        self._thumb_button.set_tooltip(_('Thumbnail view'))

    def _unit_combo_cb(self, arg=None):
        ''' Read value of predefined conversion factors from combo box '''
        if hasattr(self, '_unit_combo'):
            active = self._unit_combo.get_active()
            if active in UNIT_DICTIONARY:
                self._rate = UNIT_DICTIONARY[active][1]
Пример #9
0
class Yupana():
    def __init__(self, canvas, parent=None, colors=['#A0FFA0', '#FF8080']):
        self._activity = parent
        self._colors = ['#FFFFFF']
        self._colors.append(colors[0])
        self._colors.append(colors[1])
        self._colors.append('#000000')

        self._canvas = canvas
        if parent is not None:
            parent.show_all()
            self._parent = parent

        self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self._canvas.connect("draw", self.__draw_cb)
        self._canvas.connect("button-press-event", self._button_press_cb)

        self._width = Gdk.Screen.width()
        self._height = Gdk.Screen.height() - (GRID_CELL_SIZE * 1.5)
        self._scale = self._width / (20 * DOT_SIZE * 1.1)
        self._dot_size = int(DOT_SIZE * self._scale)
        self._space = int(self._dot_size / 5.)
        self.we_are_sharing = False
        self._sum = 0
        self._mode = 'ten'
        self.custom = [1, 1, 1, 1, 10]

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)
        Sprite(self._sprites, 0, 0,
               self._box(self._width, self._height, color=colors[1]))

        self._number_box = Sprite(
            self._sprites, 0, 0,
            self._box(self._width, 2 * self._dot_size, color=colors[1]))
        self._number_box.set_label_attributes(48)

        self._dots = []
        for p in range(SIX):
            y = self._height - self._space
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int(p * self._width / 6) + self._space
            y -= self._dot_size
            for d in range(3):  # bottom of fives row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space
            x = int((p * self._width / 6.) + self._dot_size / 2.) + self._space
            y -= self._dot_size + self._space
            for d in range(2):  # top of fives row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int((p * self._width / 6.) + self._dot_size / 2.) + self._space
            y -= self._dot_size
            for d in range(2):  # bottom of threes row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space
            x = int((p * self._width / 6.) + self._dot_size) + self._space
            y -= self._dot_size + self._space
            for d in range(1):  # top of threes row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int((p * self._width / 6.) + self._dot_size / 2.) + self._space
            y -= self._dot_size
            for d in range(2):  # twos row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int((p * self._width / 6.) + self._dot_size) + self._space
            y -= self._dot_size
            for d in range(1):  # ones row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

        for p in range(SIX - 1):
            x = int((p + 1) * self._width / 6)
            Sprite(self._sprites, x - 1, y, self._line(vertical=True))

        # and initialize a few variables we'll need.
        self._all_clear()

    def _all_clear(self):
        ''' Things to reinitialize when starting up a new yupana. '''
        self._sum = 0
        for dot in self._dots:
            if dot.type > 0:
                dot.type = 0
                dot.set_shape(self._new_dot(self._colors[0]))
            dot.set_label('')
        self.set_label(str(self._sum))
        if self.we_are_sharing:
            _logger.debug('sending new label to the share')
            self._parent.send_label(str(self._sum))

    def _initiating(self):
        return self._activity._collab.props.leader

    def new_yupana(self, mode=None):
        ''' Create a new yupana. '''
        self._all_clear()

        if mode is not None:
            self._mode = mode
            o = (SIX - 1) * (TEN + 1)  # only label units
            if mode == 'ten':
                for i in range(TEN + 1):
                    self._dots[o + i].set_label('1')
                self._dots[o - 1].set_label('10')
            elif mode == 'twenty':
                for i in range(TEN + 1):
                    if i in [7, 10]:
                        self._dots[o + i].set_label('1')
                    else:
                        self._dots[o + i].set_label('2')
                self._dots[o - 1].set_label('20')
            elif mode == 'factor':
                for i in range(TEN + 1):
                    if i in [10]:
                        self._dots[o + i].set_label('1')
                    elif i in [8, 9]:
                        self._dots[o + i].set_label('2')
                    elif i in [5, 6, 7]:
                        self._dots[o + i].set_label('3')
                    else:
                        self._dots[o + i].set_label('5')
                self._dots[o - 1].set_label('10')
            elif mode == 'fibonacci':
                for i in range(TEN + 1):
                    if i in [10]:
                        self._dots[o + i].set_label('1')
                    elif i in [8, 9]:
                        self._dots[o + i].set_label('2')
                    elif i in [5, 6, 7]:
                        self._dots[o + i].set_label('5')
                    else:
                        self._dots[o + i].set_label('20')
                self._dots[o - 1].set_label('60')
            else:  # custom
                for i in range(TEN + 1):
                    if i in [10]:
                        self._dots[o + i].set_label(str(self.custom[0]))
                    elif i in [8, 9]:
                        self._dots[o + i].set_label(str(self.custom[1]))
                    elif i in [5, 6, 7]:
                        self._dots[o + i].set_label(str(self.custom[2]))
                    else:
                        self._dots[o + i].set_label(str(self.custom[3]))
                self._dots[o - 1].set_label(str(self.custom[4]))

        if self.we_are_sharing:
            _logger.debug('sending a new yupana')
            self._parent.send_new_yupana()

    def restore_yupana(self, mode, dot_list):
        ''' Restore a yumpana from the Journal or share '''
        for i, dot in enumerate(dot_list):
            self._dots[i].type = dot
            self._dots[i].set_shape(
                self._new_dot(self._colors[self._dots[i].type]))
            if self._dots[i].type == 1:
                self._sum += self._calc_bead_value(i)
        self._mode = mode
        self.set_label(str(self._sum))
        if self.we_are_sharing:
            _logger.debug('sending new label to the share')
            self._parent.send_label(str(self._sum))

    def save_yupana(self):
        ''' Return dot list and orientation for saving to Journal or
        sharing '''
        dot_list = []
        for dot in self._dots:
            dot_list.append(dot.type)
        return [self._mode, dot_list]

    def set_label(self, string):
        ''' Set the label in the toolbar or the window frame. '''
        self._number_box.set_label(string)

    def get_label(self):
        return self._number_box.get_label()

    def _button_press_cb(self, win, event):
        win.grab_focus()
        x, y = list(map(int, event.get_coords()))

        spr = self._sprites.find_sprite((x, y))
        if spr == None:
            return

        if spr.type is not None:
            spr.type += 1
            spr.type %= 2
            spr.set_shape(self._new_dot(self._colors[spr.type]))

            if self.we_are_sharing:
                _logger.debug('sending a click to the share')
                self._parent.send_dot_click(self._dots.index(spr), spr.type)

            if spr.type == 1:
                self._sum += self._calc_bead_value(self._dots.index(spr))
            else:
                self._sum -= self._calc_bead_value(self._dots.index(spr))
            self.set_label(str(self._sum))
            if self.we_are_sharing:
                _logger.debug('sending new label to the share')
                self._parent.send_label(str(self._sum))
        return True

    def _calc_bead_value(self, i):
        ''' Calculate a bead value based on the index and the mode '''
        e = 5 - i / (TEN + 1)
        m = i % 11
        if self._mode == 'ten':
            return 10**e
        elif self._mode == 'twenty':
            if m in [7, 10]:
                return 20**e
            else:
                return (20**e) * 2
        elif self._mode == 'factor':
            if m in [10]:
                return 10**e
            elif m in [8, 9]:
                return (10**e) * 2
            elif m in [5, 6, 7]:
                return (10**e) * 3
            else:
                return (10**e) * 5
        elif self._mode == 'fibonacci':
            if m in [10]:
                return 60**e
            elif m in [8, 9]:
                return (60**e) * 2
            elif m in [5, 6, 7]:
                return (60**e) * 5
            else:
                return (60**e) * 20
        else:  # custom
            if m in [10]:
                return (self.custom[4]**e) * self.custom[0]
            elif m in [8, 9]:
                return (self.custom[4]**e) * self.custom[1]
            elif m in [5, 6, 7]:
                return (self.custom[4]**e) * self.custom[2]
            else:
                return (self.custom[4]**e) * self.custom[3]

    def remote_button_press(self, dot, color):
        ''' Receive a button press from a sharer '''
        self._dots[dot].type = color
        self._dots[dot].set_shape(self._new_dot(self._colors[color]))

    def set_sharing(self, share=True):
        _logger.debug('enabling sharing')
        self.we_are_sharing = share

    def _grid_to_dot(self, pos):
        ''' calculate the dot index from a column and row in the grid '''
        return pos[0] + pos[1] * TEN

    def _dot_to_grid(self, dot):
        ''' calculate the grid column and row for a dot '''
        return [dot % TEN, int(dot / TEN)]

    def __draw_cb(self, canvas, cr):
        self._sprites.redraw_sprites(cr=cr)

    def do_expose_event(self, event):
        ''' Handle the expose-event by drawing '''
        # Restrict Cairo to the exposed area
        cr = self._canvas.window.cairo_create()
        cr.rectangle(event.area.x, event.area.y, event.area.width,
                     event.area.height)
        cr.clip()
        # Refresh sprite list
        self._sprites.redraw_sprites(cr=cr)

    def _destroy_cb(self, win, event):
        Gtk.main_quit()

    def _new_dot(self, color):
        ''' generate a dot of a color color '''
        def darken(color):
            ''' return a darker color than color '''
            gdk_fill_color = Gdk.color_parse(self._fill)
            gdk_fill_dark_color = Gdk.Color(int(gdk_fill_color.red * 0.5),
                                            int(gdk_fill_color.green * 0.5),
                                            int(gdk_fill_color.blue *
                                                0.5)).to_string()
            return str(gdk_fill_dark_color)

        self._dot_cache = {}
        if not color in self._dot_cache:
            self._stroke = color
            self._fill = color
            self._fill_dark = darken(color)
            self._svg_width = self._dot_size
            self._svg_height = self._dot_size
            if color in ['#FFFFFF', '#000000']:
                pixbuf = svg_str_to_pixbuf(
                    self._header() + \
                    self._circle(self._dot_size / 2., self._dot_size / 2.,
                                 self._dot_size / 2.) + \
                    self._footer())
            else:
                pixbuf = svg_str_to_pixbuf(
                    self._header() + \
                    self._def(self._dot_size) + \
                    self._gradient(self._dot_size / 2., self._dot_size / 2.,
                                 self._dot_size / 2.) + \
                    self._footer())

            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self._svg_width,
                                         self._svg_height)
            context = cairo.Context(surface)
            Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0)
            context.rectangle(0, 0, self._svg_width, self._svg_height)
            context.fill()
            self._dot_cache[color] = surface

        return self._dot_cache[color]

    def _line(self, vertical=True):
        ''' Generate a center line '''
        if vertical:
            self._svg_width = 3
            self._svg_height = self._dot_size * 10 + self._space * 2
            return svg_str_to_pixbuf(
                self._header() + \
                self._rect(3, self._dot_size * 10 + self._space * 2, 0, 0) + \
                self._footer())
        else:
            self._svg_width = self._width
            self._svg_height = 3
            return svg_str_to_pixbuf(
                self._header() + \
                self._rect(self._width, 3, 0, 0) + \
                self._footer())

    def _box(self, w, h, color='white'):
        ''' Generate a box '''
        self._svg_width = w
        self._svg_height = h
        return svg_str_to_pixbuf(
                self._header() + \
                self._rect(self._svg_width, self._svg_height, 0, 0,
                           color=color) + \
                self._footer())

    def _header(self):
        return '<svg\n' + 'xmlns:svg="http://www.w3.org/2000/svg"\n' + \
            'xmlns="http://www.w3.org/2000/svg"\n' + \
            'xmlns:xlink="http://www.w3.org/1999/xlink"\n' + \
            'version="1.1"\n' + 'width="' + str(self._svg_width) + '"\n' + \
            'height="' + str(self._svg_height) + '">\n'

    def _rect(self, w, h, x, y, color='black'):
        svg_string = '       <rect\n'
        svg_string += '          width="%f"\n' % (w)
        svg_string += '          height="%f"\n' % (h)
        svg_string += '          rx="%f"\n' % (0)
        svg_string += '          ry="%f"\n' % (0)
        svg_string += '          x="%f"\n' % (x)
        svg_string += '          y="%f"\n' % (y)
        if color == 'black':
            svg_string += 'style="fill:#000000;stroke:#000000;"/>\n'
        elif color == 'white':
            svg_string += 'style="fill:#ffffff;stroke:#ffffff;"/>\n'
        else:
            svg_string += 'style="fill:%s;stroke:%s;"/>\n' % (color, color)
        return svg_string

    def _circle(self, r, cx, cy):
        scale = (DOT_SIZE * self._scale) / 55.
        return '\
  <g transform="matrix(%f,0,0,%f,0,0)">\
  <path\
     d="m 35.798426,4.2187227 c -2.210658,0.9528967 -4.993612,-0.9110169 -7.221856,0 C 23.805784,6.1692574 20.658687,10.945585 17.543179,15.051507 13.020442,21.012013 7.910957,27.325787 6.7103942,34.711004 6.0558895,38.737163 6.434461,43.510925 8.917073,46.747431 c 3.604523,4.699107 15.24614,7.62307 16.048569,7.62307 0.802429,0 8.366957,0.46766 12.036427,-1.203642 2.841316,-1.294111 5.173945,-3.766846 6.820641,-6.419428 2.543728,-4.097563 3.563068,-9.062928 4.21275,-13.841891 C 49.107723,25.018147 48.401726,15.967648 47.433639,9.0332932 47.09109,6.5796321 43.508442,7.2266282 42.329009,5.7211058 41.256823,4.3524824 42.197481,1.860825 40.813604,0.80840168 40.384481,0.48205899 39.716131,0.42556727 39.208747,0.60779459 37.650593,1.1674066 37.318797,3.5633724 35.798426,4.2187227 z"\
     style="fill:#be9e00;fill-opacity:1;stroke:%s;stroke-width:3.0" />\
</g>' % (scale, scale, self._colors[1])

    def _gradient(self, r, cx, cy):
        scale = (DOT_SIZE * self._scale) / 55.
        return '\
  <defs>\
    <linearGradient\
       id="linearGradient3769">\
      <stop\
         id="stop3771"\
         style="stop-color:#ffff00;stop-opacity:1"\
         offset="0" />\
      <stop\
         id="stop3773"\
         style="stop-color:#ffff00;stop-opacity:0"\
         offset="1" />\
    </linearGradient>\
    <linearGradient\
       x1="10.761448"\
       y1="41.003559"\
       x2="56.70686"\
       y2="41.003559"\
       id="linearGradient2999"\
       xlink:href="#linearGradient3769"\
       gradientUnits="userSpaceOnUse"\
       gradientTransform="matrix(0.93094239,0,0,0.93094239,-3.9217825,-2.4013121)" />\
  </defs>\
  <g transform="matrix(%f,0,0,%f,0,0)">\
  <path\
     d="m 35.798426,4.2187227 c -2.210658,0.9528967 -4.993612,-0.9110169 -7.221856,0 C 23.805784,6.1692574 20.658687,10.945585 17.543179,15.051507 13.020442,21.012013 7.910957,27.325787 6.7103942,34.711004 6.0558895,38.737163 6.434461,43.510925 8.917073,46.747431 c 3.604523,4.699107 15.24614,7.62307 16.048569,7.62307 0.802429,0 8.366957,0.46766 12.036427,-1.203642 2.841316,-1.294111 5.173945,-3.766846 6.820641,-6.419428 2.543728,-4.097563 3.563068,-9.062928 4.21275,-13.841891 C 49.107723,25.018147 48.401726,15.967648 47.433639,9.0332932 47.09109,6.5796321 43.508442,7.2266282 42.329009,5.7211058 41.256823,4.3524824 42.197481,1.860825 40.813604,0.80840168 40.384481,0.48205899 39.716131,0.42556727 39.208747,0.60779459 37.650593,1.1674066 37.318797,3.5633724 35.798426,4.2187227 z"\
     style="fill:#fffec2;fill-opacity:1;stroke:#878600;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />\
  <path\
     d="m 15.11608,18.808876 c 1.271657,-1.444003 4.153991,-3.145785 5.495465,-1.7664 2.950062,3.033434 -6.07961,8.17155 -4.219732,11.972265 0.545606,1.114961 2.322391,1.452799 3.532799,1.177599 5.458966,-1.241154 6.490591,-12.132334 12.070397,-11.677864 1.584527,0.129058 2.526156,2.269906 2.845867,3.827199 0.453143,2.207236 -1.962667,6.182399 -1.570133,6.574932 0.392533,0.392533 2.371401,0.909584 3.140266,0.196266 1.91857,-1.779962 -0.490667,-7.752531 0.09813,-7.850664 0.5888,-0.09813 4.421663,2.851694 5.789865,5.004799 0.583188,0.917747 -0.188581,2.956817 0.8832,3.140266 2.128963,0.364398 1.601562,-5.672021 3.729066,-5.299199 1.836829,0.321884 1.450925,3.532631 1.471999,5.397332 0.06743,5.965698 -0.565586,12.731224 -4.317865,17.369596 -3.846028,4.75426 -10.320976,8.31978 -16.388263,7.556266 C 22.030921,53.720741 16.615679,52.58734 11.485147,49.131043 7.9833717,46.771994 6.8028191,42.063042 6.5784815,37.846738 6.3607378,33.754359 8.3381535,29.765466 10.111281,26.070741 c 1.271951,-2.650408 2.940517,-4.917813 5.004799,-7.261865 z"\
     style="fill:url(#linearGradient2999);fill-opacity:1;stroke:none" />\
  <path\
     d="m 32.382709,4.7758124 c -0.123616,1.0811396 1.753928,2.8458658 2.728329,2.9439992 0.974405,0.098134 6.718874,0.7298319 9.159392,-0.1962668 0.820281,-0.3112699 0.968884,-0.9547989 0.974407,-1.4719993 0.02053,-1.9240971 0.03247,-4.7715376 -3.507853,-5.49546551 C 39.556079,0.11012647 37.217081,1.4131653 35.500801,2.2243463 34.054814,2.9077752 32.496703,3.7788369 32.382709,4.7758124 z"\
     style="fill:#b69556;fill-opacity:1;stroke:#b69556;stroke-width:1.31189477px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /></g>' % (
            scale, scale)

    def _def(self, r):
        return '  <defs>\
    <linearGradient\
       id="linearGradient3755">\
      <stop\
         id="stop3757"\
         style="stop-color:%s;stop-opacity:1"\
         offset="0" />\
      <stop\
         id="stop3759"\
         style="stop-color:%s;stop-opacity:1"\
         offset="1" />\
    </linearGradient>\
    <radialGradient\
       cx="0"\
       cy="0"\
       r="%f"\
       fx="%f"\
       fy="%f"\
       id="radialGradient3761"\
       xlink:href="#linearGradient3755"\
       gradientUnits="userSpaceOnUse" />\
  </defs>\
' % (self._fill, self._fill_dark, r, r / 3, r / 3)

    def _footer(self):
        return '</svg>\n'
Пример #10
0
class Game():

    def __init__(self, canvas, parent=None, path=None):
        self._canvas = canvas
        self._parent = parent
        self._parent.show_all()
        self._path = path

        self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self._canvas.connect("draw", self.__draw_cb)
        self._canvas.connect("button-press-event", self._button_press_cb)

        self._width = Gdk.Screen.width()
        self._height = Gdk.Screen.height()
        self._scale = self._width / 1200.
        self._target = 0
        self._tries = 0

        self.level = 0

        self._picture_cards = []
        self._small_picture_cards = []
        self.food_cards = []
        self._group_cards = []
        self._quantity_cards = []
        self._balance_cards = []
        self._last_twenty = []
        self._background = None

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)
        self._background = Sprite(
            self._sprites, 0, 0, GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images','background.png'),
                self._width, self._height))
        self._background.set_layer(0)
        self._background.type = None
        self._background.hide()

        self.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            os.path.join(self._path, 'images', 'word-box.png'),
            int(350 * self._scale), int(100 * self._scale))

        for i in range(len(FOOD_DATA) / 4):
            FOOD.append([FOOD_DATA[i * 4 + NAME], FOOD_DATA[i * 4 + CALS],
                         FOOD_DATA[i * 4 + GROUP], FOOD_DATA[i * 4 + IMAGE]])
            self.food_cards.append(None)
            self._picture_cards.append(None)
            for j in range(6):
                self._small_picture_cards.append(None)
        self.allocate_food(0)

        x = 10
        dx, dy = self.food_cards[0].get_dimensions()

        y = 10
        for i in range(len(MYPLATE)):
            self.word_card_append(self._group_cards, self.pixbuf)
            self._group_cards[-1].type = i
            self._group_cards[-1].set_label(MYPLATE[i][0])
            self._group_cards[-1].move((x, y))
            y += int(dy * 1.25)

        y = 10
        for i in range(len(QUANTITIES)):
            self.word_card_append(self._quantity_cards, self.pixbuf)
            self._quantity_cards[-1].type = i
            self._quantity_cards[-1].set_label(QUANTITIES[i])
            self._quantity_cards[-1].move((x, y))
            y += int(dy * 1.25)

        y = 10
        for i in range(len(BALANCE)):
            self.word_card_append(self._balance_cards, self.pixbuf)
            self._balance_cards[-1].type = i
            self._balance_cards[-1].set_label(BALANCE[i])
            self._balance_cards[-1].move((x, y))
            y += int(dy * 1.25)

        self._smile = Sprite(self._sprites,
                             int(self._width / 4),
                             int(self._height / 4),
                             GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images', 'correct.png'),
                int(self._width / 2),
                int(self._height / 2)))
        self._smile.set_label_attributes(36)
        self._smile.set_margins(10, 0, 10, 0)

        self._frown = Sprite(self._sprites,
                             int(self._width / 4),
                             int(self._height / 4),
                             GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images', 'wrong.png'),
                int(self._width / 2),
                int(self._height / 2)))
        self._frown.set_label_attributes(36)
        self._frown.set_margins(10, 0, 10, 0)

        self.build_food_groups()

        self._all_clear()

    def allocate_food(self, i):
        self.picture_append(os.path.join(self._path, 'images',
                                         FOOD_DATA[i * 4 + IMAGE]), i)
        self.small_picture_append(os.path.join(self._path, 'images',
                                               FOOD_DATA[i * 4 + IMAGE]), i)
        self.word_card_append(self.food_cards, self.pixbuf, i)
        self.food_cards[i].type = i
        self.food_cards[i].set_label(FOOD_DATA[i * 4 + NAME])

    def word_card_append(self, card_list, pixbuf, i=-1):
        if i == -1:
            card_list.append(Sprite(self._sprites, 10, 10, pixbuf))
        else:
            card_list[i] = Sprite(self._sprites, 10, 10, pixbuf)
        card_list[i].set_label_attributes(36)
        card_list[i].set_margins(10, 0, 10, 0)
        card_list[i].hide()

    def picture_append(self, path, i=-1):
        spr = Sprite(
            self._sprites,
            int(self._width / 2.),
            int(self._height / 4.),
            GdkPixbuf.Pixbuf.new_from_file_at_size(
                path, int(self._width / 3.), int(9 * self._width / 12.)))
        if i == -1:
            self._picture_cards.append(spr)
        else:
            self._picture_cards[i] = spr
        self._picture_cards[i].type = 'picture'
        self._picture_cards[i].hide()

    def small_picture_append(self, path, i=-1):
        x = int(self._width / 3.)
        y = int(self._height / 6.)
        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            path,
            int(self._width / 6.),
            int(3 * self._width / 8.)) 
        for j in range(6):  # up to 6 of each card
            if i == -1:
                self._small_picture_cards.append(Sprite(
                self._sprites, x, y, pixbuf))
                self._small_picture_cards[-1].type = 'picture'
                self._small_picture_cards[-1].hide()
            else:
                self._small_picture_cards[i * 6 + j] = Sprite(
                    self._sprites, x, y, pixbuf)
                self._small_picture_cards[i * 6 + j].type = 'picture'
                self._small_picture_cards[i * 6 + j].hide()
            x += int(self._width / 6.)
            if j == 2:
                x = int(self._width / 3.)
                y += int(3 * self._width / 16.)

    def _all_clear(self):
        ''' Things to reinitialize when starting up a new game. '''
        for p in self._picture_cards:
            if p is not None:
                p.hide()
        for p in self._small_picture_cards:
            if p is not None:
                p.hide()
        for i, w in enumerate(self.food_cards):
            if w is not None:
                w.set_label_color('black')
                w.set_label(FOOD[i][NAME])
                w.hide()
        for i, w in enumerate(self._group_cards):
            w.set_label_color('black')
            w.set_label(MYPLATE[i][0])
            w.hide()
        for i, w in enumerate(self._quantity_cards):
            w.set_label_color('black')
            w.set_label(QUANTITIES[i])
            w.hide()
        for i, w in enumerate(self._balance_cards):
            w.set_label_color('black')
            w.set_label(BALANCE[i])
            w.hide()
        self._smile.hide()
        self._frown.hide()

        self._background.set_layer(1)

    def build_food_groups(self):
        self._my_plate = [[], [], [], []]
        for i, food in enumerate(FOOD):
            self._my_plate[MYPLATE[food[GROUP]][QUANT]].append(i)

    def new_game(self):
        ''' Start a new game. '''
        games = {0: self._name_that_food, 1: self._name_that_food_group,
                 2: self._compare_calories, 3: self._how_much_to_eat,
                 4: self._balanced_meal}
        self._all_clear()
        
        games[self.level]()
        
        self._frown.set_label('')
        self._smile.set_label('')
        self._tries = 0

    def _name_that_food(self):
        ''' Choose food cards and one matching food picture '''
        x = 10
        y = 10
        dx, dy = self.food_cards[0].get_dimensions()

        # Select some cards
        word_list = []
        for i in range(NCARDS):
            j = int(uniform(0, len(FOOD)))
            while j in word_list:
                j = int(uniform(0, len(FOOD)))
            word_list.append(j)

        # Show the word cards from the list
        for i in word_list:
            if self.food_cards[i] is None:
                self.allocate_food(i)
            self.food_cards[i].set_layer(100)
            self.food_cards[i].move((x, y))
            y += int(dy * 1.25)

        # Choose a random food image from the list and show it.
        self._target = self.food_cards[
            word_list[int(uniform(0, NCARDS))]].type
        while self._target in self._last_twenty:
            self._target = self.food_cards[
                word_list[int(uniform(0, NCARDS))]].type
        self._last_twenty.append(self._target)
        if len(self._last_twenty) > 20:
            self._last_twenty.remove(self._last_twenty[0])
            
        self._picture_cards[self._target].set_layer(100)

    def _name_that_food_group(self):
        ''' Show group cards and one food picture '''
        for i in range(len(MYPLATE)):
            self._group_cards[i].set_layer(100)

        # Choose a random food image and show it.
        self._target = int(uniform(0, len(FOOD)))
        if self.food_cards[self._target] is None:
            self.allocate_food(self._target)
        self._picture_cards[self._target].set_layer(100)

    def _compare_calories(self):
        ''' Choose food cards and compare the calories '''
        x = 10
        y = 10
        dx, dy = self.food_cards[0].get_dimensions()

        # Select some cards
        word_list = []
        for i in range(6):
            j = int(uniform(0, len(FOOD)))
            while j in word_list:
                j = int(uniform(0, len(FOOD)))
            word_list.append(j)
            if self.food_cards[j] is None:
                self.allocate_food(j)

        # Show the word cards from the list
        for i in word_list:
            self.food_cards[i].set_layer(100)
            self.food_cards[i].move((x, y))
            y += int(dy * 1.25)

        # Show food images
        self._target = word_list[0]
        for i in range(5):
             if FOOD[word_list[i + 1]][CALS] > FOOD[self._target][CALS]:
                 self._target = word_list[i + 1]
        self._small_picture_cards[word_list[0] * 6].set_layer(100)
        self._small_picture_cards[word_list[1] * 6 + 1].set_layer(100)
        self._small_picture_cards[word_list[2] * 6 + 2].set_layer(100)
        self._small_picture_cards[word_list[3] * 6 + 3].set_layer(100)
        self._small_picture_cards[word_list[4] * 6 + 4].set_layer(100)
        self._small_picture_cards[word_list[5] * 6 + 5].set_layer(100)

    def _how_much_to_eat(self):
        ''' Show quantity cards and one food picture '''
        for i in range(len(QUANTITIES)):
            self._quantity_cards[i].set_layer(100)

        # Choose a random image from the list and show it.
        self._target = int(uniform(0, len(FOOD)))
        if self.food_cards[self._target] is None:
            self.allocate_food(self._target)
        self._picture_cards[self._target].set_layer(100)

    def _balanced_meal(self):
        ''' A well-balanced meal '''
        for i in range(2):
            self._balance_cards[i].set_layer(100)

        # Determine how many foods from each group
        n = [0, 0, 0, 0]
        n[0] = int(uniform(0, 2.5))
        n[1] = int(uniform(0, 3 - n[0]))
        n[2] = 3 - n[0] - n[1]
        n[3] = 6 - n[0] - n[1] - n[2]

        # Fill a plate with foods from different groups
        meal = []
        for i in range(n[0]):  # Sweets
            j = int(uniform(0, len(self._my_plate[0])))
            meal.append(self._my_plate[0][j])
        for i in range(n[1]):  # Dairy
            j = int(uniform(0, len(self._my_plate[1])))
            meal.append(self._my_plate[1][j])
        for i in range(n[2]):  # Protein and Fruits
            j = int(uniform(0, len(self._my_plate[2])))
            meal.append(self._my_plate[2][j])
        for i in range(n[3]):  # Veggies and Grains
            j = int(uniform(0, len(self._my_plate[3])))
            meal.append(self._my_plate[3][j])

        if n[0] < 2 and n[1] < 2 and n[2] < n[3]:
            self._target = 0  # Balanced meal
        else:
            self._target = 1

        for i in range(6):
            if self.food_cards[meal[i]] is None:
                self.allocate_food(meal[i])
        # Randomly position small cards
        self._small_picture_cards[meal[3] * 6].set_layer(100)
        self._small_picture_cards[meal[4] * 6 + 1].set_layer(100)
        self._small_picture_cards[meal[1] * 6 + 2].set_layer(100)
        self._small_picture_cards[meal[2] * 6 + 3].set_layer(100)
        self._small_picture_cards[meal[5] * 6 + 4].set_layer(100)
        self._small_picture_cards[meal[0] * 6 + 5].set_layer(100)

    def _button_press_cb(self, win, event):
        win.grab_focus()
        x, y = map(int, event.get_coords())
        spr = self._sprites.find_sprite((x, y))
        if spr == None:
            return
        # We only care about clicks on word cards
        if type(spr.type) != int:
            return

        # Which card was clicked? Set its label to red.
        spr.set_label_color('red')
        label = spr.labels[0]
        spr.set_label(label)

        if self.level == 0:
            if spr.type == self._target:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self.food_cards[self._target].set_label_color('blue')
                label = self.food_cards[self._target].labels[0]
                self.food_cards[self._target].set_label(label)
        elif self.level == 1:
            i = FOOD[self._target][GROUP]
            if spr.type == i:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self._group_cards[i].set_label_color('blue')
                label = self._group_cards[i].labels[0]
                self._group_cards[i].set_label(label)
        elif self.level == 2:
            if spr.type == self._target:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self.food_cards[self._target].set_label_color('blue')
                label = self.food_cards[self._target].labels[0]
                self.food_cards[self._target].set_label(label)
        elif self.level == 3:
            i = MYPLATE[FOOD[self._target][GROUP]][QUANT]
            if spr.type == i:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self._quantity_cards[i].set_label_color('blue')
                label = self._quantity_cards[i].labels[0]
                self._quantity_cards[i].set_label(label)
        elif self.level == 4:
            if self._target == spr.type:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self._balance_cards[self._target].set_label_color('blue')
                label = self._balance_cards[self._target].labels[0]
                self._balance_cards[self._target].set_label(label)
        else:
            _logger.debug('unknown play level %d' % (self.level))

        # Play again
        if self._tries == 3:
            GObject.timeout_add(2000, self.new_game)
        else:
            GObject.timeout_add(1000, self._reset_game)
        return True

    def _reset_game(self):
        self._frown.hide()
        if self.level in [0, 2]:
            for i, w in enumerate(self.food_cards):
                w.set_label_color('black')
                w.set_label(FOOD[i][NAME])
        elif self.level == 1:
            for i, w in enumerate(self._group_cards):
                w.set_label_color('black')
                w.set_label(MYPLATE[i][0])
        elif self.level == 3:
            for i, w in enumerate(self._quantity_cards):
                w.set_label_color('black')
                w.set_label(QUANTITIES[i])
        elif self.level == 4:
            for i, w in enumerate(self._balance_cards):
                w.set_label_color('black')
                w.set_label(BALANCE[i])

    def __draw_cb(self, canvas, cr):
        self._sprites.redraw_sprites(cr=cr)

    def do_expose_event(self, event):
        ''' Handle the expose-event by drawing '''
        # Restrict Cairo to the exposed area
        cr = self._canvas.window.cairo_create()
        cr.rectangle(event.area.x, event.area.y,
                event.area.width, event.area.height)
        cr.clip()
        # Refresh sprite list
        self._sprites.redraw_sprites(cr=cr)

    def _destroy_cb(self, win, event):
        Gtk.main_quit()
Пример #11
0
class Game():
    def __init__(self, canvas, parent=None, path=None):
        self._canvas = canvas
        self._parent = parent
        self._parent.show_all()
        self._path = path

        self._canvas.connect("draw", self.__draw_cb)
        self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self._canvas.connect("button-press-event", self._button_press_cb)
        self._canvas.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
        self._canvas.connect("motion-notify-event", self._mouse_move_cb)
        self._canvas.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
        self._canvas.connect('button-release-event', self._button_release_cb)
        self._canvas.add_events(Gdk.EventMask.KEY_PRESS_MASK)
        self._canvas.connect('key-press-event', self._keypress_cb)

        self._canvas.set_can_focus(True)
        self._canvas.grab_focus()

        self._width = Gdk.Screen.width()
        self._height = Gdk.Screen.height()
        self._scale_x = self._width / 1200.0
        self._scale_y = self._height / 900.0
        self._first_time = True
        self._loco_pos = (0, 0)
        self._loco_dim = (0, 0)
        self._loco_quadrant = 3
        self._drag_pos = [0, 0]
        self._counter = 0
        self._correct = 0
        self._timeout_id = None
        self._pause = 200
        self._press = None
        self._clicked = False
        self._dead_key = None
        self._waiting_for_delete = False
        self._waiting_for_enter = False
        self._seconds = 0
        self._timer_id = None
        self.level = 0
        self.score = 0

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)

        self._BG = [
            'background0.jpg', 'background0.jpg', 'background0.jpg',
            'background1.jpg', 'background2.jpg', 'background2.jpg',
            'background2.jpg'
        ]
        self._backgrounds = []
        for bg in self._BG:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file(
                os.path.join(self._path, 'images', bg))
            pixbuf = pixbuf.scale_simple(self._width, self._height,
                                         GdkPixbuf.InterpType.BILINEAR)
            self._backgrounds.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._backgrounds[-1].type = 'background'
            self._backgrounds[-1].hide()

        self._panel = Sprite(
            self._sprites, int(400 * self._scale_x), int(400 * self._scale_y),
            GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images', 'ventana.png'),
                int(720 * self._scale_x), int(370 * self._scale_y)))
        self._panel.type = 'panel'
        self._panel.set_label(LABELS[0])
        self._panel.set_label_attributes(20)
        self._panel.hide()

        self._LOCOS = glob.glob(os.path.join(self._path, 'images',
                                             'loco*.png'))
        self._loco_cards = []
        for loco in self._LOCOS:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale_x), int(208 * self._scale_y))
            self._loco_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._loco_cards[-1].type = 'loco'
        self._loco_dim = (int(150 * self._scale_x), int(208 * self._scale_y))

        self._MEN = glob.glob(os.path.join(self._path, 'images', 'man*.png'))
        self._man_cards = []
        for loco in self._MEN:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale_x), int(208 * self._scale_y))
            self._man_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._man_cards[-1].type = 'loco'

        self._TAUNTS = glob.glob(
            os.path.join(self._path, 'images', 'taunt*.png'))
        self._taunt_cards = []
        for loco in self._TAUNTS:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale_x), int(208 * self._scale_y))
            self._taunt_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._taunt_cards[-1].type = 'loco'

        self._GHOSTS = glob.glob(
            os.path.join(self._path, 'images', 'ghost*.png'))
        self._ghost_cards = []
        for loco in self._GHOSTS:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale_x), int(208 * self._scale_y))
            self._ghost_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._ghost_cards[-1].type = 'loco'

        self._sticky_cards = []
        self._loco_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            self._LOCOS[0], int(150 * self._scale_x), int(208 * self._scale_y))
        self._man_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            self._MEN[0], int(150 * self._scale_x), int(208 * self._scale_y))
        self._ghost_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            self._GHOSTS[0], int(150 * self._scale_x),
            int(208 * self._scale_y))
        for i in range(len(MSGS[1])):  # Check re i18n
            self._sticky_cards.append(
                Sprite(self._sprites, 0, 0, self._loco_pixbuf))
            self._sticky_cards[-1].type = 'loco'
            self._sticky_cards[-1].set_label_attributes(24,
                                                        vert_align='bottom')

        self._all_clear()

    def _time_increment(self):
        ''' Track seconds since start_time. '''
        self._seconds = int(GLib.get_current_time() - self._start_time)
        self.timer_id = GLib.timeout_add(1000, self._time_increment)

    def _timer_reset(self):
        ''' Reset the timer for each level '''
        self._start_time = GLib.get_current_time()
        if self._timer_id is not None:
            GLib.source_remove(self._timer_id)
            self._timer_id = None
        self.score += self._seconds
        self._time_increment()

    def _all_clear(self):
        ''' Things to reinitialize when starting up a new game. '''
        for p in self._loco_cards:
            p.hide()
        for p in self._man_cards:
            p.hide()
        for p in self._taunt_cards:
            p.hide()
        for p in self._ghost_cards:
            p.hide()
        for p in self._sticky_cards:
            p.set_shape(self._loco_pixbuf)
            p.set_label('')
            p.set_label_color('white')
            p.hide()
        self._backgrounds[self.level].set_layer(BG_LAYER)

    def _show_time(self):
        self.level = 0
        self._all_clear()
        x = int(self._width / 4.)
        y = int(self._height / 8.)
        for i in range(len(str(self.score))):
            self._sticky_cards[i].move((x, y))
            self._sticky_cards[i].set_layer(LOCO_LAYER)
            self._sticky_cards[i].set_label(str(self.score)[i])
            x += int(self._loco_dim[0] / 2.)
        self.score = 0
        self._parent.fullscreen()
        aplay.play(os.path.join(self._path, 'sounds', 'sonar.ogg'))
        GLib.timeout_add(5000, self.new_game, True)

    def new_game(self, first_time):
        ''' Start a new game at the current level. '''
        self._first_time = first_time
        self._clicked = False

        # It may be time to advance to the next level.
        if (self.level == 6 and self._counter == len(MSGS)) or \
           self._counter > 4:
            self._first_time = True
            self.level += 1
            self._counter = 0
            self._correct = 0
            self._pause = 200
            if self.level == len(self._backgrounds):
                self._show_time()
                return

        self._all_clear()

        if self._first_time:
            # Every game starts by putting up a panel with instructions
            # The panel disappears on mouse movement
            self._panel.set_label(LABELS[self.level])
            self._panel.set_layer(PANEL_LAYER)
            aplay.play(os.path.join(self._path, 'sounds', 'drip.ogg'))
            self._timer_reset()

        if self.level == 0:
            # Choose a random location for the Loco
            self._loco_quadrant += int(uniform(1, 4))
            self._loco_quadrant %= 4
            x, y = self._quad_to_xy(self._loco_quadrant)
            aplay.play(os.path.join(self._path, 'sounds', 'bark.ogg'))
            self._loco_cards[0].move((x, y))
            self._loco_pos = (x, y)
        elif self.level == 1:
            aplay.play(os.path.join(self._path, 'sounds', 'glass.ogg'))
        elif self.level == 2:
            aplay.play(os.path.join(self._path, 'sounds', 'glass.ogg'))
            # Place some Locos on the canvas
            for i in range(self._counter + 1):
                self._loco_quadrant += int(uniform(1, 4))
                self._loco_quadrant %= 4
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
        elif self.level == 3:
            aplay.play(os.path.join(self._path, 'sounds', 'bark.ogg'))
            # Place some Locos on the left-side of the canvas
            for i in range(self._counter + 1):
                self._loco_quadrant = int(uniform(2, 4))
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
        elif self.level == 4:
            # Place some Locos on the canvas with letters as labels
            # Just lowercase
            for i in range(self._counter + 1):
                self._loco_quadrant = int(uniform(0, 4))
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
                self._sticky_cards[i].set_label(ALPHABETLC[int(
                    uniform(0, len(ALPHABETLC)))])
        elif self.level == 5:
            # Place some Locos on the canvas with letters as labels
            # Uppercase
            for i in range(self._counter + 1):
                self._loco_quadrant = int(uniform(0, 4))
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
                self._sticky_cards[i].set_label(ALPHABETUC[int(
                    uniform(0, len(ALPHABETUC)))])
        elif self.level == 6:
            x = 0
            y = 0
            c = 0
            for i in range(len(MSGS[self._counter])):
                if MSGS[self._counter][i] == ' ':
                    y += self._loco_dim[1]
                    x = 0
                else:
                    self._sticky_cards[c].move((x, y))
                    self._sticky_cards[c].type = i
                    self._sticky_cards[c].set_layer(LOCO_LAYER)
                    self._sticky_cards[c].set_label(MSGS[self._counter][i])
                    c += 1
                    x += int(self._loco_dim[0] / 2.)

        if self.level in [0, 1]:
            self._loco_quadrant += int(uniform(1, 4))
            self._loco_quadrant %= 4
            x, y = self._quad_to_xy(self._loco_quadrant)
            if self.level == 0:
                self._move_loco(x, y, 0)
            else:
                self._taunt(x, y, 0)

    def _quad_to_xy(self, q):
        x = int(max(0, (self._width / 2.) * uniform(0, 1) - self._loco_dim[0]))
        if q in [0, 1]:
            x += int(self._width / 2.)
        y = int(max(0,
                    (self._height / 2.) * uniform(0, 1) - self._loco_dim[1]))
        if q in [1, 2]:
            y += int(self._height / 2.)
        return x, y

    def _taunt(self, x, y, i):
        n = len(self._taunt_cards)
        self._taunt_cards[(i + 1) % n].hide()
        if self._clicked:
            self._timeout_id = None
            return True
        else:
            self._taunt_cards[i % n].move((x, y))
            self._taunt_cards[i % n].set_layer(LOCO_LAYER)
            self._timeout_id = GLib.timeout_add(200, self._taunt, x, y, i + 1)

    def _move_loco(self, x, y, i):
        j = (i + 1) % len(self._loco_cards)
        cx, cy = self._loco_cards[i].get_xy()
        dx = cx - x
        dy = cy - y
        if dx * dx + dy * dy < 100:
            self._loco_cards[j].move((x, y))
            self._loco_pos = (x, y)
            self._loco_cards[j].hide()
            self._loco_cards[i].hide()
            self._man_cards[0].move((x, y))
            self._man_cards[0].set_layer(LOCO_LAYER)
            self._timeout_id = None
            if self._pause > 50:
                self._pause -= 10
            return True
        else:
            if dx > 0:
                cx -= 5
            elif dx < 0:
                cx += 5
            if dy > 0:
                cy -= 5
            elif dy < 0:
                cy += 5
            self._loco_cards[j].move((cx, cy))
            self._loco_pos = (cx, cy)
            self._loco_cards[j].set_layer(LOCO_LAYER)
            self._loco_cards[i].hide()
            self._timeout_id = GLib.timeout_add(self._pause, self._move_loco,
                                                x, y, j)

    def _keypress_cb(self, area, event):
        ''' Keypress '''
        # Games 4, 5, and 6 use the keyboard
        if self.level not in [4, 5, 6]:
            return True
        k = Gdk.keyval_name(event.keyval)

        if self._waiting_for_enter:
            if k == 'Return':
                self._waiting_for_enter = False
                self._panel.hide()
                self._counter += 1
                self._correct = 0
                GLib.timeout_add(1000, self.new_game, False)
            return

        if k in NOISE_KEYS or k in WHITE_SPACE:
            return True

        if self.level == 6 and self._waiting_for_delete:
            if k in ['BackSpace', 'Delete']:
                self._waiting_for_delete = False
                self._sticky_cards[self._correct].set_label_color('white')
                self._sticky_cards[self._correct].set_label(MSGS[
                    self._counter][self._sticky_cards[self._correct].type])
                self._panel.hide()
                self._panel.set_label_color('black')
            return

        if k[0:5] == 'dead_':
            self._dead_key = k[5:]
            return

        if self.level == 6:
            n = len(MSGS[self._counter])
        else:
            n = self._counter + 1

        if self.level == 6:
            i = self._correct
            if self._dead_key is not None:
                k = DEAD_DICTS[DEAD_KEYS.index(self._dead_key)][k]
                self._dead_key = None
            elif k in PUNCTUATION:
                k = PUNCTUATION[k]
            elif k in SPECIAL:
                k = SPECIAL[k]
            elif len(k) > 1:
                return True
            if self._sticky_cards[i].labels[0] == k:
                self._sticky_cards[i].set_label_color('blue')
                self._sticky_cards[i].set_label(k)
                self._correct += 1
            else:
                self._sticky_cards[i].set_label_color('red')
                self._sticky_cards[i].set_label(k)
                self._panel.set_label_color('red')
                self._panel.set_label(ALERTS[1])
                self._panel.set_layer(PANEL_LAYER)
                self._waiting_for_delete = True
                aplay.play(os.path.join(self._path, 'sounds', 'glass.ogg'))
        else:
            for i in range(n):
                if self._sticky_cards[i].labels[0] == k:
                    self._sticky_cards[i].set_label('')
                    self._sticky_cards[i].hide()
                    break

        # Test for end condition
        if self.level == 6 and \
           self._correct == len(MSGS[self._counter]) - \
                            MSGS[self._counter].count(' '):
            c = 0
            for i in range(len(MSGS[self._counter])):
                if MSGS[self._counter][i] == ' ':
                    continue
                elif MSGS[self._counter][i] != self._sticky_cards[c].labels[0]:
                    return True
                c += 1
            self._panel.set_label(ALERTS[0])
            self._panel.set_layer(PANEL_LAYER)
            self._waiting_for_enter = True
            aplay.play(os.path.join(self._path, 'sounds', 'drip.ogg'))
            return
        else:
            for i in range(n):
                if len(self._sticky_cards[i].labels[0]) > 0:
                    return True
        self._counter += 1
        self._correct = 0
        GLib.timeout_add(1000, self.new_game, False)

    def _mouse_move_cb(self, win, event):
        ''' Move the mouse. '''
        # Games 0, 3, 4, and 5 use move events
        x, y = list(map(int, event.get_coords()))
        if self._seconds > 1:
            self._panel.hide()
        if not self._clicked and self.level == 0:
            # For Game 0, see if the mouse is on the Loco
            dx = x - self._loco_pos[0] - self._loco_dim[0] / 2.
            dy = y - self._loco_pos[1] - self._loco_dim[1] / 2.
            if dx * dx + dy * dy < 200:
                self._clicked = True
                if self._timeout_id is not None:
                    GLib.source_remove(self._timeout_id)
                # Play again
                self._all_clear()
                self._man_cards[0].move((x - int(self._loco_dim[0] / 2.),
                                         y - int(self._loco_dim[1] / 2.)))
                self._man_cards[0].set_layer(LOCO_LAYER)
                self._correct += 1
                self._counter += 1
                GLib.timeout_add(1000, self.new_game, False)
        elif self.level in [4, 5]:
            # For Game 4 and 5, we allow dragging
            if self._press is None:
                self._drag_pos = [0, 0]
                return True
            dx = x - self._drag_pos[0]
            dy = y - self._drag_pos[1]
            self._press.move_relative((dx, dy))
            self._drag_pos = [x, y]
        elif self.level == 3:
            # For Game 3, we are dragging
            if self._press is None:
                self._drag_pos = [0, 0]
                return True
            dx = x - self._drag_pos[0]
            dy = y - self._drag_pos[1]
            self._press.move_relative((dx, dy))
            self._drag_pos = [x, y]
            if x > self._width / 2.:
                self._press.set_shape(self._man_pixbuf)
                if self._press.type == 'loco':
                    self._correct += 1
                    self._press.type = 'man'
        return True

    def _button_release_cb(self, win, event):
        # Game 3 uses release
        if self.level == 3:
            # Move to release
            if self._correct == self._counter + 1:
                self._counter += 1
                self._correct = 0
                GLib.timeout_add(2000, self.new_game, False)
        self._press = None
        self._drag_pos = [0, 0]
        return True

    def _button_press_cb(self, win, event):
        self._press = None
        x, y = list(map(int, event.get_coords()))
        if self.level == 0:
            return
        spr = self._sprites.find_sprite((x, y))
        if spr is None:
            return
        if spr.type != 'loco':
            return
        if self.level < 2 and self._timeout_id is None:
            return
        if self._clicked:
            return

        # Games 1, 2, and 3 involve clicks; Games 4 and 5 allow click to drag
        if self.level == 1:
            self._all_clear()
            self._man_cards[0].move((x - int(self._loco_dim[0] / 2.),
                                     y - int(self._loco_dim[1] / 2.)))
            self._man_cards[0].set_layer(LOCO_LAYER)
            self._clicked = True
            self._counter += 1
            self._correct += 1
            if self._timeout_id is not None:
                GLib.source_remove(self._timeout_id)
            GLib.timeout_add(2000, self.new_game, False)
        elif self.level == 2:
            spr.set_shape(self._ghost_pixbuf)
            spr.type = 'ghost'
            if self._correct == self._counter:
                self._counter += 1
                self._correct = 0
                GLib.timeout_add(2000, self.new_game, False)
            else:
                self._correct += 1
        elif self.level in [3, 4, 5]:
            # In Games 4 and 5, dragging is used to remove overlaps
            self._press = spr
            self._drag_pos = [x, y]
        return True

    def __draw_cb(self, canvas, cr):
        self._sprites.redraw_sprites(cr=cr)

    def do_expose_event(self, event):
        ''' Handle the expose-event by drawing '''
        # Restrict Cairo to the exposed area
        cr = self._canvas.window.cairo_create()
        cr.rectangle(event.area.x, event.area.y, event.area.width,
                     event.area.height)
        cr.clip()
        # Refresh sprite list
        self._sprites.redraw_sprites(cr=cr)

    def _destroy_cb(self, win, event):
        Gtk.main_quit()
Пример #12
0
class BBoardActivity(activity.Activity):
    ''' Make a slideshow from starred Journal entries. '''

    def __init__(self, handle):
        ''' Initialize the toolbars and the work surface '''
        super(BBoardActivity, self).__init__(handle)

        self.datapath = get_path(activity, 'instance')

        self._hw = get_hardware()

        self._playback_buttons = {}
        self._audio_recordings = {}
        self.colors = profile.get_color().to_string().split(',')

        self._setup_toolbars()
        self._setup_canvas()

        self.slides = []
        self._setup_workspace()

        self._buddies = [profile.get_nick_name()]
        self._setup_presence_service()

        self._thumbs = []
        self._thumbnail_mode = False

        self._recording = False
        self._grecord = None
        self._alert = None

        self._dirty = False

    def _setup_canvas(self):
        ''' Create a canvas '''
        self._canvas = gtk.DrawingArea()
        self._canvas.set_size_request(int(gtk.gdk.screen_width()),
                                      int(gtk.gdk.screen_height()))
        self._canvas.show()
        self.set_canvas(self._canvas)
        self.show_all()

        self._canvas.set_flags(gtk.CAN_FOCUS)
        self._canvas.add_events(gtk.gdk.BUTTON_PRESS_MASK)
        self._canvas.add_events(gtk.gdk.POINTER_MOTION_MASK)
        self._canvas.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
        self._canvas.add_events(gtk.gdk.KEY_PRESS_MASK)
        self._canvas.connect("expose-event", self._expose_cb)
        self._canvas.connect("button-press-event", self._button_press_cb)
        self._canvas.connect("button-release-event", self._button_release_cb)
        self._canvas.connect("motion-notify-event", self._mouse_move_cb)

    def _setup_workspace(self):
        ''' Prepare to render the datastore entries. '''

        # Use the lighter color for the text background
        if lighter_color(self.colors) == 0:
            tmp = self.colors[0]
            self.colors[0] = self.colors[1]
            self.colors[1] = tmp

        self._width = gtk.gdk.screen_width()
        self._height = gtk.gdk.screen_height()
        self._scale = gtk.gdk.screen_height() / 900.

        if not HAVE_TOOLBOX and self._hw[0:2] == 'xo':
            titlef = 18
            descriptionf = 12
        else:
            titlef = 36
            descriptionf = 24

        self._find_starred()
        for ds in self.dsobjects:
            if 'title' in ds.metadata:
                title = ds.metadata['title']
            else:
                title = None
            pixbuf = None
            media_object = False
            mimetype = None
            if 'mime_type' in ds.metadata:
                mimetype = ds.metadata['mime_type']
            if mimetype[0:5] == 'image':
                pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
                    ds.file_path, MAXX, MAXY)
                    # ds.file_path, 300, 225)
                media_object = True
            else:
                pixbuf = get_pixbuf_from_journal(ds, MAXX, MAXY)  # 300, 225)
            if 'description' in ds.metadata:
                desc = ds.metadata['description']
            else:
                desc = None
            self.slides.append(Slide(True, ds.object_id, self.colors,
                                     title, pixbuf, desc))

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)

        self._help = Sprite(
            self._sprites,
            int((self._width - int(PREVIEWW * self._scale)) / 2),
            int(PREVIEWY * self._scale),
            gtk.gdk.pixbuf_new_from_file_at_size(
                os.path.join(activity.get_bundle_path(), 'help.png'),
                int(PREVIEWW * self._scale), int(PREVIEWH * self._scale)))
        self._help.hide()

        self._genblanks(self.colors)

        self._title = Sprite(self._sprites, 0, 0, self._title_pixbuf)
        self._title.set_label_attributes(int(titlef * self._scale),
                                         rescale=False)
        self._preview = Sprite(self._sprites,
            int((self._width - int(PREVIEWW * self._scale)) / 2),
            int(PREVIEWY * self._scale), self._preview_pixbuf)

        self._description = Sprite(self._sprites,
                                   int(DESCRIPTIONX * self._scale),
                                   int(DESCRIPTIONY * self._scale),
                                   self._desc_pixbuf)
        self._description.set_label_attributes(int(descriptionf * self._scale))

        self._my_canvas = Sprite(self._sprites, 0, 0, self._canvas_pixbuf)
        self._my_canvas.set_layer(BOTTOM)

        self._clear_screen()

        self.i = 0
        self._show_slide()

        self._playing = False
        self._rate = 10

    def _genblanks(self, colors):
        ''' Need to cache these '''
        self._title_pixbuf = svg_str_to_pixbuf(
            genblank(self._width, int(TITLEH * self._scale), colors))
        self._preview_pixbuf = svg_str_to_pixbuf(
            genblank(int(PREVIEWW * self._scale), int(PREVIEWH * self._scale),
                     colors))
        self._desc_pixbuf = svg_str_to_pixbuf(
            genblank(int(self._width - (2 * DESCRIPTIONX * self._scale)),
                     int(DESCRIPTIONH * self._scale), colors))
        self._canvas_pixbuf = svg_str_to_pixbuf(
            genblank(self._width, self._height, (colors[0], colors[0])))

    def _setup_toolbars(self):
        ''' Setup the toolbars. '''

        self.max_participants = 6

        if HAVE_TOOLBOX:
            toolbox = ToolbarBox()

            # Activity toolbar
            activity_button_toolbar = ActivityToolbarButton(self)

            toolbox.toolbar.insert(activity_button_toolbar, 0)
            activity_button_toolbar.show()

            self.set_toolbar_box(toolbox)
            toolbox.show()
            self.toolbar = toolbox.toolbar

            self.record_toolbar = gtk.Toolbar()
            record_toolbar_button = ToolbarButton(
                label=_('Record a sound'),
                page=self.record_toolbar,
                icon_name='media-audio')
            self.record_toolbar.show_all()
            record_toolbar_button.show()
            toolbox.toolbar.insert(record_toolbar_button, -1)
        else:
            # Use pre-0.86 toolbar design
            primary_toolbar = gtk.Toolbar()
            toolbox = activity.ActivityToolbox(self)
            self.set_toolbox(toolbox)
            toolbox.add_toolbar(_('Page'), primary_toolbar)
            self.record_toolbar = gtk.Toolbar()
            toolbox.add_toolbar(_('Record'), self.record_toolbar)
            toolbox.show()
            toolbox.set_current_toolbar(1)
            self.toolbar = primary_toolbar

        self._prev_button = button_factory(
            'go-previous-inactive', self.toolbar, self._prev_cb,
            tooltip=_('Prev slide'), accelerator='<Ctrl>P')

        self._next_button = button_factory(
            'go-next', self.toolbar, self._next_cb,
            tooltip=_('Next slide'), accelerator='<Ctrl>N')


        separator_factory(self.toolbar)

        slide_button = radio_factory('slide-view', self.toolbar,
                                     self._slides_cb, group=None,
                                     tooltip=_('Slide view'))
        radio_factory('thumbs-view', self.toolbar, self._thumbs_cb,
                      tooltip=_('Thumbnail view'),
                      group=slide_button)

        button_factory('view-fullscreen', self.toolbar,
                       self.do_fullscreen_cb, tooltip=_('Fullscreen'),
                       accelerator='<Alt>Return')

        separator_factory(self.toolbar)

        journal_button = button_factory(
            'write-journal', self.toolbar, self._do_journal_cb,
            tooltip=_('Update description'))
        self._palette = journal_button.get_palette()
        msg_box = gtk.HBox()

        sw = gtk.ScrolledWindow()
        sw.set_size_request(int(gtk.gdk.screen_width() / 2),
                            2 * style.GRID_CELL_SIZE)
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._text_view = gtk.TextView()
        self._text_view.set_left_margin(style.DEFAULT_PADDING)
        self._text_view.set_right_margin(style.DEFAULT_PADDING)
        self._text_view.set_wrap_mode(gtk.WRAP_WORD_CHAR)
        self._text_view.connect('focus-out-event',
                               self._text_view_focus_out_event_cb)
        sw.add(self._text_view)
        sw.show()
        msg_box.pack_start(sw, expand=False)
        msg_box.show_all()

        self._palette.set_content(msg_box)

        label_factory(self.record_toolbar, _('Record a sound') + ':')
        self._record_button = button_factory(
            'media-record', self.record_toolbar,
            self._record_cb, tooltip=_('Start recording'))

        separator_factory(self.record_toolbar)

        # Look to see if we have audio previously recorded
        obj_id = self._get_audio_obj_id()
        dsobject = self._search_for_audio_note(obj_id)
        if dsobject is not None:
            _logger.debug('Found previously recorded audio')
            self._add_playback_button(profile.get_nick_name(),
                                      self.colors,
                                      dsobject.file_path)

        if HAVE_TOOLBOX:
            button_factory('system-restart', activity_button_toolbar,
                           self._resend_cb, tooltip=_('Refresh'))
            separator_factory(activity_button_toolbar)
            self._save_pdf = button_factory(
                'save-as-pdf', activity_button_toolbar,
                self._save_as_pdf_cb, tooltip=_('Save as PDF'))
        else:
            separator_factory(self.toolbar)
            self._save_pdf = button_factory(
                'save-as-pdf', self.toolbar,
                self._save_as_pdf_cb, tooltip=_('Save as PDF'))

        if HAVE_TOOLBOX:
            separator_factory(toolbox.toolbar, True, False)

            stop_button = StopButton(self)
            stop_button.props.accelerator = '<Ctrl>q'
            toolbox.toolbar.insert(stop_button, -1)
            stop_button.show()

    def _do_journal_cb(self, button):
        self._dirty = True
        if self._palette:
            if not self._palette.is_up():
                self._palette.popup(immediate=True,
                                    state=self._palette.SECONDARY)
            else:
                self._palette.popdown(immediate=True)
            return

    def _text_view_focus_out_event_cb(self, widget, event):
        buffer = self._text_view.get_buffer()
        start_iter = buffer.get_start_iter()
        end_iter = buffer.get_end_iter()
        self.slides[self.i].desc = buffer.get_text(start_iter, end_iter)
        self._show_slide()

    def _destroy_cb(self, win, event):
        ''' Clean up on the way out. '''
        gtk.main_quit()

    def _find_starred(self):
        ''' Find all the favorites in the Journal. '''
        self.dsobjects, nobjects = datastore.find({'keep': '1'})
        _logger.debug('found %d starred items', nobjects)

    def _prev_cb(self, button=None):
        ''' The previous button has been clicked; goto previous slide. '''
        if self.i > 0:
            self.i -= 1
            self._show_slide(direction=-1)

    def _next_cb(self, button=None):
        ''' The next button has been clicked; goto next slide. '''
        if self.i < len(self.slides) - 1:
            self.i += 1
            self._show_slide()

    def _save_as_pdf_cb(self, button=None):
        ''' Export an PDF version of the slideshow to the Journal. '''
        _logger.debug('saving to PDF...')
        if 'description' in self.metadata:
            tmp_file = save_pdf(self, self._buddies,
                                description=self.metadata['description'])
        else:
            tmp_file = save_pdf(self, self._buddies)
        _logger.debug('copying PDF file to Journal...')
        dsobject = datastore.create()
        dsobject.metadata['title'] = profile.get_nick_name() + ' ' + \
                                     _('Bboard')
        dsobject.metadata['icon-color'] = profile.get_color().to_string()
        dsobject.metadata['mime_type'] = 'application/pdf'
        dsobject.set_file_path(tmp_file)
        dsobject.metadata['activity'] = 'org.laptop.sugar.ReadActivity'
        datastore.write(dsobject)
        dsobject.destroy()
        return

    def _clear_screen(self):
        ''' Clear the screen to the darker of the two user colors. '''
        self._title.hide()
        self._preview.hide()
        self._description.hide()
        if hasattr(self, '_thumbs'):
            for thumbnail in self._thumbs:
                thumbnail[0].hide()
        self.invalt(0, 0, self._width, self._height)

        # Reset drag settings
        self._press = None
        self._release = None
        self._dragpos = [0, 0]
        self._total_drag = [0, 0]
        self.last_spr_moved = None

    def _update_colors(self):
        ''' Match the colors to those of the slide originator. '''
        if len(self.slides) == 0:
            return
        self._genblanks(self.slides[self.i].colors)
        self._title.set_image(self._title_pixbuf)
        self._preview.set_image(self._preview_pixbuf)
        self._description.set_image(self._desc_pixbuf)
        self._my_canvas.set_image(self._canvas_pixbuf)

    def _show_slide(self, direction=1):
        ''' Display a title, preview image, and decription for slide. '''
        self._clear_screen()
        self._update_colors()

        if len(self.slides) == 0:
            self._prev_button.set_icon('go-previous-inactive')
            self._next_button.set_icon('go-next-inactive')
            self._description.set_label(
                _('Do you have any items in your Journal starred?'))
            self._help.set_layer(TOP)
            self._description.set_layer(MIDDLE)
            return

        if self.i == 0:
            self._prev_button.set_icon('go-previous-inactive')
        else:
            self._prev_button.set_icon('go-previous')
        if self.i == len(self.slides) - 1:
            self._next_button.set_icon('go-next-inactive')
        else:
            self._next_button.set_icon('go-next')

        pixbuf = self.slides[self.i].pixbuf
        if pixbuf is not None:
            self._preview.set_shape(pixbuf.scale_simple(
                    int(PREVIEWW * self._scale),
                    int(PREVIEWH * self._scale),
                    gtk.gdk.INTERP_NEAREST))
            self._preview.set_layer(MIDDLE)
        else:
            if self._preview is not None:
                self._preview.hide()

        self._title.set_label(self.slides[self.i].title)
        self._title.set_layer(MIDDLE)

        if self.slides[self.i].desc is not None:
            self._description.set_label(self.slides[self.i].desc)
            self._description.set_layer(MIDDLE)
            text_buffer = gtk.TextBuffer()
            text_buffer.set_text(self.slides[self.i].desc)
            self._text_view.set_buffer(text_buffer)
        else:
            self._description.set_label('')
            self._description.hide()

    def _add_playback_button(self, nick, colors, audio_file):
        ''' Add a toolbar button for this audio recording '''
        if nick not in self._playback_buttons:
            self._playback_buttons[nick] = button_factory(
                'xo-chat',  self.record_toolbar,
                self._playback_recording_cb, cb_arg=nick,
                tooltip=_('Audio recording by %s') % (nick))
            xocolor = XoColor('%s,%s' % (colors[0], colors[1]))
            icon = Icon(icon_name='xo-chat', xo_color=xocolor)
            icon.show()
            self._playback_buttons[nick].set_icon_widget(icon)
            self._playback_buttons[nick].show()
        self._audio_recordings[nick] = audio_file

    def _slides_cb(self, button=None):
        if self._thumbnail_mode:
            self._thumbnail_mode = False
            self.i = self._current_slide
            self._show_slide()

    def _thumbs_cb(self, button=None):
        ''' Toggle between thumbnail view and slideshow view. '''
        if not self._thumbnail_mode:
            self._current_slide = self.i
            self._thumbnail_mode = True
            self._clear_screen()

            self._prev_button.set_icon('go-previous-inactive')
            self._next_button.set_icon('go-next-inactive')

            n = int(ceil(sqrt(len(self.slides))))
            if n > 0:
                w = int(self._width / n)
            else:
                w = self._width
            h = int(w * 0.75)  # maintain 4:3 aspect ratio
            x_off = int((self._width - n * w) / 2)
            x = x_off
            y = 0
            self._thumbs = []
            for i in range(len(self.slides)):
                self._show_thumb(i, x, y, w, h)
                x += w
                if x + w > self._width:
                    x = x_off
                    y += h
            self.i = 0  # Reset position in slideshow to the beginning
        return False

    def _show_thumb(self, i, x, y, w, h):
        ''' Display a preview image and title as a thumbnail. '''
        pixbuf = self.slides[i].pixbuf
        if pixbuf is not None:
            pixbuf_thumb = pixbuf.scale_simple(
                int(w), int(h), gtk.gdk.INTERP_TILES)
        else:
            pixbuf_thumb = svg_str_to_pixbuf(
                genblank(int(w), int(h), self.slides[i].colors))
        # Create a Sprite for this thumbnail
        self._thumbs.append([Sprite(self._sprites, x, y, pixbuf_thumb),
                             x, y, i])
        self._thumbs[i][0].set_image(
            svg_str_to_pixbuf(svg_rectangle(int(w), int(h),
                                            self.slides[i].colors)), i=1)
        self._thumbs[i][0].set_layer(TOP)

    def _expose_cb(self, win, event):
        ''' Callback to handle window expose events '''
        self.do_expose_event(event)
        return True

    # Handle the expose-event by drawing
    def do_expose_event(self, event):

        # Create the cairo context
        cr = self.canvas.window.cairo_create()

        # Restrict Cairo to the exposed area; avoid extra work
        cr.rectangle(event.area.x, event.area.y,
                event.area.width, event.area.height)
        cr.clip()

        # Refresh sprite list
        self._sprites.redraw_sprites(cr=cr)

    def write_file(self, file_path):
        ''' Clean up '''
        if self._dirty:
            self._save_descriptions_cb()
            self._dirty = False
        if os.path.exists(os.path.join(self.datapath, 'output.ogg')):
            os.remove(os.path.join(self.datapath, 'output.ogg'))

    def do_fullscreen_cb(self, button):
        ''' Hide the Sugar toolbars. '''
        self.fullscreen()

    def invalt(self, x, y, w, h):
        ''' Mark a region for refresh '''
        self._canvas.window.invalidate_rect(
            gtk.gdk.Rectangle(int(x), int(y), int(w), int(h)), False)

    def _spr_to_thumb(self, spr):
        ''' Find which entry in the thumbnails table matches spr. '''
        for i, thumb in enumerate(self._thumbs):
            if spr == thumb[0]:
                return i
        return -1

    def _spr_is_thumbnail(self, spr):
        ''' Does spr match an entry in the thumbnails table? '''
        if self._spr_to_thumb(spr) == -1:
            return False
        else:
            return True

    def _button_press_cb(self, win, event):
        ''' The mouse button was pressed. Is it on a thumbnail sprite? '''
        win.grab_focus()
        x, y = map(int, event.get_coords())

        self._dragpos = [x, y]
        self._total_drag = [0, 0]

        spr = self._sprites.find_sprite((x, y))
        self._press = None
        self._release = None

        # Are we clicking on a thumbnail?
        if not self._spr_is_thumbnail(spr):
            return False

        self.last_spr_moved = spr
        self._press = spr
        self._press.set_layer(DRAG)
        return False

    def _mouse_move_cb(self, win, event):
        """ Drag a thumbnail with the mouse. """
        spr = self._press
        if spr is None:
            self._dragpos = [0, 0]
            return False
        win.grab_focus()
        x, y = map(int, event.get_coords())
        dx = x - self._dragpos[0]
        dy = y - self._dragpos[1]
        spr.move_relative([dx, dy])
        # Also move the star
        self._dragpos = [x, y]
        self._total_drag[0] += dx
        self._total_drag[1] += dy
        return False

    def _button_release_cb(self, win, event):
        ''' Button event is used to swap slides or goto next slide. '''
        win.grab_focus()
        self._dragpos = [0, 0]
        x, y = map(int, event.get_coords())

        if self._thumbnail_mode:
            if self._press is None:
                return
            # Drop the dragged thumbnail below the other thumbnails so
            # that you can find the thumbnail beneath it.
            self._press.set_layer(UNDRAG)
            i = self._spr_to_thumb(self._press)
            spr = self._sprites.find_sprite((x, y))
            if self._spr_is_thumbnail(spr):
                self._release = spr
                # If we found a thumbnail and it is not the one we
                # dragged, swap their positions.
                if not self._press == self._release:
                    j = self._spr_to_thumb(self._release)
                    self._thumbs[i][0] = self._release
                    self._thumbs[j][0] = self._press
                    tmp = self.slides[i]
                    self.slides[i] = self.slides[j]
                    self.slides[j] = tmp
                    self._thumbs[j][0].move((self._thumbs[j][1],
                                             self._thumbs[j][2]))
            self._thumbs[i][0].move((self._thumbs[i][1], self._thumbs[i][2]))
            self._press.set_layer(TOP)
            self._press = None
            self._release = None
        else:
            self._next_cb()
        return False

    def _unit_combo_cb(self, arg=None):
        ''' Read value of predefined conversion factors from combo box '''
        if hasattr(self, '_unit_combo'):
            active = self._unit_combo.get_active()
            if active in UNIT_DICTIONARY:
                self._rate = UNIT_DICTIONARY[active][1]

    def _record_cb(self, button=None):
        ''' Start/stop audio recording '''
        if self._grecord is None:
            _logger.debug('setting up grecord')
            self._grecord = Grecord(self)
        if self._recording:  # Was recording, so stop (and save?)
            _logger.debug('recording...True. Preparing to save.')
            self._grecord.stop_recording_audio()
            self._recording = False
            self._record_button.set_icon('media-record')
            self._record_button.set_tooltip(_('Start recording'))
            _logger.debug('Autosaving recording')
            self._notify(title=_('Save recording'))
            gobject.timeout_add(100, self._wait_for_transcoding_to_finish)
        else:  # Wasn't recording, so start
            _logger.debug('recording...False. Start recording.')
            self._grecord.record_audio()
            self._recording = True
            self._record_button.set_icon('media-recording')
            self._record_button.set_tooltip(_('Stop recording'))

    def _wait_for_transcoding_to_finish(self, button=None):
        while not self._grecord.transcoding_complete():
            time.sleep(1)
        if self._alert is not None:
            self.remove_alert(self._alert)
            self._alert = None
        self._save_recording()

    def _playback_recording_cb(self, button=None, nick=profile.get_nick_name()):
        ''' Play back current recording '''
        _logger.debug('Playback current recording from %s...' % (nick))
        if nick in self._audio_recordings:
            play_audio_from_file(self._audio_recordings[nick])
        return

    def _get_audio_obj_id(self):
        ''' Find unique name for audio object '''
        if 'activity_id' in self.metadata:
            obj_id = self.metadata['activity_id']
        else:
            obj_id = _('Bulletin Board')
        _logger.debug(obj_id)
        return obj_id

    def _save_recording(self):
        if os.path.exists(os.path.join(self.datapath, 'output.ogg')):
            _logger.debug('Saving recording to Journal...')
            obj_id = self._get_audio_obj_id()
            copyfile(os.path.join(self.datapath, 'output.ogg'),
                     os.path.join(self.datapath, '%s.ogg' % (obj_id)))
            dsobject = self._search_for_audio_note(obj_id)
            if dsobject is None:
                dsobject = datastore.create()
            if dsobject is not None:
                _logger.debug(self.dsobjects[self.i].metadata['title'])
                dsobject.metadata['title'] = _('Audio recording by %s') % \
                    (self.metadata['title'])
                dsobject.metadata['icon-color'] = \
                    profile.get_color().to_string()
                dsobject.metadata['tags'] = obj_id
                dsobject.metadata['mime_type'] = 'audio/ogg'
                dsobject.set_file_path(
                    os.path.join(self.datapath, '%s.ogg' % (obj_id)))
                datastore.write(dsobject)
                dsobject.destroy()
            self._add_playback_button(
                profile.get_nick_name(), self.colors,
                os.path.join(self.datapath, '%s.ogg' % (obj_id)))
            if hasattr(self, 'chattube') and self.chattube is not None:
                self._share_audio()
        else:
            _logger.debug('Nothing to save...')
        return

    def _search_for_audio_note(self, obj_id):
        ''' Look to see if there is already a sound recorded for this
        dsobject '''
        dsobjects, nobjects = datastore.find({'mime_type': ['audio/ogg']})
        # Look for tag that matches the target object id
        for dsobject in dsobjects:
            if 'tags' in dsobject.metadata and \
               obj_id in dsobject.metadata['tags']:
                _logger.debug('Found audio note')
                return dsobject
        return None

    def _save_descriptions_cb(self, button=None):
        ''' Find the object in the datastore and write out the changes
        to the decriptions. '''
        for s in self.slides:
            if not s.owner:
                continue
            jobject = datastore.get(s.uid)
            jobject.metadata['description'] = s.desc
            datastore.write(jobject, update_mtime=False,
                            reply_handler=self.datastore_write_cb,
                            error_handler=self.datastore_write_error_cb)

    def datastore_write_cb(self):
        pass

    def datastore_write_error_cb(self, error):
        _logger.error('datastore_write_error_cb: %r' % error)

    def _notify(self, title='', msg=''):
        ''' Notify user when saves are completed '''
        self._alert = Alert()
        self._alert.props.title = title
        self._alert.props.msg = msg
        self.add_alert(self._alert)
        self._alert.show()

    def _resend_cb(self, button=None):
        ''' Resend slides, but only of sharing '''
        if hasattr(self, 'chattube') and self.chattube is not None:
            self._share_slides()
            self._share_audio()

    # Serialize

    def _dump(self, slide):
        ''' Dump data for sharing.'''
        _logger.debug('dumping %s' % (slide.uid))
        data = [slide.uid, slide.colors, slide.title,
                pixbuf_to_base64(activity, slide.pixbuf), slide.desc]
        return self._data_dumper(data)

    def _data_dumper(self, data):
        if _OLD_SUGAR_SYSTEM:
            return json.write(data)
        else:
            io = StringIO()
            jdump(data, io)
            return io.getvalue()

    def _load(self, data):
        ''' Load game data from the journal. '''
        slide = self._data_loader(data)
        if len(slide) == 5:
            if not self._slide_search(slide[0]):
                _logger.debug('loading %s' % (slide[0]))
                self.slides.append(Slide(
                        False, slide[0], slide[1], slide[2],
                        base64_to_pixbuf(activity, slide[3]), slide[4]))

    def _slide_search(self, uid):
        ''' Is this slide in the list already? '''
        for slide in self.slides:
            if slide.uid == uid:
                _logger.debug('skipping %s' % (slide.uid))
                return True
        return False

    def _data_loader(self, data):
        if _OLD_SUGAR_SYSTEM:
            return json.read(data)
        else:
            io = StringIO(data)
            return jload(io)

    # Sharing-related methods

    def _setup_presence_service(self):
        ''' Setup the Presence Service. '''
        self.pservice = presenceservice.get_instance()
        self.initiating = None  # sharing (True) or joining (False)

        owner = self.pservice.get_owner()
        self.owner = owner
        self.buddies = [owner]
        self._share = ''
        self.connect('shared', self._shared_cb)
        self.connect('joined', self._joined_cb)

    def _shared_cb(self, activity):
        ''' Either set up initial share...'''
        if self._shared_activity is None:
            _logger.error('Failed to share or join activity ... \
                _shared_activity is null in _shared_cb()')
            return

        self.initiating = True
        self.waiting = False
        _logger.debug('I am sharing...')

        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)

        _logger.debug('This is my activity: making a tube...')
        id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
            SERVICE, {})

    def _joined_cb(self, activity):
        ''' ...or join an exisiting share. '''
        if self._shared_activity is None:
            _logger.error('Failed to share or join activity ... \
                _shared_activity is null in _shared_cb()')
            return

        self.initiating = False
        _logger.debug('I joined a shared 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)

        _logger.debug('I am joining an activity: waiting for a tube...')
        self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
            reply_handler=self._list_tubes_reply_cb,
            error_handler=self._list_tubes_error_cb)

        self.waiting = True

    def _list_tubes_reply_cb(self, tubes):
        ''' Reply to a list request. '''
        for tube_info in tubes:
            self._new_tube_cb(*tube_info)

    def _list_tubes_error_cb(self, e):
        ''' Log errors. '''
        _logger.error('ListTubes() failed: %s', e)

    def _new_tube_cb(self, id, initiator, type, service, params, state):
        ''' Create a new tube. '''
        _logger.debug('New tube: ID=%d initator=%d type=%d service=%s '
                     'params=%r state=%d', id, initiator, type, service,
                     params, state)

        if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE):
            if state == telepathy.TUBE_STATE_LOCAL_PENDING:
                self.tubes_chan[ \
                              telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)

            tube_conn = TubeConnection(self.conn,
                self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, \
                group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])

            self.chattube = ChatTube(tube_conn, self.initiating, \
                self.event_received_cb)

            if self.waiting:
                self._send_event('j:%s' % (profile.get_nick_name()))

    def event_received_cb(self, text):
        ''' Data is passed as tuples: cmd:text '''
        _logger.debug('<<< %s' % (text[0]))
        if text[0] == 's':  # shared journal objects
            e, data = text.split(':')
            self._load(data)
        elif text[0] == 'j':  # Someone new has joined
            e, buddy = text.split(':')
            _logger.debug('%s has joined' % (buddy))
            if buddy not in self._buddies:
                self._buddies.append(buddy)
            if self.initiating:
                self._send_event('J:%s' % (profile.get_nick_name()))
                self._share_slides()
                self._share_audio()
        elif text[0] == 'J':  # Everyone must share
            e, buddy = text.split(':')
            self.waiting = False
            if buddy not in self._buddies:
                self._buddies.append(buddy)
                _logger.debug('%s has joined' % (buddy))
            self._share_slides()
            self._share_audio()
        elif text[0] == 'a':  # audio recording
            e, data = text.split(':')
            nick, colors, base64 = self._data_loader(data)
            path = os.path.join(activity.get_activity_root(),
                                'instance', 'nick.ogg')
            base64_to_file(activity, base64, path)
            self._add_playback_button(nick, colors, path)

    def _share_audio(self):
        if profile.get_nick_name() in self._audio_recordings:
            base64 = file_to_base64(
                    activity, self._audio_recordings[profile.get_nick_name()])
            gobject.idle_add(self._send_event, 'a:' + str(
                    self._data_dumper([profile.get_nick_name(),
                                       self.colors,
                                       base64])))

    def _share_slides(self):
        for s in self.slides:
            if s.owner:  # Maybe stagger the timing of the sends?
                gobject.idle_add(self._send_event, 's:' + str(self._dump(s)))
        _logger.debug('finished sharing')

    def _send_event(self, text):
        ''' Send event through the tube. '''
        if hasattr(self, 'chattube') and self.chattube is not None:
            _logger.debug('>>> %s' % (text[0]))
            self.chattube.SendText(text)
Пример #13
0
class Game():
    def __init__(self, canvas, parent=None, colors=['#A0FFA0', '#FF8080']):
        self._activity = parent
        self._colors = [colors[0]]
        self._colors.append(colors[1])
        self._colors.append('#FFFFFF')
        self._colors.append('#000000')

        self._colors.append('#FF0000')
        self._colors.append('#FF8080')
        self._colors.append('#FFa0a0')
        self._colors.append('#FFc0c0')

        self._colors.append('#FFFF00')
        self._colors.append('#FFFF80')
        self._colors.append('#FFFFa0')
        self._colors.append('#FFFFe0')

        self._colors.append('#0000FF')
        self._colors.append('#8080FF')
        self._colors.append('#80a0FF')
        self._colors.append('#c0c0FF')

        self._canvas = canvas
        if parent is not None:
            parent.show_all()
            self._parent = parent

        self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self._canvas.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
        self._canvas.connect("draw", self.__draw_cb)
        self._canvas.connect("button-press-event", self._button_press_cb)
        self._canvas.connect("button-release-event", self._button_release_cb)
        self._global_scale = 1
        self._width = Gdk.Screen.width()
        self._height = Gdk.Screen.height() - (GRID_CELL_SIZE * 1.5)
        self._scale = self._width / (10 * DOT_SIZE * 1.2)
        self._dot_size = int(DOT_SIZE * self._scale)
        self._space = int(self._dot_size / 5.)
        self._press = False
        self._release = None
        self._rubbing = False
        self._tapped = None
        self._pausing = False
        self._count = 0
        self._targets = None  # click target
        self._shake = None  # accelerometer target
        self._next = None
        self.last_spr = None
        self._timer = None
        self.roygbiv = False

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)

        self._svg_width = self._width
        self._svg_height = self._height
        self._lightbg = Sprite(self._sprites, 0, 0,
                            svg_str_to_pixbuf(
                self._header() + \
                self._rect(self._width, self._height, 0, 0) + \
                self._footer()))
        self._lightbg.set_label_attributes(24)
        self._lightbg._vert_align = ["bottom"]

        self._darkbg = Sprite(self._sprites, 0, 0,
                              svg_str_to_pixbuf(
                self._header() + \
                self._rect(self._width, self._height, 0, 0, color='#000000') + \
                self._footer()))
        self._darkbg.set_label_attributes(24)
        self._darkbg._vert_align = ["bottom"]
        self._darkbg.set_label_color('yellow')
        self._darkbg.set_layer(0)

        self._dots = []
        for y in range(FIVE):
            for x in range(NINE):
                xoffset = int((self._width - NINE * self._dot_size - \
                                   (NINE - 1) * self._space) / 2.)
                self._dots.append(
                    Sprite(self._sprites,
                           xoffset + x * (self._dot_size + self._space),
                           y * (self._dot_size + self._space),
                           self._new_dot(self._colors[WHITE])))
                self._dots[-1].type = DOT
                self._dots[-1].set_label_attributes(40)

        n = FIVE / 2.

        # and initialize a few variables we'll need.
        self._yellow_dot()

    def _clear_pause(self):
        self._pausing = False
        if self._rubbing and self._release is not None:
            if self._next is not None:
                self._next()

    def _yellow_dot(self):
        for y in range(FIVE):
            for x in range(NINE):
                xoffset = int((self._width - NINE * self._dot_size - \
                                   (NINE - 1) * self._space) / 2.)
                self._dots[x + y * NINE].move(
                    (xoffset + x * (self._dot_size + self._space),
                     y * (self._dot_size + self._space)))
                self._dots[x + y * NINE].set_shape(
                    self._new_dot(self._colors[WHITE]))
                self._dots[x + y * NINE].type = DOT
                self._dots[x + y * NINE].set_layer(100)
        self._lightbg.set_label(_('Tap on the yellow dot.'))
        self._targets = [int(uniform(0, NINE * FIVE))]
        self._next = self._yellow_dot_too
        self._dots[self._targets[0]].set_shape(
            self._new_dot(self._colors[YELLOW]))
        self._dots[self._targets[0]].type = YELLOW
        self._rubbing = False
        self._shake = None

    def _yellow_dot_too(self, append=True):
        ''' Things to reinitialize when starting up a new game. '''
        if append:
            i = self._targets[0]
            while i in self._targets:
                i = int(uniform(0, NINE * FIVE))
            self._targets.append(i)
            self._lightbg.set_label(
                _('Well done! \
Now tap on the other yellow dot.'))
        self._next = self._yellow_dots_three
        self._dots[self._targets[1]].set_shape(
            self._new_dot(self._colors[YELLOW]))
        self._dots[self._targets[1]].type = YELLOW
        self._rubbing = False

    def _yellow_dots_three(self):
        ''' Things to reinitialize when starting up a new game. '''
        if self._release == self._targets[0]:
            self._yellow_dot_too(append=False)
            self._lightbg.set_label(_('The other yellow dot!'))
            return
        i = self._targets[0]
        while i in self._targets:
            i = int(uniform(0, NINE * FIVE))
        self._targets.append(i)
        self._lightbg.set_label(_('Great! Now rub on one of the yellow dots.'))
        self._next = self._red_dot
        self._dots[self._targets[2]].set_shape(
            self._new_dot(self._colors[YELLOW]))
        self._dots[self._targets[2]].type = YELLOW
        self._rubbing = True

    def _red_dot(self):
        if self._release is None:
            return
        self._lightbg.set_label(
            _('Good job! \
Now rub on another one of the yellow dots.'))
        self._next = self._blue_dot
        self._dots[self._release].set_shape(self._new_dot(self._colors[RED]))
        self._dots[self._release].type = RED
        self._rubbing = True

    def _blue_dot(self):
        if self._release is None:
            return
        if self._dots[self._release].type != YELLOW:
            return
        self._lightbg.set_label(
            _('Now gently tap on the yellow dot five times.'))
        self._next = self._yellow_tap
        self._dots[self._release].set_shape(self._new_dot(self._colors[BLUE]))
        self._dots[self._release].type = BLUE
        self._rubbing = False
        self._count = 0

    def _yellow_tap(self):
        if self._dots[self._release].type != YELLOW:
            if self._count == 0:
                self._lightbg.set_label(
                    _('Now gently tap on the yellow dot five times.'))
            else:
                self._lightbg.set_label(_('Tap on a yellow dot.'))
            return
        self._count += 1
        if self._count > 4:
            self._count = 0
            self._next = self._red_tap
            self._lightbg.set_label(
                _('Now gently tap on the red dot five times.'))
        else:
            self._lightbg.set_label(_('Keep tapping.'))
        i = self._targets[0]
        while i in self._targets:
            i = int(uniform(0, NINE * FIVE))
        self._targets.append(i)
        self._dots[i].set_shape(self._new_dot(self._colors[YELLOW]))
        self._dots[i].type = YELLOW

    def _red_tap(self):
        if self._dots[self._release].type != RED:
            if self._count == 0:
                self._lightbg.set_label(
                    _('Now gently tap on the red dot five times.'))
            else:
                self._lightbg.set_label(_('Tap on a red dot.'))
            return
        self._count += 1
        if self._count > 4:
            self._count = 0
            self._next = self._blue_tap
            self._lightbg.set_label(
                _('Now gently tap on the blue dot five times.'))
        else:
            self._lightbg.set_label(_('Keep tapping.'))
        i = self._targets[0]
        while i in self._targets:
            i = int(uniform(0, NINE * FIVE))
        self._targets.append(i)
        self._dots[i].set_shape(self._new_dot(self._colors[RED]))
        self._dots[i].type = RED

    def _blue_tap(self):
        if self._dots[self._release].type != BLUE:
            if self._count == 0:
                self._lightbg.set_label(
                    _('Now gently tap on the blue dot five times.'))
            else:
                self._lightbg.set_label(_('Tap on a blue dot.'))
            return
        self._count += 1
        if self._count > 4:
            self._count = 0
            self._next = self._shake_it
            self._lightbg.set_label('')
            # Since we don't end up in the button press
            GObject.timeout_add(500, self._next)
        else:
            self._lightbg.set_label(_('Keep tapping.'))
        i = self._targets[0]
        while i in self._targets:
            i = int(uniform(0, NINE * FIVE))
        self._targets.append(i)
        self._dots[i].set_shape(self._new_dot(self._colors[BLUE]))
        self._dots[i].type = BLUE

    def _shake_it(self):
        self._lightbg.set_label(_('OK. Now, shake the computer!!'))
        for dot in self._dots:
            if dot.type in [RED, YELLOW, BLUE]:
                dot.set_layer(200)
        self._next = self._shake_it_more
        self._shake = 'random'
        self._pausing = True
        GObject.timeout_add(5000, self._clear_pause)
        GObject.timeout_add(100, read_accelerometer, self)

    def _shake_it_more(self):
        self._lightbg.set_label(_('Shake it harder!!'))
        self._next = self._turn_left
        self._shake = 'random2'
        self._pausing = True
        GObject.timeout_add(5000, self._clear_pause)

    def _turn_left(self):
        self._lightbg.set_label(
            _('See what happens if you turn it to the left.'))
        self._next = self._turn_right
        self._shake = 'left'
        self._pausing = True

    def _turn_right(self):
        self._lightbg.set_label(_('Now turn it to the right.'))
        self._next = self._align
        self._pausing = True
        self._shake = 'right'

    def _align(self):
        self._lightbg.set_label(_('Shake it some more.'))
        self._next = self._tap_six
        self._pausing = True
        self._shake = 'align'

    def _tap_six(self):
        self._shake = None
        self._lightbg.set_label(_('OK. Now press each of the yellow dots.'))
        if self._tapped == None:
            self._tapped = []
        if self._dots[self._release].type != YELLOW:
            self._lightbg.set_label(_('Press the yellow dots.'))
            return
        else:
            if not self._release in self._tapped:
                self._tapped.append(self._release)
                self._dots[self._release].set_label(':)')
        if len(self._tapped) == 6:
            self._darkbg.set_layer(100)
            self._lightbg.set_layer(0)
            for dot in self._dots:
                if dot.type != YELLOW:
                    dot.set_layer(0)
            self._darkbg.set_label(_('Press all of the yellow dots again!'))
            self._tapped = None
            self._next = self._tap_six_too

    def _tap_six_too(self):
        self._shake = None
        if self._tapped == None:
            self._tapped = []
        if self._dots[self._release].type != YELLOW:
            return
        else:
            if not self._release in self._tapped:
                self._tapped.append(self._release)
                self._dots[self._release].set_label('')
        if len(self._tapped) == 6:
            self._lightbg.set_layer(100)
            self._darkbg.set_layer(0)
            for dot in self._dots:
                if dot.type in [RED, BLUE]:
                    dot.set_layer(100)
            pos1 = self._dots[self._targets[1]].get_xy()
            pos2 = self._dots[self._targets[2]].get_xy()
            self._dots[self._targets[1]].move(pos2)
            self._dots[self._targets[2]].move(pos1)
            self._lightbg.set_label(
                _('Tap on the two dots that switched positions.'))
            self._tapped = None
            self._next = self._tap_two

    def _tap_two(self):
        self._shake = None
        if self._tapped == None:
            self._tapped = []
        if not self._release in [self._targets[1], self._targets[2]]:
            self._lightbg.set_label(_('Keep trying.'))
            return
        else:
            if not self._release in self._tapped:
                self._tapped.append(self._release)
                self._dots[self._release].set_label(':)')
        if len(self._tapped) == 2:
            pos1 = self._dots[self._targets[1]].get_xy()
            pos2 = self._dots[self._targets[2]].get_xy()
            self._dots[self._targets[1]].move(pos2)
            self._dots[self._targets[2]].move(pos1)
            self._lightbg.set_label(_("Good job! Now let's shake again."))
            self._shake = 'random2'
            self._next = self._shake_three
            # Since we don't end up in the button press
            GObject.timeout_add(500, self._next)
            for i in self._tapped:
                self._dots[i].set_label('')
        elif len(self._tapped) == 1:
            self._lightbg.set_label(
                _('You found one. Now find the other one.'))

    def _shake_three(self):
        self._next = self._fade_it
        self._shake = 'random2'
        GObject.timeout_add(100, read_accelerometer, self)
        self._pausing = True
        GObject.timeout_add(2000, self._clear_pause)

    def _fade_it(self):
        for dot in self._dots:
            if dot.type in [RED, YELLOW, BLUE]:
                self._fade_dot(dot, 1)
        self._lightbg.set_label(_('Going'))
        self._shake = 'random2'
        self._next = self._fade_it_again
        self._pausing = True
        GObject.timeout_add(2000, self._clear_pause)

    def _fade_it_again(self):
        for dot in self._dots:
            if dot.type in [RED, YELLOW, BLUE]:
                self._fade_dot(dot, 2)
        self._lightbg.set_label(_('Going') + '..')
        self._shake = 'random2'
        self._next = self._and_again
        self._pausing = True
        GObject.timeout_add(2000, self._clear_pause)

    def _and_again(self):
        for dot in self._dots:
            if dot.type in [RED, YELLOW, BLUE]:
                self._fade_dot(dot, 3)
        self._lightbg.set_label(_('Going') + '...')
        self._shake = 'random2'
        self._next = self._one_last_time
        self._pausing = True
        GObject.timeout_add(2000, self._clear_pause)

    def _one_last_time(self):
        for dot in self._dots:
            if dot.type in [RED, YELLOW, BLUE]:
                self._fade_dot(dot, 4)
        self._lightbg.set_label(_('Gone!'))
        self._shake = None
        self._next = self._yellow_dot
        GObject.timeout_add(500, self._next)

    def _fade_dot(self, dot, i):
        if i == 4:
            dot.set_shape(self._new_dot(self._colors[WHITE]))
        else:
            dot.set_shape(self._new_dot(self._colors[dot.type + i]))

    def _set_label(self, string):
        ''' Set the label in the toolbar or the window frame. '''
        self._activity.status.set_label(string)

    def motion_cb(self, x, y, z):
        if read_accelerometer.device_path is None:
            jiggle_factor = 5
        else:
            jiggle_factor = 3
        if self._shake is None:
            return
        elif self._shake in ['random', 'random2']:
            if self._shake == 'random2':
                jiggle_factor *= 2
            for dot in self._dots:
                if dot.type in [RED, YELLOW, BLUE]:
                    x += int(uniform(-jiggle_factor, jiggle_factor))
                    z += int(uniform(-jiggle_factor, jiggle_factor))
                    # Randomize z drift, which tends toward up...
                    if int(uniform(0, 2)) == 0:
                        z = -z
                    dot.move_relative((x, z))
        elif self._shake == 'align':
            docked = True
            yellow = 0
            red = 0
            blue = 0
            for dot in self._dots:
                if dot.type == YELLOW:
                    docked = self._dock_dot(dot, yellow + 1, 1, jiggle_factor,
                                            docked)
                    yellow += 1
                elif dot.type == RED:
                    docked = self._dock_dot(dot, red + 2, 2, jiggle_factor,
                                            docked)
                    red += 1
                elif dot.type == BLUE:
                    docked = self._dock_dot(dot, blue + 3, 3, jiggle_factor,
                                            docked)
                    blue += 1
            if docked:
                self._lightbg.set_label(_('Interesting.'))
                self._pausing = False
        elif self._shake == 'left':
            right = False
            for dot in self._dots:
                if dot.type in [RED, YELLOW, BLUE]:
                    pos = dot.get_xy()
                    if pos[0] < 0:
                        if pos[1] > self._height:
                            z = int(uniform(-20, 0))
                        elif pos[1] < 0:
                            z = int(uniform(0, 20))
                        x = int(uniform(0, 10))
                        dot.move_relative((x, z))
                    elif x < 0:
                        x += int(uniform(-10, 0))
                        if pos[1] > self._height:
                            z = int(uniform(-20, 0))
                        elif pos[1] < 0:
                            z = int(uniform(0, 20))
                        if pos[0] > -x:
                            dot.move_relative((x, z))
                    pos = dot.get_xy()
                    if pos[0] > 100:
                        right = True
            if not right:
                self._lightbg.set_label(_('Hmm'))
                self._pausing = False
        elif self._shake == 'right':
            left = False
            for dot in self._dots:
                if dot.type in [RED, YELLOW, BLUE]:
                    pos = dot.get_xy()
                    if pos[0] > self._width - self._dot_size:
                        if pos[1] > self._height:
                            z = int(uniform(-20, 0))
                        elif pos[1] < 0:
                            z = int(uniform(0, 20))
                        x = int(uniform(-10, 0))
                        dot.move_relative((x, z))
                    elif x < self._width - self._dot_size:
                        x += int(uniform(0, 10))
                        if pos[1] > self._height:
                            z = int(uniform(-20, 0))
                        elif pos[1] < 0:
                            z = int(uniform(0, 20))
                        if pos[0] < self._width - x - self._dot_size:
                            dot.move_relative((x, z))
                    pos = dot.get_xy()
                    if pos[0] < self._width - self._dot_size - 100:
                        left = True
            if not left:
                self._lightbg.set_label(_('Hmm'))
                self._pausing = False
        if not self._pausing:
            if self._next is not None:
                GObject.timeout_add(1000, self._next)
            else:
                self._lightbg.set_label('')
                self._shake = None
        GObject.timeout_add(100, read_accelerometer, self)
        return

    def _dock_dot(self, dot, n, m, jiggle_factor, docked):
        x = (self._dot_size + self._space) * n
        y = (self._dot_size + self._space) * m
        pos = dot.get_xy()
        dx = x - pos[0]
        dy = y - pos[1]
        if abs(dx) < 11 and abs(dy) < 11:
            dot.move((x, y))
            return docked
        else:
            if dx < 0:
                dx = max(-10, dx)
            elif dx > 0:
                dx = min(10, dx)
            if dy < 0:
                dy = max(-10, dy)
            elif dy > 0:
                dy = min(10, dy)
            dx += int(uniform(-jiggle_factor, jiggle_factor))
            dy += int(uniform(-jiggle_factor, jiggle_factor))
            dot.move_relative((dx, dy))
            return False

    def _button_press_cb(self, win, event):
        if self._shake is not None:
            return True
        win.grab_focus()
        x, y = map(int, event.get_coords())
        self._press = True
        self._release = None

        spr = self._sprites.find_sprite((x, y))
        if spr == None:
            return True

        self.last_spr = spr
        if self._rubbing:
            self._pausing = True
            if spr in self._dots:
                for target in self._targets:
                    if self._dots.index(spr) == target:
                        self._release = target
            GObject.timeout_add(1000, self._clear_pause)
        return True

    def _button_release_cb(self, win, event):
        if self._shake is not None:
            return True
        self._press = False
        self._release = None

        if self._pausing:
            self._lightbg.set_label(_('Rub a little longer.'))
            return True

        x, y = map(int, event.get_coords())
        spr = self._sprites.find_sprite((x, y))
        if spr.type is not None:
            if spr in self._dots:
                for target in self._targets:
                    if self._dots.index(spr) == target:
                        self._release = target
                        if self._next is not None:
                            GObject.timeout_add(200, self._next)

    def _smile(self):
        for dot in self._dots:
            dot.set_label(':)')

    def __draw_cb(self, canvas, cr):
        self._sprites.redraw_sprites(cr=cr)

    def _grid_to_dot(self, pos):
        ''' calculate the dot index from a column and row in the grid '''
        return pos[0] + pos[1] * NINE

    def _dot_to_grid(self, dot):
        ''' calculate the grid column and row for a dot '''
        return [dot % NINE, int(dot / NINE)]

    def _destroy_cb(self, win, event):
        Gtk.main_quit()

    def _new_dot(self, color):
        ''' generate a dot of a color color '''
        self._dot_cache = {}
        if not color in self._dot_cache:
            self._stroke = color
            self._fill = color
            self._svg_width = self._dot_size
            self._svg_height = self._dot_size
            pixbuf = svg_str_to_pixbuf(
                self._header() + \
                self._circle(self._dot_size / 2., self._dot_size / 2.,
                             self._dot_size / 2.) + \
                self._footer())

            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self._svg_width,
                                         self._svg_height)
            context = cairo.Context(surface)
            Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0)
            context.rectangle(0, 0, self._svg_width, self._svg_height)
            context.fill()
            self._dot_cache[color] = surface

        return self._dot_cache[color]

    def _line(self, vertical=True):
        ''' Generate a center line '''
        if vertical:
            self._svg_width = 3
            self._svg_height = self._height
            return svg_str_to_pixbuf(
                self._header() + \
                self._rect(3, self._height, 0, 0) + \
                self._footer())
        else:
            self._svg_width = self._width
            self._svg_height = 3
            return svg_str_to_pixbuf(
                self._header() + \
                self._rect(self._width, 3, 0, 0) + \
                self._footer())

    def _header(self):
        return '<svg\n' + 'xmlns:svg="http://www.w3.org/2000/svg"\n' + \
            'xmlns="http://www.w3.org/2000/svg"\n' + \
            'xmlns:xlink="http://www.w3.org/1999/xlink"\n' + \
            'version="1.1"\n' + 'width="' + str(self._svg_width) + '"\n' + \
            'height="' + str(self._svg_height) + '">\n'

    def _rect(self, w, h, x, y, color='#ffffff'):
        svg_string = '       <rect\n'
        svg_string += '          width="%f"\n' % (w)
        svg_string += '          height="%f"\n' % (h)
        svg_string += '          rx="%f"\n' % (0)
        svg_string += '          ry="%f"\n' % (0)
        svg_string += '          x="%f"\n' % (x)
        svg_string += '          y="%f"\n' % (y)
        svg_string += 'style="fill:%s;stroke:none;"/>\n' % (color)
        return svg_string

    def _circle(self, r, cx, cy):
        return '<circle style="fill:' + str(self._fill) + ';stroke:' + \
            str(self._stroke) + ';" r="' + str(r - 0.5) + '" cx="' + \
            str(cx) + '" cy="' + str(cy) + '" />\n'

    def _footer(self):
        return '</svg>\n'
class AbacusGeneric():
    """ A generic abacus: a frame, rods, and beads. """

    def __init__(self, abacus):
        """ Specify parameters that define the abacus """
        self.abacus = abacus
        self.set_parameters()
        self.create()

    def set_parameters(self):
        """ 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

    def create(self):
        """ Create and position the sprites that compose the abacus """

        # Width is a function of the number of rods
        self.frame_width = self.num_rods*(BWIDTH+BOFFSET)+FSTROKE*2

        # Height is a function of the number of beads
        if self.top_beads > 0:
            self.frame_height = (self.bot_beads+self.top_beads+5)*BHEIGHT +\
                                FSTROKE*2
        else:
            self.frame_height = (self.bot_beads+2)*BHEIGHT + FSTROKE*2

        # Draw the frame...
        x = (self.abacus.width-(self.frame_width*self.abacus.scale))/2
        y = (self.abacus.height-(self.frame_height*self.abacus.scale))/2
        _frame = _svg_header(self.frame_width, self.frame_height,
                             self.abacus.scale) +\
                 _svg_rect(self.frame_width, self.frame_height, 
                           FSTROKE/2, FSTROKE/2, 0, 0, "#000000", "#000000") +\
                 _svg_rect(self.frame_width-(FSTROKE*2), 
                           self.frame_height-(FSTROKE*2), 0, 0,
                           FSTROKE, FSTROKE, "#808080", "#000000") +\
                 _svg_footer()
        self.frame = Sprite(self.abacus.sprites, x, y, 
                            _svg_str_to_pixbuf(_frame))
        self.frame.type = 'frame'

        # and then the rods and beads.
        self.rods = []
        self.beads = []
        x += FSTROKE*self.abacus.scale
        y += FSTROKE*self.abacus.scale

        self.draw_rods_and_beads(x, y)

        # Draw the dividing bar...
        _bar = _svg_header(self.frame_width-(FSTROKE*2), BHEIGHT,
                           self.abacus.scale) +\
               _svg_rect(self.frame_width-(FSTROKE*2), BHEIGHT, 0, 0, 0, 0,
                         "#000000", "#000000") +\
               _svg_footer()
        if self.top_beads > 0:
            self.bar = Sprite(self.abacus.sprites, x,
                              y+(self.top_beads+2)*BHEIGHT*self.abacus.scale,
                              _svg_str_to_pixbuf(_bar))
        else:
            self.bar = Sprite(self.abacus.sprites, x,
                              y-FSTROKE*self.abacus.scale,
                              _svg_str_to_pixbuf(_bar))

        self.bar.type = 'frame'
        self.bar.set_label_color('white')

        # and finally, the mark.
        _mark = _svg_header(20, 15, self.abacus.scale) +\
                _svg_indicator() +\
                _svg_footer()
        dx = (BWIDTH+BOFFSET)*self.abacus.scale
        self.mark = Sprite(self.abacus.sprites, x+(self.num_rods-1)*dx,
                           y-((FSTROKE/2)*self.abacus.scale),
                           _svg_str_to_pixbuf(_mark))
        self.mark.type = 'mark'

    def draw_rods_and_beads(self, x, y):
        """ Draw the rods and beads """
        _white = _svg_header(BWIDTH, BHEIGHT, self.abacus.scale) +\
                 _svg_bead("#ffffff", "#000000") +\
                 _svg_footer()
        _yellow1 = _svg_header(BWIDTH, BHEIGHT, self.abacus.scale) +\
                 _svg_bead("#ffffcc", "#000000") +\
                 _svg_footer()
        _yellow2 = _svg_header(BWIDTH, BHEIGHT, self.abacus.scale) +\
                 _svg_bead("#ffff88", "#000000") +\
                 _svg_footer()
        _yellow3 = _svg_header(BWIDTH, BHEIGHT, self.abacus.scale) +\
                 _svg_bead("#ffff00", "#000000") +\
                 _svg_footer()
        self.colors = [_svg_str_to_pixbuf(_white),
                       _svg_str_to_pixbuf(_yellow1),
                       _svg_str_to_pixbuf(_yellow2),
                       _svg_str_to_pixbuf(_yellow3)]

        dx = (BWIDTH+BOFFSET)*self.abacus.scale
        bo =  (BWIDTH-BOFFSET)*self.abacus.scale/4
        ro =  (BWIDTH+5)*self.abacus.scale/2
        for i in range(self.num_rods):
            _rod = _svg_header(10, self.frame_height-(FSTROKE*2),
                               self.abacus.scale) +\
                   _svg_rect(10, self.frame_height-(FSTROKE*2), 0, 0, 0, 0,
                             ROD_COLORS[i%len(ROD_COLORS)], "#404040") +\
                   _svg_footer()
            self.rods.append(Sprite(self.abacus.sprites, x+i*dx+ro, y,
                                    _svg_str_to_pixbuf(_rod)))

            for b in range(self.top_beads):
                self.beads.append(Bead(Sprite(self.abacus.sprites, x+i*dx+bo,
                                              y+b*BHEIGHT*self.abacus.scale,
                                              self.colors[0]),
                                       2*BHEIGHT*self.abacus.scale,
                                       self.top_factor*(pow(self.base,
                                                        self.num_rods-i-1))))
            for b in range(self.bot_beads):
                if self.top_beads > 0:
                    self.beads.append(Bead(Sprite(self.abacus.sprites,
                                                  x+i*dx+bo,
                                                  y+(self.top_beads+5+b)*\
                                                  BHEIGHT*self.abacus.scale,
                                                  self.colors[0]),
                                           2*BHEIGHT*self.abacus.scale,
                                           pow(self.base,self.num_rods-i-1)))
                else:
                    self.beads.append(Bead(Sprite(self.abacus.sprites,
                                                  x+i*dx+bo,
                                                  y+(2+b)*BHEIGHT\
                                                  *self.abacus.scale,
                                                  self.colors[0]),
                                           2*BHEIGHT*self.abacus.scale,
                                           pow(self.base,self.num_rods-i-1)))

        for rod in self.rods:
            rod.type = "frame"

    def hide(self):
        """ Hide the rod, beads, mark, and frame. """
        for rod in self.rods:
            rod.hide()
        for bead in self.beads:
            bead.hide()
        self.bar.hide()
        self.frame.hide()
        self.mark.hide()

    def show(self):
        """ Show the rod, beads, mark, and frame. """
        self.frame.set_layer(FRAME_LAYER)
        for rod in self.rods:
            rod.set_layer(ROD_LAYER)
        for bead in self.beads:
            bead.show()
        self.bar.set_layer(BAR_LAYER)
        self.mark.set_layer(MARK_LAYER)

    def set_value(self, string):
        """ Set abacus to value in string """
        _logger.debug("restoring %s: %s" % (self.name, string))
        # String has two bytes per column.
        v = []
        for r in range(self.num_rods):
            v.append(0)

        # Convert string to column values.
        if len(string) == 2*self.num_rods:
            for i in range(self.num_rods):
                v[self.num_rods-i-1] = int(
                              string[2*self.num_rods-i*2-1:2*self.num_rods-i*2])
        else:
            _logger.debug("bad saved string %s (%d != 2*%d)" % (string,
                          len(string), self.num_rods))

        # Move the beads to correspond to column values.
        for r in range(self.num_rods):
            self.set_rod_value(r, v[r])

    def set_rod_value(self, r, v):
        """ Move beads on rod r to represent value v """
        bot = v % self.top_factor
        top = (v-bot)/self.top_factor
        top_bead_index = r*(self.top_beads+self.bot_beads)
        bot_bead_index = r*(self.top_beads+self.bot_beads)+self.top_beads

        # Clear the top.
        for i in range(self.top_beads):
            if self.beads[top_bead_index+i].get_state() == 1:
                self.beads[top_bead_index+i].move_up()
        # Clear the bottom.
        for i in range(self.bot_beads):
            if self.beads[bot_bead_index+i].get_state() == 1:
                self.beads[bot_bead_index+i].move_down()
        # Set the top.
        for i in range(top):
            self.beads[top_bead_index+self.top_beads-i-1].move_down()
        # Set the bottom
        for i in range(bot):
            self.beads[bot_bead_index+i].move_up()

    def value(self, count_beads=False):
        """ Return a string representing the value of each rod. """
        string = ''
        v = []
        for r in range(self.num_rods+1): # +1 for overflow
            v.append(0)

        # Tally the values on each rod.
        for i, bead in enumerate(self.beads):
            r = i/(self.top_beads+self.bot_beads)
            j = i % (self.top_beads+self.bot_beads)
            if bead.get_state() == 1:
                if j < self.top_beads:
                    v[r+1] += self.top_factor
                else:
                    v[r+1] += 1

        if count_beads:
            # Save the value associated with each rod as a 2-byte integer.
            for j in v[1:]:
                string += "%2d" % (j)
        else:
            sum = 0
            for bead in self.beads:
                sum += bead.get_value()
            string = str(sum)

        return(string)

    def label(self, string):
        """ Label the crossbar with the string. (Used with self.value) """
        self.bar.set_label(string)

    def move_mark(self, dx):
        """ Move indicator horizontally across the top of the frame. """
        self.mark.move_relative((dx, 0))

    def fade_colors(self):
        """ Reduce the saturation level of every bead. """
        for bead in self.beads:
            if bead.get_level() > 0:
                bead.set_color(self.colors[bead.get_level()-1])
                bead.set_level(bead.get_level()-1)

    def move_bead(self, sprite, dy):
        """ Move a bead (or beads) up or down a rod. """

        # find the bead associated with the sprite
        i = -1
        for bead in self.beads:
            if sprite == bead.spr:
                i = self.beads.index(bead)
                break
        if i == -1:
            print "bead not found"
            return

        b = i % (self.top_beads+self.bot_beads)
        if b < self.top_beads:
            if dy > 0 and bead.get_state() == 0:
                self.fade_colors()
                bead.set_color(self.colors[3])
                bead.move_down()
                # Make sure beads below this bead are also moved.
                for ii in range(self.top_beads-b):
                    if self.beads[i+ii].state == 0:
                        self.beads[i+ii].set_color(self.colors[3])
                        self.beads[i+ii].move_down()
            elif dy < 0 and bead.state == 1:
                self.fade_colors()
                bead.set_color(self.colors[3])
                bead.move_up()
                # Make sure beads above this bead are also moved.
                for ii in range(b+1):
                    if self.beads[i-ii].state == 1:
                        self.beads[i-ii].set_color(self.colors[3])
                        self.beads[i-ii].move_up()
        else:
            if dy < 0 and bead.state == 0:
                self.fade_colors()
                bead.set_color(self.colors[3])
                bead.move_up()
                # Make sure beads above this bead are also moved.
                for ii in range(b-self.top_beads+1):
                    if self.beads[i-ii].state == 0:
                        self.beads[i-ii].set_color(self.colors[3])
                        self.beads[i-ii].move_up()
            elif dy > 0 and bead.state == 1:
                self.fade_colors()
                bead.set_color(self.colors[3])
                bead.move_down()
                # Make sure beads below this bead are also moved.
                for ii in range(self.top_beads+self.bot_beads-b):
                    if self.beads[i+ii].state == 1:
                        self.beads[i+ii].set_color(self.colors[3])
                        self.beads[i+ii].move_down()
Пример #15
0
class Game():
    def __init__(self, canvas, parent=None, path=None):
        self._canvas = canvas
        self._parent = parent
        self._parent.show_all()
        self._path = path

        self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self._canvas.connect("draw", self.__draw_cb)
        self._canvas.connect("button-press-event", self._button_press_cb)

        self._width = Gdk.Screen.width()
        self._height = Gdk.Screen.height()
        self._scale = self._width / 1200.
        self._target = 0
        self._tries = 0

        self.level = 0

        self._picture_cards = []
        self._small_picture_cards = []
        self.food_cards = []
        self._group_cards = []
        self._quantity_cards = []
        self._balance_cards = []
        self._last_twenty = []
        self._background = None

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)
        self._background = Sprite(
            self._sprites, 0, 0,
            GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images', 'background.png'),
                self._width, self._height))
        self._background.set_layer(0)
        self._background.type = None
        self._background.hide()

        self.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            os.path.join(self._path, 'images', 'word-box.png'),
            int(350 * self._scale), int(100 * self._scale))

        for i in range(len(FOOD_DATA) / 4):
            FOOD.append([
                FOOD_DATA[i * 4 + NAME], FOOD_DATA[i * 4 + CALS],
                FOOD_DATA[i * 4 + GROUP], FOOD_DATA[i * 4 + IMAGE]
            ])
            self.food_cards.append(None)
            self._picture_cards.append(None)
            for j in range(6):
                self._small_picture_cards.append(None)
        self.allocate_food(0)

        x = 10
        dx, dy = self.food_cards[0].get_dimensions()

        y = 10
        for i in range(len(MYPLATE)):
            self.word_card_append(self._group_cards, self.pixbuf)
            self._group_cards[-1].type = i
            self._group_cards[-1].set_label(MYPLATE[i][0])
            self._group_cards[-1].move((x, y))
            y += int(dy * 1.25)

        y = 10
        for i in range(len(QUANTITIES)):
            self.word_card_append(self._quantity_cards, self.pixbuf)
            self._quantity_cards[-1].type = i
            self._quantity_cards[-1].set_label(QUANTITIES[i])
            self._quantity_cards[-1].move((x, y))
            y += int(dy * 1.25)

        y = 10
        for i in range(len(BALANCE)):
            self.word_card_append(self._balance_cards, self.pixbuf)
            self._balance_cards[-1].type = i
            self._balance_cards[-1].set_label(BALANCE[i])
            self._balance_cards[-1].move((x, y))
            y += int(dy * 1.25)

        self._smile = Sprite(
            self._sprites, int(self._width / 4), int(self._height / 4),
            GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images', 'correct.png'),
                int(self._width / 2), int(self._height / 2)))
        self._smile.set_label_attributes(36)
        self._smile.set_margins(10, 0, 10, 0)

        self._frown = Sprite(
            self._sprites, int(self._width / 4), int(self._height / 4),
            GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images', 'wrong.png'),
                int(self._width / 2), int(self._height / 2)))
        self._frown.set_label_attributes(36)
        self._frown.set_margins(10, 0, 10, 0)

        self.build_food_groups()

        self._all_clear()

    def allocate_food(self, i):
        self.picture_append(
            os.path.join(self._path, 'images', FOOD_DATA[i * 4 + IMAGE]), i)
        self.small_picture_append(
            os.path.join(self._path, 'images', FOOD_DATA[i * 4 + IMAGE]), i)
        self.word_card_append(self.food_cards, self.pixbuf, i)
        self.food_cards[i].type = i
        self.food_cards[i].set_label(FOOD_DATA[i * 4 + NAME])

    def word_card_append(self, card_list, pixbuf, i=-1):
        if i == -1:
            card_list.append(Sprite(self._sprites, 10, 10, pixbuf))
        else:
            card_list[i] = Sprite(self._sprites, 10, 10, pixbuf)
        card_list[i].set_label_attributes(36)
        card_list[i].set_margins(10, 0, 10, 0)
        card_list[i].hide()

    def picture_append(self, path, i=-1):
        spr = Sprite(
            self._sprites, int(self._width / 2.), int(self._height / 4.),
            GdkPixbuf.Pixbuf.new_from_file_at_size(path, int(self._width / 3.),
                                                   int(9 * self._width / 12.)))
        if i == -1:
            self._picture_cards.append(spr)
        else:
            self._picture_cards[i] = spr
        self._picture_cards[i].type = 'picture'
        self._picture_cards[i].hide()

    def small_picture_append(self, path, i=-1):
        x = int(self._width / 3.)
        y = int(self._height / 6.)
        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            path, int(self._width / 6.), int(3 * self._width / 8.))
        for j in range(6):  # up to 6 of each card
            if i == -1:
                self._small_picture_cards.append(
                    Sprite(self._sprites, x, y, pixbuf))
                self._small_picture_cards[-1].type = 'picture'
                self._small_picture_cards[-1].hide()
            else:
                self._small_picture_cards[i * 6 + j] = Sprite(
                    self._sprites, x, y, pixbuf)
                self._small_picture_cards[i * 6 + j].type = 'picture'
                self._small_picture_cards[i * 6 + j].hide()
            x += int(self._width / 6.)
            if j == 2:
                x = int(self._width / 3.)
                y += int(3 * self._width / 16.)

    def _all_clear(self):
        ''' Things to reinitialize when starting up a new game. '''
        for p in self._picture_cards:
            if p is not None:
                p.hide()
        for p in self._small_picture_cards:
            if p is not None:
                p.hide()
        for i, w in enumerate(self.food_cards):
            if w is not None:
                w.set_label_color('black')
                w.set_label(FOOD[i][NAME])
                w.hide()
        for i, w in enumerate(self._group_cards):
            w.set_label_color('black')
            w.set_label(MYPLATE[i][0])
            w.hide()
        for i, w in enumerate(self._quantity_cards):
            w.set_label_color('black')
            w.set_label(QUANTITIES[i])
            w.hide()
        for i, w in enumerate(self._balance_cards):
            w.set_label_color('black')
            w.set_label(BALANCE[i])
            w.hide()
        self._smile.hide()
        self._frown.hide()

        self._background.set_layer(1)

    def build_food_groups(self):
        self._my_plate = [[], [], [], []]
        for i, food in enumerate(FOOD):
            self._my_plate[MYPLATE[food[GROUP]][QUANT]].append(i)

    def new_game(self):
        ''' Start a new game. '''
        games = {
            0: self._name_that_food,
            1: self._name_that_food_group,
            2: self._compare_calories,
            3: self._how_much_to_eat,
            4: self._balanced_meal
        }
        self._all_clear()

        games[self.level]()

        self._frown.set_label('')
        self._smile.set_label('')
        self._tries = 0

    def _name_that_food(self):
        ''' Choose food cards and one matching food picture '''
        x = 10
        y = 10
        dx, dy = self.food_cards[0].get_dimensions()

        # Select some cards
        word_list = []
        for i in range(NCARDS):
            j = int(uniform(0, len(FOOD)))
            while j in word_list:
                j = int(uniform(0, len(FOOD)))
            word_list.append(j)

        # Show the word cards from the list
        for i in word_list:
            if self.food_cards[i] is None:
                self.allocate_food(i)
            self.food_cards[i].set_layer(100)
            self.food_cards[i].move((x, y))
            y += int(dy * 1.25)

        # Choose a random food image from the list and show it.
        self._target = self.food_cards[word_list[int(uniform(0, NCARDS))]].type
        while self._target in self._last_twenty:
            self._target = self.food_cards[word_list[int(uniform(
                0, NCARDS))]].type
        self._last_twenty.append(self._target)
        if len(self._last_twenty) > 20:
            self._last_twenty.remove(self._last_twenty[0])

        self._picture_cards[self._target].set_layer(100)

    def _name_that_food_group(self):
        ''' Show group cards and one food picture '''
        for i in range(len(MYPLATE)):
            self._group_cards[i].set_layer(100)

        # Choose a random food image and show it.
        self._target = int(uniform(0, len(FOOD)))
        if self.food_cards[self._target] is None:
            self.allocate_food(self._target)
        self._picture_cards[self._target].set_layer(100)

    def _compare_calories(self):
        ''' Choose food cards and compare the calories '''
        x = 10
        y = 10
        dx, dy = self.food_cards[0].get_dimensions()

        # Select some cards
        word_list = []
        for i in range(6):
            j = int(uniform(0, len(FOOD)))
            while j in word_list:
                j = int(uniform(0, len(FOOD)))
            word_list.append(j)
            if self.food_cards[j] is None:
                self.allocate_food(j)

        # Show the word cards from the list
        for i in word_list:
            self.food_cards[i].set_layer(100)
            self.food_cards[i].move((x, y))
            y += int(dy * 1.25)

        # Show food images
        self._target = word_list[0]
        for i in range(5):
            if FOOD[word_list[i + 1]][CALS] > FOOD[self._target][CALS]:
                self._target = word_list[i + 1]
        self._small_picture_cards[word_list[0] * 6].set_layer(100)
        self._small_picture_cards[word_list[1] * 6 + 1].set_layer(100)
        self._small_picture_cards[word_list[2] * 6 + 2].set_layer(100)
        self._small_picture_cards[word_list[3] * 6 + 3].set_layer(100)
        self._small_picture_cards[word_list[4] * 6 + 4].set_layer(100)
        self._small_picture_cards[word_list[5] * 6 + 5].set_layer(100)

    def _how_much_to_eat(self):
        ''' Show quantity cards and one food picture '''
        for i in range(len(QUANTITIES)):
            self._quantity_cards[i].set_layer(100)

        # Choose a random image from the list and show it.
        self._target = int(uniform(0, len(FOOD)))
        if self.food_cards[self._target] is None:
            self.allocate_food(self._target)
        self._picture_cards[self._target].set_layer(100)

    def _balanced_meal(self):
        ''' A well-balanced meal '''
        for i in range(2):
            self._balance_cards[i].set_layer(100)

        # Determine how many foods from each group
        n = [0, 0, 0, 0]
        n[0] = int(uniform(0, 2.5))
        n[1] = int(uniform(0, 3 - n[0]))
        n[2] = 3 - n[0] - n[1]
        n[3] = 6 - n[0] - n[1] - n[2]

        # Fill a plate with foods from different groups
        meal = []
        for i in range(n[0]):  # Sweets
            j = int(uniform(0, len(self._my_plate[0])))
            meal.append(self._my_plate[0][j])
        for i in range(n[1]):  # Dairy
            j = int(uniform(0, len(self._my_plate[1])))
            meal.append(self._my_plate[1][j])
        for i in range(n[2]):  # Protein and Fruits
            j = int(uniform(0, len(self._my_plate[2])))
            meal.append(self._my_plate[2][j])
        for i in range(n[3]):  # Veggies and Grains
            j = int(uniform(0, len(self._my_plate[3])))
            meal.append(self._my_plate[3][j])

        if n[0] < 2 and n[1] < 2 and n[2] < n[3]:
            self._target = 0  # Balanced meal
        else:
            self._target = 1

        for i in range(6):
            if self.food_cards[meal[i]] is None:
                self.allocate_food(meal[i])
        # Randomly position small cards
        self._small_picture_cards[meal[3] * 6].set_layer(100)
        self._small_picture_cards[meal[4] * 6 + 1].set_layer(100)
        self._small_picture_cards[meal[1] * 6 + 2].set_layer(100)
        self._small_picture_cards[meal[2] * 6 + 3].set_layer(100)
        self._small_picture_cards[meal[5] * 6 + 4].set_layer(100)
        self._small_picture_cards[meal[0] * 6 + 5].set_layer(100)

    def _button_press_cb(self, win, event):
        win.grab_focus()
        x, y = list(map(int, event.get_coords()))
        spr = self._sprites.find_sprite((x, y))
        if spr == None:
            return
        # We only care about clicks on word cards
        if type(spr.type) != int:
            return

        # Which card was clicked? Set its label to red.
        spr.set_label_color('red')
        label = spr.labels[0]
        spr.set_label(label)

        if self.level == 0:
            if spr.type == self._target:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self.food_cards[self._target].set_label_color('blue')
                label = self.food_cards[self._target].labels[0]
                self.food_cards[self._target].set_label(label)
        elif self.level == 1:
            i = FOOD[self._target][GROUP]
            if spr.type == i:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self._group_cards[i].set_label_color('blue')
                label = self._group_cards[i].labels[0]
                self._group_cards[i].set_label(label)
        elif self.level == 2:
            if spr.type == self._target:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self.food_cards[self._target].set_label_color('blue')
                label = self.food_cards[self._target].labels[0]
                self.food_cards[self._target].set_label(label)
        elif self.level == 3:
            i = MYPLATE[FOOD[self._target][GROUP]][QUANT]
            if spr.type == i:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self._quantity_cards[i].set_label_color('blue')
                label = self._quantity_cards[i].labels[0]
                self._quantity_cards[i].set_label(label)
        elif self.level == 4:
            if self._target == spr.type:
                self._smile.set_layer(200)
                self._tries = 3
            else:
                self._frown.set_layer(200)
                self._tries += 1
            if self._tries == 3:
                self._balance_cards[self._target].set_label_color('blue')
                label = self._balance_cards[self._target].labels[0]
                self._balance_cards[self._target].set_label(label)
        else:
            _logger.debug('unknown play level %d' % (self.level))

        # Play again
        if self._tries == 3:
            GObject.timeout_add(2000, self.new_game)
        else:
            GObject.timeout_add(1000, self._reset_game)
        return True

    def _reset_game(self):
        self._frown.hide()
        if self.level in [0, 2]:
            for i, w in enumerate(self.food_cards):
                w.set_label_color('black')
                w.set_label(FOOD[i][NAME])
        elif self.level == 1:
            for i, w in enumerate(self._group_cards):
                w.set_label_color('black')
                w.set_label(MYPLATE[i][0])
        elif self.level == 3:
            for i, w in enumerate(self._quantity_cards):
                w.set_label_color('black')
                w.set_label(QUANTITIES[i])
        elif self.level == 4:
            for i, w in enumerate(self._balance_cards):
                w.set_label_color('black')
                w.set_label(BALANCE[i])

    def __draw_cb(self, canvas, cr):
        self._sprites.redraw_sprites(cr=cr)

    def do_expose_event(self, event):
        ''' Handle the expose-event by drawing '''
        # Restrict Cairo to the exposed area
        cr = self._canvas.window.cairo_create()
        cr.rectangle(event.area.x, event.area.y, event.area.width,
                     event.area.height)
        cr.clip()
        # Refresh sprite list
        self._sprites.redraw_sprites(cr=cr)

    def _destroy_cb(self, win, event):
        Gtk.main_quit()
Пример #16
0
class Game():

    def __init__(self, canvas, parent=None, path=None):
        self._canvas = canvas
        self._parent = parent
        self._parent.show_all()
        self._path = path

        self._canvas.connect("draw", self.__draw_cb)
        self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self._canvas.connect("button-press-event", self._button_press_cb)
        self._canvas.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
        self._canvas.connect("motion-notify-event", self._mouse_move_cb)
        self._canvas.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
        self._canvas.connect('button-release-event', self._button_release_cb)
        self._canvas.add_events(Gdk.EventMask.KEY_PRESS_MASK)
        self._canvas.connect('key-press-event', self._keypress_cb)

        self._canvas.set_can_focus(True)
        self._canvas.grab_focus()

        self._width = Gdk.Screen.width()
        self._height = Gdk.Screen.height()
        self._scale = self._width / 1200.
        self._first_time = True
        self._loco_pos = (0, 0)
        self._loco_dim = (0, 0)
        self._loco_quadrant = 3
        self._drag_pos = [0, 0]
        self._counter = 0
        self._correct = 0
        self._timeout_id = None
        self._pause = 200
        self._press = None
        self._clicked = False
        self._dead_key = None
        self._waiting_for_delete = False
        self._waiting_for_enter = False
        self._seconds = 0
        self._timer_id = None
        self.level = 0
        self.score = 0

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)

        self._BG = ['background0.jpg', 'background0.jpg', 'background0.jpg',
                    'background1.jpg', 'background2.jpg', 'background2.jpg',
                    'background2.jpg']
        self._backgrounds = []
        for bg in self._BG:
            self._backgrounds.append(Sprite(
                    self._sprites, 0, 0, GdkPixbuf.Pixbuf.new_from_file_at_size(
                        os.path.join(self._path, 'images', bg),
                        self._width, self._height)))
            self._backgrounds[-1].type = 'background'
            self._backgrounds[-1].hide()

        self._panel = Sprite(
            self._sprites, int(400 * self._scale), int(400 * self._scale),
            GdkPixbuf.Pixbuf.new_from_file_at_size(
                os.path.join(self._path, 'images', 'ventana.png'),
                int(720 * self._scale), int(370 * self._scale)))
        self._panel.type = 'panel'
        self._panel.set_label(LABELS[0])
        self._panel.set_label_attributes(20)
        self._panel.hide()

        self._LOCOS = glob.glob(
                os.path.join(self._path, 'images', 'loco*.png'))
        self._loco_cards = []
        for loco in self._LOCOS:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale), int(208 * self._scale))
            self._loco_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._loco_cards[-1].type = 'loco'
        self._loco_dim = (int(150 * self._scale), int(208 * self._scale))

        self._MEN = glob.glob(
                os.path.join(self._path, 'images', 'man*.png'))
        self._man_cards = []
        for loco in self._MEN:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale), int(208 * self._scale))
            self._man_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._man_cards[-1].type = 'loco'

        self._TAUNTS = glob.glob(
                os.path.join(self._path, 'images', 'taunt*.png'))
        self._taunt_cards = []
        for loco in self._TAUNTS:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale), int(208 * self._scale))
            self._taunt_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._taunt_cards[-1].type = 'loco'

        self._GHOSTS = glob.glob(
                os.path.join(self._path, 'images', 'ghost*.png'))
        self._ghost_cards = []
        for loco in self._GHOSTS:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                loco, int(150 * self._scale), int(208 * self._scale))
            self._ghost_cards.append(Sprite(self._sprites, 0, 0, pixbuf))
            self._ghost_cards[-1].type = 'loco'

        self._sticky_cards = []
        self._loco_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            self._LOCOS[0], int(150 * self._scale), int(208 * self._scale))
        self._man_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            self._MEN[0], int(150 * self._scale), int(208 * self._scale))
        self._ghost_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            self._GHOSTS[0], int(150 * self._scale), int(208 * self._scale))
        for i in range(len(MSGS[1])):  # Check re i18n
            self._sticky_cards.append(Sprite(self._sprites, 0, 0,
                                             self._loco_pixbuf))
            self._sticky_cards[-1].type = 'loco'
            self._sticky_cards[-1].set_label_attributes(24,
                                                        vert_align='bottom')

        self._all_clear()

    def _time_increment(self):
        ''' Track seconds since start_time. '''
        self._seconds = int(GObject.get_current_time() - self._start_time)
        self.timer_id = GObject.timeout_add(1000, self._time_increment)

    def _timer_reset(self):
        ''' Reset the timer for each level '''
        self._start_time = GObject.get_current_time()
        if self._timer_id is not None:
            GObject.source_remove(self._timer_id)
            self._timer_id = None
        self.score += self._seconds
        self._time_increment()

    def _all_clear(self):
        ''' Things to reinitialize when starting up a new game. '''
        for p in self._loco_cards:
            p.hide()
        for p in self._man_cards:
            p.hide()
        for p in self._taunt_cards:
            p.hide()
        for p in self._ghost_cards:
            p.hide()
        for p in self._sticky_cards:
            p.set_shape(self._loco_pixbuf)
            p.set_label('')
            p.set_label_color('white')
            p.hide()
        self._backgrounds[self.level].set_layer(BG_LAYER)

    def _show_time(self):
        self.level = 0
        self._all_clear()
        x = int(self._width / 4.)
        y = int(self._height / 8.)
        for i in range(len(str(self.score))):
            self._sticky_cards[i].move((x, y))
            self._sticky_cards[i].set_layer(LOCO_LAYER)
            self._sticky_cards[i].set_label(str(self.score)[i])
            x += int(self._loco_dim[0] / 2.)
        self.score = 0
        self._parent.unfullscreen()
        GObject.idle_add(play_audio_from_file, self, os.path.join(
                self._path, 'sounds', 'sonar.ogg'))
        GObject.timeout_add(5000, self.new_game, True)

    def new_game(self, first_time):
        ''' Start a new game at the current level. '''
        self._first_time = first_time
        self._clicked = False

        # It may be time to advance to the next level.
        if (self.level == 6 and self._counter == len(MSGS)) or \
           self._counter > 4:
            self._first_time = True
            self.level += 1
            self._counter = 0
            self._correct = 0
            self._pause = 200
            if self.level == len(self._backgrounds):
                self._show_time()
                return

        self._all_clear()

        if self._first_time:
            # Every game starts by putting up a panel with instructions
            # The panel disappears on mouse movement
            self._panel.set_label(LABELS[self.level])
            self._panel.set_layer(PANEL_LAYER)
            play_audio_from_file(self, os.path.join(
                    self._path, 'sounds', 'drip.ogg'))
            self._timer_reset()

        if self.level == 0:
            # Choose a random location for the Loco
            self._loco_quadrant += int(uniform(1, 4))
            self._loco_quadrant %= 4
            x, y = self._quad_to_xy(self._loco_quadrant)
            play_audio_from_file(self, os.path.join(
                    self._path, 'sounds', 'bark.ogg'))
            self._loco_cards[0].move((x, y))
            self._loco_pos = (x, y)
        elif self.level == 1:
            play_audio_from_file(self, os.path.join(
                    self._path, 'sounds', 'glass.ogg'))
        elif self.level == 2:
            play_audio_from_file(self, os.path.join(
                    self._path, 'sounds', 'glass.ogg'))
            # Place some Locos on the canvas
            for i in range(self._counter + 1):
                self._loco_quadrant += int(uniform(1, 4))
                self._loco_quadrant %= 4
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
        elif self.level == 3:
            play_audio_from_file(self, os.path.join(
                    self._path, 'sounds', 'bark.ogg'))
            # Place some Locos on the left-side of the canvas
            for i in range(self._counter + 1):
                self._loco_quadrant = int(uniform(2, 4))
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
        elif self.level == 4:
            # Place some Locos on the canvas with letters as labels
            # Just lowercase
            for i in range(self._counter + 1):
                self._loco_quadrant = int(uniform(0, 4))
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
                self._sticky_cards[i].set_label(
                    ALPHABETLC[int(uniform(0, len(ALPHABETLC)))])
        elif self.level == 5:
            # Place some Locos on the canvas with letters as labels
            # Uppercase
            for i in range(self._counter + 1):
                self._loco_quadrant = int(uniform(0, 4))
                x, y = self._quad_to_xy(self._loco_quadrant)
                self._sticky_cards[i].move((x, y))
                self._sticky_cards[i].type = 'loco'
                self._sticky_cards[i].set_layer(LOCO_LAYER)
                self._sticky_cards[i].set_label(
                    ALPHABETUC[int(uniform(0, len(ALPHABETUC)))])
        elif self.level == 6:
            x = 0
            y = 0
            c = 0
            for i in range(len(MSGS[self._counter])):
                if MSGS[self._counter][i] == ' ':
                    y += self._loco_dim[1]
                    x = 0
                else:
                    self._sticky_cards[c].move((x, y))
                    self._sticky_cards[c].type = i
                    self._sticky_cards[c].set_layer(LOCO_LAYER)
                    self._sticky_cards[c].set_label(MSGS[self._counter][i])
                    c += 1
                    x += int(self._loco_dim[0] / 2.)

        if self.level in [0, 1]:
            self._loco_quadrant += int(uniform(1, 4))
            self._loco_quadrant %= 4
            x, y = self._quad_to_xy(self._loco_quadrant)
            if self.level == 0:
                self._move_loco(x, y, 0)
            else:
                self._taunt(x, y, 0)

    def _quad_to_xy(self, q):
        x = int(max(0, (self._width / 2.) * uniform(0, 1) - self._loco_dim[0]))
        if q in [0, 1]:
            x += int(self._width / 2.)
        y = int(max(0, (self._height / 2.) * uniform(0, 1) - self._loco_dim[1]))
        if q in [1, 2]:
            y += int(self._height / 2.)
        return x, y

    def _taunt(self, x, y, i):
        n = len(self._taunt_cards)
        self._taunt_cards[(i + 1) % n].hide()
        if self._clicked:
            self._timeout_id = None
            return True
        else:
            self._taunt_cards[i % n].move((x, y))
            self._taunt_cards[i % n].set_layer(LOCO_LAYER)
            self._timeout_id = GObject.timeout_add(
                200, self._taunt, x, y, i + 1)

    def _move_loco(self, x, y, i):
        j = (i + 1) % len(self._loco_cards)
        cx, cy = self._loco_cards[i].get_xy()
        dx = cx - x
        dy = cy - y
        if dx * dx + dy * dy < 100:
            self._loco_cards[j].move((x, y))
            self._loco_pos = (x, y)
            self._loco_cards[j].hide()
            self._loco_cards[i].hide()
            self._man_cards[0].move((x, y))
            self._man_cards[0].set_layer(LOCO_LAYER)
            self._timeout_id = None
            if self._pause > 50:
                self._pause -= 10
            return True
        else:
            if dx > 0:
                cx -= 5
            elif dx < 0:
                cx += 5
            if dy > 0:
                cy -= 5
            elif dy < 0:
                cy += 5
            self._loco_cards[j].move((cx, cy))
            self._loco_pos = (cx, cy)
            self._loco_cards[j].set_layer(LOCO_LAYER)
            self._loco_cards[i].hide()
            self._timeout_id = GObject.timeout_add(
                self._pause, self._move_loco, x, y, j)

    def _keypress_cb(self, area, event):
        ''' Keypress '''
        # Games 4, 5, and 6 use the keyboard
        print 'keypress event'
        if self.level not in [4, 5, 6]:
            return True
        k = Gdk.keyval_name(event.keyval)
        u = Gdk.keyval_to_unicode(event.keyval)

        if self._waiting_for_enter:
            if k == 'Return':
                self._waiting_for_enter = False
                self._panel.hide()
                self._counter += 1
                self._correct = 0
                GObject.timeout_add(1000, self.new_game, False)
            return

        if k in NOISE_KEYS or k in WHITE_SPACE:
            return True

        if self.level == 6 and self._waiting_for_delete:
            if k in ['BackSpace', 'Delete']:
                self._waiting_for_delete = False
                self._sticky_cards[self._correct].set_label_color('white')
                self._sticky_cards[self._correct].set_label(
                    MSGS[self._counter][
                        self._sticky_cards[self._correct].type])
                self._panel.hide()
                self._panel.set_label_color('black')
            return

        if k[0:5] == 'dead_':
            self._dead_key = k[5:]
            return

        if self.level == 6:
            n = len(MSGS[self._counter])
        else:
            n = self._counter + 1

        if self.level == 6:
            i = self._correct
            if self._dead_key is not None:
                k = DEAD_DICTS[DEAD_KEYS.index(self._dead_key)][k]
                self._dead_key = None
            elif k in PUNCTUATION:
                k = PUNCTUATION[k]
            elif k in SPECIAL:
                k = SPECIAL[k]
            elif len(k) > 1:
                return True
            if self._sticky_cards[i].labels[0] == k:
                self._sticky_cards[i].set_label_color('blue')
                self._sticky_cards[i].set_label(k)
                self._correct += 1
            else:
                self._sticky_cards[i].set_label_color('red')
                self._sticky_cards[i].set_label(k)
                self._panel.set_label_color('red')
                self._panel.set_label(ALERTS[1])
                self._panel.set_layer(PANEL_LAYER)
                self._waiting_for_delete = True
                play_audio_from_file(self, os.path.join(
                        self._path, 'sounds', 'glass.ogg'))
        else:
            for i in range(n):
                if self._sticky_cards[i].labels[0] == k:
                    self._sticky_cards[i].set_label('')
                    self._sticky_cards[i].hide()
                    break

        # Test for end condition
        if self.level == 6 and \
           self._correct == len(MSGS[self._counter]) - \
                            MSGS[self._counter].count(' '):
            c = 0
            for i in range(len(MSGS[self._counter])):
                if MSGS[self._counter][i] == ' ':
                    continue
                elif MSGS[self._counter][i] != self._sticky_cards[c].labels[0]:
                    return True
                c += 1
            self._panel.set_label(ALERTS[0])
            self._panel.set_layer(PANEL_LAYER)
            self._waiting_for_enter = True
            GObject.idle_add(play_audio_from_file, self, os.path.join(
                    self._path, 'sounds', 'drip.ogg'))
            return
        else:
            for i in range(n):
                if len(self._sticky_cards[i].labels[0]) > 0:
                    return True
        self._counter += 1
        self._correct = 0
        GObject.timeout_add(1000, self.new_game, False)

    def _mouse_move_cb(self, win, event):
        ''' Move the mouse. '''
        # Games 0, 3, 4, and 5 use move events
        x, y = map(int, event.get_coords())
        if self._seconds > 1:
            self._panel.hide()
        if not self._clicked and self.level == 0:
            # For Game 0, see if the mouse is on the Loco
            dx = x - self._loco_pos[0] - self._loco_dim[0] / 2.
            dy = y - self._loco_pos[1] - self._loco_dim[1] / 2.
            if dx * dx + dy * dy < 200:
                self._clicked = True
                if self._timeout_id is not None:
                    GObject.source_remove(self._timeout_id)
                # Play again
                self._all_clear()
                self._man_cards[0].move((x - int(self._loco_dim[0] / 2.),
                                         y - int(self._loco_dim[1] / 2.)))
                self._man_cards[0].set_layer(LOCO_LAYER)
                self._correct += 1
                self._counter += 1
                GObject.timeout_add(1000, self.new_game, False)
        elif self.level in [4, 5]:
            # For Game 4 and 5, we allow dragging
            if self._press is None:
                self._drag_pos = [0, 0]
                return True
            dx = x - self._drag_pos[0]
            dy = y - self._drag_pos[1]
            self._press.move_relative((dx, dy))
            self._drag_pos = [x, y]
        elif self.level == 3:
            # For Game 3, we are dragging
            if self._press is None:
                self._drag_pos = [0, 0]
                return True
            dx = x - self._drag_pos[0]
            dy = y - self._drag_pos[1]
            self._press.move_relative((dx, dy))
            self._drag_pos = [x, y]
            if x > self._width / 2.:
                self._press.set_shape(self._man_pixbuf)
                if self._press.type == 'loco':
                    self._correct += 1
                    self._press.type = 'man'
        return True

    def _button_release_cb(self, win, event):
        # Game 3 uses release
        if self.level == 3:
            # Move to release
            if self._correct == self._counter + 1:
                self._counter += 1
                self._correct = 0
                GObject.timeout_add(2000, self.new_game, False)
        self._press = None
        self._drag_pos = [0, 0]
        return True

    def _button_press_cb(self, win, event):
        self._press = None
        x, y = map(int, event.get_coords())
        if self.level == 0:
            return
        spr = self._sprites.find_sprite((x, y))
        if spr is None:
            return
        if spr.type != 'loco':
            return
        if self.level < 2 and self._timeout_id is None:
            return
        if self._clicked:
            return

        # Games 1, 2, and 3 involve clicks; Games 4 and 5 allow click to drag
        if self.level == 1:
            self._all_clear()
            self._man_cards[0].move((x - int(self._loco_dim[0] / 2.),
                                     y - int(self._loco_dim[1] / 2.)))
            self._man_cards[0].set_layer(LOCO_LAYER)
            self._clicked = True
            self._counter += 1
            self._correct += 1
            if self._timeout_id is not None:
                GObject.source_remove(self._timeout_id)
            GObject.timeout_add(2000, self.new_game, False)
        elif self.level == 2:
            spr.set_shape(self._ghost_pixbuf)
            spr.type = 'ghost'
            if self._correct == self._counter:
                self._counter += 1
                self._correct = 0
                GObject.timeout_add(2000, self.new_game, False)
            else:
                self._correct += 1
        elif self.level in [3, 4, 5]:
            # In Games 4 and 5, dragging is used to remove overlaps
            self._press = spr
            self._drag_pos = [x, y]
        return True

    def __draw_cb(self, canvas, cr):
        self._sprites.redraw_sprites(cr=cr)

    def do_expose_event(self, event):
        ''' Handle the expose-event by drawing '''
        # Restrict Cairo to the exposed area
        cr = self._canvas.window.cairo_create()
        cr.rectangle(event.area.x, event.area.y,
                event.area.width, event.area.height)
        cr.clip()
        # Refresh sprite list
        self._sprites.redraw_sprites(cr=cr)

    def _destroy_cb(self, win, event):
        Gtk.main_quit()
Пример #17
0
class Yupana():

    def __init__(self, canvas, parent=None, colors=['#A0FFA0', '#FF8080']):
        self._activity = parent
        self._colors = ['#FFFFFF']
        self._colors.append(colors[0])
        self._colors.append(colors[1])
        self._colors.append('#000000')

        self._canvas = canvas
        if parent is not None:
            parent.show_all()
            self._parent = parent

        self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self._canvas.connect("draw", self.__draw_cb)
        self._canvas.connect("button-press-event", self._button_press_cb)

        self._width = Gdk.Screen.width()
        self._height = Gdk.Screen.height() - (GRID_CELL_SIZE * 1.5)
        self._scale = self._width / (20 * DOT_SIZE * 1.1)
        self._dot_size = int(DOT_SIZE * self._scale)
        self._space = int(self._dot_size / 5.)
        self.we_are_sharing = False
        self._sum = 0
        self._mode = 'ten'
        self.custom = [1, 1, 1, 1, 10]

        # Generate the sprites we'll need...
        self._sprites = Sprites(self._canvas)
        Sprite(self._sprites, 0, 0, self._box(self._width, self._height,
                                              color=colors[1]))

        self._number_box = Sprite(self._sprites, 0, 0, self._box(
                self._width, 2 * self._dot_size, color=colors[1]))
        self._number_box.set_label_attributes(48)

        self._dots = []
        for p in range(SIX):
            y = self._height - self._space
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int(p * self._width / 6) + self._space
            y -= self._dot_size
            for d in range(3):  # bottom of fives row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space
            x = int((p * self._width / 6.) + self._dot_size / 2.) + self._space
            y -= self._dot_size + self._space
            for d in range(2):  # top of fives row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int((p * self._width / 6.) + self._dot_size / 2.) + self._space
            y -= self._dot_size
            for d in range(2):  # bottom of threes row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space
            x = int((p * self._width / 6.) + self._dot_size) + self._space
            y -= self._dot_size + self._space
            for d in range(1):  # top of threes row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int((p * self._width / 6.) + self._dot_size / 2.) + self._space
            y -= self._dot_size
            for d in range(2):  # twos row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

            x = int((p * self._width / 6.) + self._dot_size) + self._space
            y -= self._dot_size
            for d in range(1):  # ones row
                self._dots.append(
                    Sprite(self._sprites, x, y,
                           self._new_dot(self._colors[0])))
                self._dots[-1].type = 0  # not set
                # self._dots[-1].set_label_color('white')
                x += self._dot_size + self._space

            y -= self._dot_size
            Sprite(self._sprites, 0, y, self._line(vertical=False))

        for p in range(SIX - 1):
            x = int((p + 1) * self._width / 6)
            Sprite(self._sprites, x - 1, y,
                   self._line(vertical=True))

        # and initialize a few variables we'll need.
        self._all_clear()

    def _all_clear(self):
        ''' Things to reinitialize when starting up a new yupana. '''
        self._sum = 0
        for dot in self._dots:
            if dot.type > 0:
                dot.type = 0
                dot.set_shape(self._new_dot(self._colors[0]))
            dot.set_label('')
        self._set_label(str(self._sum))

    def _initiating(self):
        return self._activity.initiating

    def new_yupana(self, mode=None):
        ''' Create a new yupana. '''
        self._all_clear()

        if mode is not None:
            self._mode = mode
            o = (SIX - 1) * (TEN + 1)  # only label units 
            if mode == 'ten':
                for i in range(TEN + 1):
                    self._dots[o + i].set_label('1')
                self._dots[o - 1].set_label('10')
            elif mode == 'twenty':
                for i in range(TEN + 1):
                    if i in [7, 10]:
                        self._dots[o + i].set_label('1')
                    else:
                        self._dots[o + i].set_label('2')
                self._dots[o - 1].set_label('20')
            elif mode == 'factor':
                for i in range(TEN + 1):
                    if i in [10]:
                        self._dots[o + i].set_label('1')
                    elif i in [8, 9]:
                        self._dots[o + i].set_label('2')
                    elif i in [5, 6, 7]:
                        self._dots[o + i].set_label('3')
                    else:
                        self._dots[o + i].set_label('5')
                self._dots[o - 1].set_label('10')
            elif mode == 'fibonacci':
                for i in range(TEN + 1):
                    if i in [10]:
                        self._dots[o + i].set_label('1')
                    elif i in [8, 9]:
                        self._dots[o + i].set_label('2')
                    elif i in [5, 6, 7]:
                        self._dots[o + i].set_label('5')
                    else:
                        self._dots[o + i].set_label('20')
                self._dots[o - 1].set_label('60')
            else:  # custom
                for i in range(TEN + 1):
                    if i in [10]:
                        self._dots[o + i].set_label(str(self.custom[0]))
                    elif i in [8, 9]:
                        self._dots[o + i].set_label(str(self.custom[1]))
                    elif i in [5, 6, 7]:
                        self._dots[o + i].set_label(str(self.custom[2]))
                    else:
                        self._dots[o + i].set_label(str(self.custom[3]))
                self._dots[o - 1].set_label(str(self.custom[4]))

        if self.we_are_sharing:
            _logger.debug('sending a new yupana')
            self._parent.send_new_yupana()

    def restore_yupana(self, dot_list):
        ''' Restore a yumpana from the Journal or share '''
        for i, dot in enumerate(dot_list):
            self._dots[i].type = dot
            self._dots[i].set_shape(self._new_dot(
                    self._colors[self._dots[i].type]))
            if self._dots[i].type == 1:
                self._sum += self._calc_bead_value(i)
        self._set_label(str(self._sum))

    def save_yupana(self):
        ''' Return dot list and orientation for saving to Journal or
        sharing '''
        dot_list = []
        for dot in self._dots:
            dot_list.append(dot.type)
        return [self._mode, dot_list]

    def _set_label(self, string):
        ''' Set the label in the toolbar or the window frame. '''
        self._number_box.set_label(string)
        # self._activity.status.set_label(string)

    def _button_press_cb(self, win, event):
        win.grab_focus()
        x, y = map(int, event.get_coords())

        spr = self._sprites.find_sprite((x, y))
        if spr == None:
            return

        if spr.type is not None:
            spr.type += 1
            spr.type %= 2
            spr.set_shape(self._new_dot(self._colors[spr.type]))

            if self.we_are_sharing:
                _logger.debug('sending a click to the share')
                self._parent.send_dot_click(self._dots.index(spr),
                                            spr.type)

            if spr.type == 1:
                self._sum += self._calc_bead_value(self._dots.index(spr))
            else:
                self._sum -= self._calc_bead_value(self._dots.index(spr))
            self._set_label(str(self._sum))
        return True

    def _calc_bead_value(self, i):
        ''' Calculate a bead value based on the index and the mode '''
        e = 5 - i / (TEN + 1)
        m = i % 11
        if self._mode == 'ten':
            return 10 ** e
        elif self._mode == 'twenty':
            if m in [7, 10]:
                return 20 ** e
            else:
                return (20 ** e) * 2
        elif self._mode == 'factor':
            if m in [10]:
                return 10 ** e
            elif m in [8, 9]:
                return (10 ** e) * 2
            elif m in [5, 6, 7]:
                return (10 ** e) * 3
            else:
                return (10 ** e) * 5
        elif self._mode == 'fibonacci':
            if m in [10]:
                return 60 ** e
            elif m in [8, 9]:
                return (60 ** e) * 2
            elif m in [5, 6, 7]:
                return (60 ** e) * 5
            else:
                return (60 ** e) * 20
        else:  # custom
            if m in [10]:
                return (self.custom[4] ** e) * self.custom[0]
            elif m in [8, 9]:
                return (self.custom[4] ** e) * self.custom[1]
            elif m in [5, 6, 7]:
                return (self.custom[4] ** e) * self.custom[2]
            else:
                return (self.custom[4] ** e) * self.custom[3]


    def remote_button_press(self, dot, color):
        ''' Receive a button press from a sharer '''
        self._dots[dot].type = color
        self._dots[dot].set_shape(self._new_dot(self._colors[color]))

    def set_sharing(self, share=True):
        _logger.debug('enabling sharing')
        self.we_are_sharing = share

    def _grid_to_dot(self, pos):
        ''' calculate the dot index from a column and row in the grid '''
        return pos[0] + pos[1] * TEN

    def _dot_to_grid(self, dot):
        ''' calculate the grid column and row for a dot '''
        return [dot % TEN, int(dot / TEN)]

    def __draw_cb(self, canvas, cr):
	self._sprites.redraw_sprites(cr=cr)

    def do_expose_event(self, event):
        ''' Handle the expose-event by drawing '''
        # Restrict Cairo to the exposed area
        cr = self._canvas.window.cairo_create()
        cr.rectangle(event.area.x, event.area.y,
                event.area.width, event.area.height)
        cr.clip()
        # Refresh sprite list
        self._sprites.redraw_sprites(cr=cr)

    def _destroy_cb(self, win, event):
        Gtk.main_quit()

    def _new_dot(self, color):
        ''' generate a dot of a color color '''
        def darken(color):
            ''' return a darker color than color '''
            gdk_fill_color = Gdk.color_parse(self._fill)
            gdk_fill_dark_color = Gdk.Color(
                int(gdk_fill_color.red * 0.5),
                int(gdk_fill_color.green * 0.5),
                int(gdk_fill_color.blue * 0.5)).to_string()
            return str(gdk_fill_dark_color)

        self._dot_cache = {}
        if not color in self._dot_cache:
            self._stroke = color
            self._fill = color
            self._fill_dark = darken(color)
            self._svg_width = self._dot_size
            self._svg_height = self._dot_size
            if color in ['#FFFFFF', '#000000']:
                pixbuf = svg_str_to_pixbuf(
                    self._header() + \
                    self._circle(self._dot_size / 2., self._dot_size / 2.,
                                 self._dot_size / 2.) + \
                    self._footer())
            else:
                pixbuf = svg_str_to_pixbuf(
                    self._header() + \
                    self._def(self._dot_size) + \
                    self._gradient(self._dot_size / 2., self._dot_size / 2.,
                                 self._dot_size / 2.) + \
                    self._footer())

            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
                                         self._svg_width, self._svg_height)
            context = cairo.Context(surface)
	    Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0)
            context.rectangle(0, 0, self._svg_width, self._svg_height)
            context.fill()
            self._dot_cache[color] = surface

        return self._dot_cache[color]

    def _line(self, vertical=True):
        ''' Generate a center line '''
        if vertical:
            self._svg_width = 3
            self._svg_height = self._dot_size * 10 + self._space * 2
            return svg_str_to_pixbuf(
                self._header() + \
                self._rect(3, self._dot_size * 10 + self._space * 2, 0, 0) + \
                self._footer())
        else:
            self._svg_width = self._width
            self._svg_height = 3
            return svg_str_to_pixbuf(
                self._header() + \
                self._rect(self._width, 3, 0, 0) + \
                self._footer())

    def _box(self, w, h, color='white'):
        ''' Generate a box '''
        self._svg_width = w
        self._svg_height = h
        return svg_str_to_pixbuf(
                self._header() + \
                self._rect(self._svg_width, self._svg_height, 0, 0,
                           color=color) + \
                self._footer())

    def _header(self):
        return '<svg\n' + 'xmlns:svg="http://www.w3.org/2000/svg"\n' + \
            'xmlns="http://www.w3.org/2000/svg"\n' + \
            'xmlns:xlink="http://www.w3.org/1999/xlink"\n' + \
            'version="1.1"\n' + 'width="' + str(self._svg_width) + '"\n' + \
            'height="' + str(self._svg_height) + '">\n'

    def _rect(self, w, h, x, y, color='black'):
        svg_string = '       <rect\n'
        svg_string += '          width="%f"\n' % (w)
        svg_string += '          height="%f"\n' % (h)
        svg_string += '          rx="%f"\n' % (0)
        svg_string += '          ry="%f"\n' % (0)
        svg_string += '          x="%f"\n' % (x)
        svg_string += '          y="%f"\n' % (y)
        if color == 'black':
            svg_string += 'style="fill:#000000;stroke:#000000;"/>\n'
        elif color == 'white':
            svg_string += 'style="fill:#ffffff;stroke:#ffffff;"/>\n'
        else:
            svg_string += 'style="fill:%s;stroke:%s;"/>\n' % (color, color)
        return svg_string

    def _circle(self, r, cx, cy):
        scale = (DOT_SIZE * self._scale) / 55.
        return '\
  <g transform="matrix(%f,0,0,%f,0,0)">\
  <path\
     d="m 35.798426,4.2187227 c -2.210658,0.9528967 -4.993612,-0.9110169 -7.221856,0 C 23.805784,6.1692574 20.658687,10.945585 17.543179,15.051507 13.020442,21.012013 7.910957,27.325787 6.7103942,34.711004 6.0558895,38.737163 6.434461,43.510925 8.917073,46.747431 c 3.604523,4.699107 15.24614,7.62307 16.048569,7.62307 0.802429,0 8.366957,0.46766 12.036427,-1.203642 2.841316,-1.294111 5.173945,-3.766846 6.820641,-6.419428 2.543728,-4.097563 3.563068,-9.062928 4.21275,-13.841891 C 49.107723,25.018147 48.401726,15.967648 47.433639,9.0332932 47.09109,6.5796321 43.508442,7.2266282 42.329009,5.7211058 41.256823,4.3524824 42.197481,1.860825 40.813604,0.80840168 40.384481,0.48205899 39.716131,0.42556727 39.208747,0.60779459 37.650593,1.1674066 37.318797,3.5633724 35.798426,4.2187227 z"\
     style="fill:none;fill-opacity:1;stroke:%s;stroke-width:3.0" />\
</g>' % (
            scale, scale, self._colors[1])

    def _gradient(self, r, cx, cy):
        scale = (DOT_SIZE * self._scale) / 55.
        return '\
  <defs>\
    <linearGradient\
       id="linearGradient3769">\
      <stop\
         id="stop3771"\
         style="stop-color:#ffff00;stop-opacity:1"\
         offset="0" />\
      <stop\
         id="stop3773"\
         style="stop-color:#ffff00;stop-opacity:0"\
         offset="1" />\
    </linearGradient>\
    <linearGradient\
       x1="10.761448"\
       y1="41.003559"\
       x2="56.70686"\
       y2="41.003559"\
       id="linearGradient2999"\
       xlink:href="#linearGradient3769"\
       gradientUnits="userSpaceOnUse"\
       gradientTransform="matrix(0.93094239,0,0,0.93094239,-3.9217825,-2.4013121)" />\
  </defs>\
  <g transform="matrix(%f,0,0,%f,0,0)">\
  <path\
     d="m 35.798426,4.2187227 c -2.210658,0.9528967 -4.993612,-0.9110169 -7.221856,0 C 23.805784,6.1692574 20.658687,10.945585 17.543179,15.051507 13.020442,21.012013 7.910957,27.325787 6.7103942,34.711004 6.0558895,38.737163 6.434461,43.510925 8.917073,46.747431 c 3.604523,4.699107 15.24614,7.62307 16.048569,7.62307 0.802429,0 8.366957,0.46766 12.036427,-1.203642 2.841316,-1.294111 5.173945,-3.766846 6.820641,-6.419428 2.543728,-4.097563 3.563068,-9.062928 4.21275,-13.841891 C 49.107723,25.018147 48.401726,15.967648 47.433639,9.0332932 47.09109,6.5796321 43.508442,7.2266282 42.329009,5.7211058 41.256823,4.3524824 42.197481,1.860825 40.813604,0.80840168 40.384481,0.48205899 39.716131,0.42556727 39.208747,0.60779459 37.650593,1.1674066 37.318797,3.5633724 35.798426,4.2187227 z"\
     style="fill:#fffec2;fill-opacity:1;stroke:#878600;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />\
  <path\
     d="m 15.11608,18.808876 c 1.271657,-1.444003 4.153991,-3.145785 5.495465,-1.7664 2.950062,3.033434 -6.07961,8.17155 -4.219732,11.972265 0.545606,1.114961 2.322391,1.452799 3.532799,1.177599 5.458966,-1.241154 6.490591,-12.132334 12.070397,-11.677864 1.584527,0.129058 2.526156,2.269906 2.845867,3.827199 0.453143,2.207236 -1.962667,6.182399 -1.570133,6.574932 0.392533,0.392533 2.371401,0.909584 3.140266,0.196266 1.91857,-1.779962 -0.490667,-7.752531 0.09813,-7.850664 0.5888,-0.09813 4.421663,2.851694 5.789865,5.004799 0.583188,0.917747 -0.188581,2.956817 0.8832,3.140266 2.128963,0.364398 1.601562,-5.672021 3.729066,-5.299199 1.836829,0.321884 1.450925,3.532631 1.471999,5.397332 0.06743,5.965698 -0.565586,12.731224 -4.317865,17.369596 -3.846028,4.75426 -10.320976,8.31978 -16.388263,7.556266 C 22.030921,53.720741 16.615679,52.58734 11.485147,49.131043 7.9833717,46.771994 6.8028191,42.063042 6.5784815,37.846738 6.3607378,33.754359 8.3381535,29.765466 10.111281,26.070741 c 1.271951,-2.650408 2.940517,-4.917813 5.004799,-7.261865 z"\
     style="fill:url(#linearGradient2999);fill-opacity:1;stroke:none" />\
  <path\
     d="m 32.382709,4.7758124 c -0.123616,1.0811396 1.753928,2.8458658 2.728329,2.9439992 0.974405,0.098134 6.718874,0.7298319 9.159392,-0.1962668 0.820281,-0.3112699 0.968884,-0.9547989 0.974407,-1.4719993 0.02053,-1.9240971 0.03247,-4.7715376 -3.507853,-5.49546551 C 39.556079,0.11012647 37.217081,1.4131653 35.500801,2.2243463 34.054814,2.9077752 32.496703,3.7788369 32.382709,4.7758124 z"\
     style="fill:#b69556;fill-opacity:1;stroke:#b69556;stroke-width:1.31189477px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /></g>' % (
            scale, scale)

    def _def(self, r):
        return '  <defs>\
    <linearGradient\
       id="linearGradient3755">\
      <stop\
         id="stop3757"\
         style="stop-color:%s;stop-opacity:1"\
         offset="0" />\
      <stop\
         id="stop3759"\
         style="stop-color:%s;stop-opacity:1"\
         offset="1" />\
    </linearGradient>\
    <radialGradient\
       cx="0"\
       cy="0"\
       r="%f"\
       fx="%f"\
       fy="%f"\
       id="radialGradient3761"\
       xlink:href="#linearGradient3755"\
       gradientUnits="userSpaceOnUse" />\
  </defs>\
' % (self._fill, self._fill_dark, r, r / 3, r / 3)

    def _footer(self):
        return '</svg>\n'
Пример #18
0
class Bar():
    ''' The Bar class is used to define the bars at the bottom of the
    screen '''
    def __init__(self, sprites, width, height, scale, size):
        ''' Initialize the 2-segment bar, labels, and mark '''
        self.sprites = sprites
        self.bars = {}
        self.screen_width = width
        self.screen_height = height
        self.scale = scale
        self.ball_size = size

        self.make_bar(2)
        self.make_mark()
        self.make_labels()

    def make_mark(self):
        ''' Make a mark to show the fraction position on the bar. '''
        mark = svg_header(self.ball_size / 2.,
                          BAR_HEIGHT * self.scale + 4, 1.0) + \
               svg_rect(self.ball_size / 2.,
                        BAR_HEIGHT * self.scale + 4, 0, 0, 0, 0,
                        '#FF0000', '#FF0000') + \
               svg_rect(1, BAR_HEIGHT * self.scale + 4, 0, 0,
                        self.ball_size / 4., 0, '#000000', '#000000') + \
               svg_footer()
        self.mark = Sprite(
            self.sprites,
            0,
            self.screen_height,  # hide off bottom of screen
            svg_str_to_pixbuf(mark))
        self.mark.set_layer(2)

    def mark_width(self):
        return self.mark.rect[2]

    def bar_x(self):
        return self.bars[2].get_xy()[0]

    def bar_y(self):
        return self.bars[2].get_xy()[1]

    def width(self):
        return self.bars[2].rect[2]

    def height(self):
        return self.bars[2].rect[3]

    def hide_bars(self):
        ''' Hide all of the bars '''
        for bar in self.bars:
            self.bars[bar].set_layer(-1)

    def make_labels(self):
        ''' Label the bar '''
        num = svg_header(BAR_HEIGHT * self.scale, BAR_HEIGHT * self.scale,
                         1.0) + \
              svg_rect(BAR_HEIGHT * self.scale, BAR_HEIGHT * self.scale,
                       0, 0, 0, 0, 'none', 'none') + \
              svg_footer()
        self.left = Sprite(self.sprites, int(self.ball_size / 4), self.bar_y(),
                           svg_str_to_pixbuf(num))
        self.left.set_label(_('0'))
        self.right = Sprite(self.sprites,
                            self.screen_width - int(self.ball_size / 2),
                            self.bar_y(), svg_str_to_pixbuf(num))
        self.right.set_label(_('1'))

    def get_bar(self, nsegments):
        ''' Return a bar with n segments '''
        if nsegments not in self.bars:
            self.make_bar(nsegments)
        return self.bars[nsegments]

    def make_bar(self, nsegments):
        ''' Create a bar with n segments '''
        svg = svg_header(self.screen_width - self.ball_size, BAR_HEIGHT, 1.0)
        dx = (self.screen_width - self.ball_size) / float(nsegments)
        for i in range(int(nsegments) / 2):
            svg += svg_rect(dx, BAR_HEIGHT * self.scale, 0, 0, i * 2 * dx, 0,
                            '#FFFFFF', '#FFFFFF')
            svg += svg_rect(dx, BAR_HEIGHT * self.scale, 0, 0,
                            (i * 2 + 1) * dx, 0, '#AAAAAA', '#AAAAAA')
        if int(nsegments) % 2 == 1:  # odd
            svg += svg_rect(dx, BAR_HEIGHT * self.scale, 0, 0,
                            (i * 2 + 2) * dx, 0, '#FFFFFF', '#FFFFFF')
        svg += svg_footer()

        self.bars[nsegments] = Sprite(self.sprites, 0, 0,
                                      svg_str_to_pixbuf(svg))
        self.bars[nsegments].move(
            (int(self.ball_size / 2), self.screen_height - \
                 int((self.ball_size + self.height()) / 2)))