示例#1
0
class JigsawPuzzleUI(BorderFrame):
    __gsignals__ = {
        'game-state-changed':
        (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (int, ))
    }

    def __init__(self, parent):
        super(JigsawPuzzleUI, self).__init__(border_color=COLOR_FRAME_OUTER)

        self._shuffling = False

        self._parent = parent
        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE
        self._readonly = False
        self._join_time = 0

        inner_table = gtk.Table(2, 2, False)
        self.add(inner_table)

        self.game = JigsawPuzzleWidget()
        self.game.connect('picked', self.piece_pick_cb, False)
        self.game.connect('dropped', self.piece_drop_cb)
        self.game.connect('solved', self.do_solve)
        self.game.connect('cutter-changed', self.cutter_change_cb)
        self.game.show()

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = gtk.VBox()

        # Logo image
        img_logo = gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, expand=False, fill=False)

        # Control panel has the image controls
        control_panel = BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
                                    border_color=COLOR_FRAME_CONTROLS,
                                    bg_color=COLOR_BG_CONTROLS)
        control_panel_box = gtk.VBox()

        scrolled = gtk.ScrolledWindow()
        scrolled.props.hscrollbar_policy = gtk.POLICY_NEVER
        scrolled.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
        scrolled.show()
        scrolled.add_with_viewport(control_panel_box)
        scrolled.child.modify_bg(gtk.STATE_NORMAL,
                                 gtk.gdk.color_parse(COLOR_BG_CONTROLS))
        control_panel.add(scrolled)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        btn_box = gtk.Table(2, 5, False)
        btn_box.set_col_spacings(5)
        btn_box.set_row_spacings(5)
        btn_box.attach(gtk.Label(), 0, 1, 0, 2)
        # Cut type buttons
        self.btn_basic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'cut_basic.svg')))
        self.btn_basic_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_basic_cut), 1, 2, 0, 1, 0, 0)
        self.btn_simple_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'cut_simple.svg')))
        self.btn_simple_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_simple_cut), 2, 3, 0, 1, 0, 0)
        self.btn_classic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'cut_classic.svg')))
        self.btn_classic_cut.set_image(i)
        # Link cutter buttons with cutter styles
        self.btn_cut_mapping = {
            'basic': self.btn_basic_cut,
            'simple': self.btn_simple_cut,
            'classic': self.btn_classic_cut,
        }
        for k, v in self.btn_cut_mapping.items():
            v.connect("released", self.set_piece_cut, k)

        btn_box.attach(prepare_btn(self.btn_classic_cut), 3, 4, 0, 1, 0, 0)
        # Difficulty level buttons
        self.btn_easy_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'level_easy.svg')))
        self.btn_easy_level.set_active(True)
        self.btn_easy_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_easy_level), 1, 2, 1, 2, 0, 0)
        self.btn_normal_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'level_normal.svg')))
        self.btn_normal_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_normal_level), 2, 3, 1, 2, 0, 0)
        self.btn_hard_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'level_hard.svg')))
        self.btn_hard_level.set_image(i)
        # Link level buttons with levels
        self.btn_level_mapping = {
            3: self.btn_easy_level,
            5: self.btn_normal_level,
            8: self.btn_hard_level,
        }
        for k, v in self.btn_level_mapping.items():
            v.connect("released", self.set_level, k)

        btn_box.attach(prepare_btn(self.btn_hard_level), 3, 4, 1, 2, 0, 0)

        btn_box.attach(gtk.Label(), 4, 5, 0, 2)
        control_panel_box.pack_start(btn_box, expand=False)

        self.thumb = ImageSelectorWidget(frame_color=COLOR_FRAME_THUMB,
                                         prepare_btn_cb=prepare_btn,
                                         method=utils.RESIZE_PAD,
                                         image_dir="images",
                                         parent=self._parent)
        self.thumb.connect("category_press", self.do_select_category)
        self.thumb.connect("image_press", self.do_shuffle)
        control_panel_box.pack_start(self.thumb, expand=False)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # The game control buttons
        btn_box = gtk.Table(3, 4, False)
        btn_box.set_row_spacings(2)
        btn_box.attach(gtk.Label(), 0, 1, 0, 4)
        btn_box.attach(gtk.Label(), 2, 3, 0, 4)
        self.btn_solve = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_solve, _("Solve")])
        self.btn_solve.connect("clicked", self.do_solve)
        btn_box.attach(self.btn_solve, 1, 2, 0, 1, 0, 0)
        self.btn_shuffle = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        self.btn_shuffle.connect("clicked", self.do_shuffle)
        btn_box.attach(self.btn_shuffle, 1, 2, 1, 2, 0, 0)
        self.btn_add = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_add, _("My Picture")])
        self.btn_add.connect("clicked", self.do_add_image)
        btn_box.attach(self.btn_add, 1, 2, 2, 3, 0, 0)
        self.btn_hint = prepare_btn(gtk.ToggleButton(" "), 200)
        self.labels_to_translate.append([self.btn_hint, _("Board Hint")])
        self.btn_hint.connect("clicked", self.do_show_hint)
        btn_box.attach(self.btn_hint, 1, 2, 3, 4, 0, 0)
        control_panel_box.pack_start(btn_box, False)
        self.control_panel_box = control_panel_box

        # Control panel end
        panel.pack_start(control_panel, expand=True, fill=True)

        inner_table.attach(panel, 0, 1, 0, 1, 0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game)

        self.notebook = gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box)
        inner_table.attach(self.notebook, 1, 2, 0, 1)

        lang_combo = prepare_btn(
            LanguageComboBox('org.worldwideworkshop.olpc.JigsawPuzzle'))
        lang_combo.connect('changed', self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS,
                               border_color=COLOR_FRAME_CONTROLS)
        hbox = gtk.HBox(False)
        vbox = gtk.VBox(False)
        vbox.pack_start(lang_combo, padding=8)
        hbox.pack_start(vbox, padding=8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0, 1, 1, 2, gtk.FILL, gtk.FILL)

        timer_box = BorderFrame(border=BORDER_ALL_BUT_LEFT,
                                bg_color=COLOR_BG_CONTROLS,
                                border_color=COLOR_FRAME_CONTROLS)
        timer_hbox = gtk.HBox(False)
        self.timer = TimerWidget(bg_color=COLOR_BG_BUTTONS[0][1],
                                 fg_color=COLOR_FG_BUTTONS[0][1],
                                 lbl_color=COLOR_BG_BUTTONS[1][1])
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)
        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, padding=8)
        self.timer.connect('timer_toggle', self.timer_toggle_cb)

        self.msg_label = gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True)

        self.do_select_language(lang_combo)

        self.buddy_panel = BuddyPanel(BUDDYMODE_COLLABORATION)
        self.buddy_panel.show()

        if not parent._shared_activity:
            self.do_select_category(self)

        self.set_contest_mode(False)

        # Assert consistent state
        self.cutter_change_cb(None, self.game.get_cutter(),
                              self.game.get_target_pieces_per_line())

    def set_message(self, msg, frommesh=False):
        if frommesh and self.get_game_state() != GAME_STARTED:
            return
        self.msg_label.set_label(msg)

    def _set_control_area(self, *args):
        """ The controls area below the logo needs different actions when in contest mode,
        and also if we are the contest initiators or not. """
        if self._contest_mode:
            if self.get_game_state() > GAME_IDLE or not self.is_initiator():
                self.set_readonly()
            if self.get_game_state() <= GAME_IDLE:
                if self.is_initiator():
                    if self.timer.is_reset():
                        self.set_message(
                            _("Select image and press Start Game..."))
                    else:
                        self.set_game_state(GAME_STARTED)
                else:
                    self.set_message(
                        _("Waiting for Puzzle image to be chosen..."))
                    self.set_button_translation(self.btn_add, "Buddies")
                    self.btn_add.get_child().set_label(_("Buddies"))

    def set_readonly(self):
        """ In collaborative mode, after an image is selected and the game started you can not change much """
        self.thumb.set_readonly(True)
        self.set_button_translation(self.btn_shuffle, "Game Running")
        self.btn_shuffle.get_child().set_label(_("Game Running"))
        self.btn_shuffle.set_sensitive(False)
        for b in self.btn_cut_mapping.values() + self.btn_level_mapping.values(
        ):
            if not (b.get_active() and self.is_initiator()):
                b.set_sensitive(False)
        self._readonly = True

    def is_readonly(self):
        return self._readonly

    def is_initiator(self):
        return self._parent.initiating

    @utils.trace
    def timer_toggle_cb(self, evt, running):
        logging.debug("Timer running: %s" % str(running))
        if self._contest_mode and running:
            self.set_game_state(GAME_STARTED)
        self._send_status_update()

    def set_contest_mode(self, mode):
        if getattr(self, '_contest_mode', None) != mode:
            self.timer.set_can_stop(not bool(mode))
            self._contest_mode = bool(mode)
            self._set_control_area()
            if self._contest_mode:
                self.btn_solve.set_sensitive(False)
                #self.set_button_translation(self.btn_solve, "Give Up")
                #self.btn_solve.get_child().set_label(_("Give Up"))
                self.set_button_translation(self.btn_shuffle, "Start Game")
                self.btn_shuffle.get_child().set_label(_("Start Game"))

    @utils.trace
    def set_game_state(self, state, force=False):
        if state[0] > self._state[0] or force:
            self._state = state
            self.emit('game-state-changed', state[0])
            self._set_control_area()
            if state == GAME_STARTED:
                self.set_button_translation(self.btn_add, "Buddies")
                self.btn_add.get_child().set_label(_("Buddies"))
                if self._contest_mode:
                    if self.is_initiator():
                        self._send_game_update()
            self._send_status_update()
        elif state[0] <= GAME_STARTED[
                0] and self._contest_mode and not self.is_initiator():
            c = gtk.gdk.Cursor(gtk.gdk.WATCH)
            self.window.set_cursor(c)

    def get_game_state(self):
        return self._state

    def do_select_category(self, o, *args):
        if isinstance(o, CategorySelector):
            self.thumb.set_image_dir(args[0])
            #if not self.thumb.category.has_images():
            #    self.do_add_image(None)
        else:
            if self.game.get_parent():
                s = CategorySelector(_("Choose a Subject"),
                                     self.thumb.get_image_dir(),
                                     path="images")
                s.connect("selected", self.do_select_category)
                s.show()
                self.game_box.push(s)
                s.grab_focus()
            else:
                self.game_box.pop()

    @utils.trace
    def _show_game(self, pixbuf=None, reshuffle=True):
        if not self.game.get_parent():
            self.game_box.pop()
            while gtk.events_pending():
                gtk.main_iteration(False)
        c = gtk.gdk.Cursor(gtk.gdk.WATCH)
        self.window.set_cursor(c)
        if not self.game.prepare_image(pixbuf, reshuffle):
            self._shuffling = False
            return
        self._shuffling = False
        self.window.set_cursor(None)
        #self.game.randomize()

    def do_shuffle(self, o, *args):
        #if self.thumb.has_image():
        #    print ("FN", self.thumb.category.filename)
        if self._contest_mode and \
             self.get_game_state() == GAME_IDLE and \
             self.game.is_running() and \
             o == self.btn_shuffle and \
             self.timer.is_reset():
            # Start
            logging.debug('do_shuffle')
            self.timer.start()
        elif self.thumb.has_image():
            if not self._shuffling:
                logging.debug('do_shuffle start')
                self.timer.stop()
                self._shuffling = True
                self._show_game(self.thumb.get_image())
                self.timer.reset(False)
                self.do_show_hint(self.btn_hint)

    def do_solve(self, o, *args):
        if not self.game.is_running():
            return
        if not self.game.get_parent():
            self.game_box.pop()
        self.game.solve()
        self.timer.stop(True)
        if self._contest_mode:
            self.set_game_state(GAME_FINISHED)
            self.set_message(_("Puzzle Solved!"))
            self.control_panel_box.foreach(self.control_panel_box.remove)
            lbl = gtk.Label(_("Press Stop on the Toolbar to Exit Activity!"))
            lbl.modify_font(pango.FontDescription("bold 9"))
            lbl.set_line_wrap(True)
            lbl.set_justify(gtk.JUSTIFY_CENTER)
            lbl.set_size_request(200, -1)
            lbl.show()
            self.control_panel_box.pack_start(lbl, True)

    def do_add_image(self, o, *args):
        if self._contest_mode and self.get_game_state() >= GAME_STARTED:
            # Buddy Panel
            if not self.buddy_panel.get_parent():
                #self.timer.stop()
                self.game_box.push(self.buddy_panel)
            else:
                self.game_box.pop()
        else:
            self.thumb.add_image()

    @utils.trace
    def do_select_language(self, combo, *args):
        self.selected_lang_details = combo.translations[combo.get_active()]
        self.refresh_labels()

    def do_show_hint(self, o, *args):
        self.game.show_hint(o.get_active())

    def set_button_translation(self, btn, translation):
        for i in range(len(self.labels_to_translate)):
            if self.labels_to_translate[i][0] == btn:
                self.labels_to_translate[i][1] = translation
                break

    def refresh_labels(self, first_time=False):
        self._parent.set_title(_("Jigsaw Puzzle Activity"))
        for lbl in self.labels_to_translate:
            if isinstance(lbl[0], gtk.Button):
                lbl[0].get_child().set_label(_(lbl[1]))
            else:
                lbl[0].set_label(_(lbl[1]))
        if not self.game.get_parent() and not first_time:
            self.game_box.pop()
            if self.notebook.get_current_page() == 1:
                m = self.do_lesson_plan
            else:
                m = self.do_select_category
            m(self)

    def set_piece_cut(self, btn, cutter, *args):
        if self.is_readonly():
            return
        self.game.set_cutter(cutter)
        if self.game.is_running():
            self.do_shuffle(btn)

    def cutter_change_cb(self, o, cutter, tppl):
        # tppl = target pieces per line
        for c, b in self.btn_cut_mapping.items():
            if c == cutter:
                b.set_sensitive(True)
                b.set_active(True)
            else:
                b.set_active(False)
        for c, b in self.btn_level_mapping.items():
            if c == tppl:
                b.set_sensitive(True)
                b.set_active(True)
            else:
                b.set_active(False)

    def set_level(self, btn, level, *args):
        if self.is_readonly():
            return
        self.game.set_target_pieces_per_line(level)
        if self.game.is_running():
            self.do_shuffle(btn)

    def piece_pick_cb(self, o, piece, from_mesh=False):
        if not self.timer.is_running():
            self.timer.start()
        if not from_mesh:
            self._send_pick_notification(piece)

    def piece_drop_cb(self, o, piece, from_mesh=False):
        if self._parent._shared_activity and not from_mesh:
            self._send_drop_notification(piece)

    def _freeze(self, journal=True):
        if journal:
            return {
                'thumb': self.thumb._freeze(),
                'timer': self.timer._freeze(),
                'game': self.game._freeze(),
            }
        else:
            return {
                'timer': self.timer._freeze(),
                'game': self.game._freeze(img_cksum_only=True),
            }

    def _thaw(self, data):
        self.timer.reset()
        for k in ('thumb', 'timer', 'game'):
            if data.has_key(k):
                logging.debug('_thaw data for %s: %s' % (k, data))
                getattr(self, k)._thaw(data[k])
        if data.has_key('game'):  # and not data.has_key('thumb'):
            self.thumb.load_pb(self.game.board.cutboard.pb)
        if data.has_key('timer'):
            self._join_time = self.timer.ellapsed()
        if data.has_key('game') and data['game']['piece_pos']:
            self._show_game(reshuffle=False)

    @utils.trace
    def _send_status_update(self):
        """ Send a status update signal """
        if self._parent._shared_activity:
            if self.get_game_state() == GAME_STARTED:
                if self.thumb.has_image():
                    self.set_message(_("Game Started!"))
                else:
                    self.set_message(
                        _("Waiting for Puzzle image to be transferred..."))
            self._parent.game_tube.StatusUpdate(self._state[1],
                                                self._join_time)

    @utils.trace
    def _send_game_update(self):
        """ A puzzle was selected, share it """
        if self._parent._shared_activity:
            # TODO: Send image
            self._parent.game_tube.GameUpdate(self._state[1])

    @utils.trace
    def _send_pick_notification(self, piece):
        """ """
        if self._parent._shared_activity:
            self._parent.game_tube.PiecePicked(piece.get_index())

    @utils.trace
    def _recv_pick_notification(self, index):
        for piece in self.game.get_floating_pieces():
            if piece.get_index() == index:
                logging.debug("Remote picked piece %s" % piece)
                piece.set_sensitive(False)

    @utils.trace
    def _send_drop_notification(self, piece):
        """ """
        if piece.placed:
            self._parent.game_tube.PiecePlaced(piece.get_index())
        else:
            self._parent.game_tube.PieceDropped(piece.get_index(),
                                                piece.get_position())

    @utils.trace
    def _recv_drop_notification(self, index, position=None):
        for piece in self.game.get_floating_pieces():
            if piece.get_index() == index:
                logging.debug("Moving piece %s" % piece)
                if position is None:
                    self.game.board.place_piece(piece)
                else:
                    self.game._move_cb(piece,
                                       position[0],
                                       position[1],
                                       absolute=True)
                    self.game._drop_cb(piece, from_mesh=True)
                piece.set_sensitive(True)
                break
示例#2
0
    def __init__(self, parent):
        super(JigsawPuzzleUI, self).__init__(border_color=COLOR_FRAME_OUTER)

        self._shuffling = False

        self._parent = parent
        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE
        self._readonly = False
        self._join_time = 0

        inner_table = gtk.Table(2, 2, False)
        self.add(inner_table)

        self.game = JigsawPuzzleWidget()
        self.game.connect('picked', self.piece_pick_cb, False)
        self.game.connect('dropped', self.piece_drop_cb)
        self.game.connect('solved', self.do_solve)
        self.game.connect('cutter-changed', self.cutter_change_cb)
        self.game.show()

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = gtk.VBox()

        # Logo image
        img_logo = gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, expand=False, fill=False)

        # Control panel has the image controls
        control_panel = BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
                                    border_color=COLOR_FRAME_CONTROLS,
                                    bg_color=COLOR_BG_CONTROLS)
        control_panel_box = gtk.VBox()

        scrolled = gtk.ScrolledWindow()
        scrolled.props.hscrollbar_policy = gtk.POLICY_NEVER
        scrolled.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
        scrolled.show()
        scrolled.add_with_viewport(control_panel_box)
        scrolled.child.modify_bg(gtk.STATE_NORMAL,
                                 gtk.gdk.color_parse(COLOR_BG_CONTROLS))
        control_panel.add(scrolled)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        btn_box = gtk.Table(2, 5, False)
        btn_box.set_col_spacings(5)
        btn_box.set_row_spacings(5)
        btn_box.attach(gtk.Label(), 0, 1, 0, 2)
        # Cut type buttons
        self.btn_basic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'cut_basic.svg')))
        self.btn_basic_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_basic_cut), 1, 2, 0, 1, 0, 0)
        self.btn_simple_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'cut_simple.svg')))
        self.btn_simple_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_simple_cut), 2, 3, 0, 1, 0, 0)
        self.btn_classic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'cut_classic.svg')))
        self.btn_classic_cut.set_image(i)
        # Link cutter buttons with cutter styles
        self.btn_cut_mapping = {
            'basic': self.btn_basic_cut,
            'simple': self.btn_simple_cut,
            'classic': self.btn_classic_cut,
        }
        for k, v in self.btn_cut_mapping.items():
            v.connect("released", self.set_piece_cut, k)

        btn_box.attach(prepare_btn(self.btn_classic_cut), 3, 4, 0, 1, 0, 0)
        # Difficulty level buttons
        self.btn_easy_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'level_easy.svg')))
        self.btn_easy_level.set_active(True)
        self.btn_easy_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_easy_level), 1, 2, 1, 2, 0, 0)
        self.btn_normal_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'level_normal.svg')))
        self.btn_normal_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_normal_level), 2, 3, 1, 2, 0, 0)
        self.btn_hard_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(
            utils.load_image(os.path.join('icons', 'level_hard.svg')))
        self.btn_hard_level.set_image(i)
        # Link level buttons with levels
        self.btn_level_mapping = {
            3: self.btn_easy_level,
            5: self.btn_normal_level,
            8: self.btn_hard_level,
        }
        for k, v in self.btn_level_mapping.items():
            v.connect("released", self.set_level, k)

        btn_box.attach(prepare_btn(self.btn_hard_level), 3, 4, 1, 2, 0, 0)

        btn_box.attach(gtk.Label(), 4, 5, 0, 2)
        control_panel_box.pack_start(btn_box, expand=False)

        self.thumb = ImageSelectorWidget(frame_color=COLOR_FRAME_THUMB,
                                         prepare_btn_cb=prepare_btn,
                                         method=utils.RESIZE_PAD,
                                         image_dir="images",
                                         parent=self._parent)
        self.thumb.connect("category_press", self.do_select_category)
        self.thumb.connect("image_press", self.do_shuffle)
        control_panel_box.pack_start(self.thumb, expand=False)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # The game control buttons
        btn_box = gtk.Table(3, 4, False)
        btn_box.set_row_spacings(2)
        btn_box.attach(gtk.Label(), 0, 1, 0, 4)
        btn_box.attach(gtk.Label(), 2, 3, 0, 4)
        self.btn_solve = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_solve, _("Solve")])
        self.btn_solve.connect("clicked", self.do_solve)
        btn_box.attach(self.btn_solve, 1, 2, 0, 1, 0, 0)
        self.btn_shuffle = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        self.btn_shuffle.connect("clicked", self.do_shuffle)
        btn_box.attach(self.btn_shuffle, 1, 2, 1, 2, 0, 0)
        self.btn_add = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_add, _("My Picture")])
        self.btn_add.connect("clicked", self.do_add_image)
        btn_box.attach(self.btn_add, 1, 2, 2, 3, 0, 0)
        self.btn_hint = prepare_btn(gtk.ToggleButton(" "), 200)
        self.labels_to_translate.append([self.btn_hint, _("Board Hint")])
        self.btn_hint.connect("clicked", self.do_show_hint)
        btn_box.attach(self.btn_hint, 1, 2, 3, 4, 0, 0)
        control_panel_box.pack_start(btn_box, False)
        self.control_panel_box = control_panel_box

        # Control panel end
        panel.pack_start(control_panel, expand=True, fill=True)

        inner_table.attach(panel, 0, 1, 0, 1, 0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game)

        self.notebook = gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box)
        inner_table.attach(self.notebook, 1, 2, 0, 1)

        lang_combo = prepare_btn(
            LanguageComboBox('org.worldwideworkshop.olpc.JigsawPuzzle'))
        lang_combo.connect('changed', self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS,
                               border_color=COLOR_FRAME_CONTROLS)
        hbox = gtk.HBox(False)
        vbox = gtk.VBox(False)
        vbox.pack_start(lang_combo, padding=8)
        hbox.pack_start(vbox, padding=8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0, 1, 1, 2, gtk.FILL, gtk.FILL)

        timer_box = BorderFrame(border=BORDER_ALL_BUT_LEFT,
                                bg_color=COLOR_BG_CONTROLS,
                                border_color=COLOR_FRAME_CONTROLS)
        timer_hbox = gtk.HBox(False)
        self.timer = TimerWidget(bg_color=COLOR_BG_BUTTONS[0][1],
                                 fg_color=COLOR_FG_BUTTONS[0][1],
                                 lbl_color=COLOR_BG_BUTTONS[1][1])
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)
        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, padding=8)
        self.timer.connect('timer_toggle', self.timer_toggle_cb)

        self.msg_label = gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True)

        self.do_select_language(lang_combo)

        self.buddy_panel = BuddyPanel(BUDDYMODE_COLLABORATION)
        self.buddy_panel.show()

        if not parent._shared_activity:
            self.do_select_category(self)

        self.set_contest_mode(False)

        # Assert consistent state
        self.cutter_change_cb(None, self.game.get_cutter(),
                              self.game.get_target_pieces_per_line())
示例#3
0
class JigsawPuzzleUI(BorderFrame):
    __gsignals__ = {"game-state-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (int,))}

    def __init__(self, parent):
        super(JigsawPuzzleUI, self).__init__(border_color=COLOR_FRAME_OUTER)

        self._shuffling = False

        self._parent = parent
        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE
        self._readonly = False
        self._join_time = 0

        inner_table = gtk.Table(2, 2, False)
        self.add(inner_table)

        self.game = JigsawPuzzleWidget()
        self.game.connect("picked", self.piece_pick_cb, False)
        self.game.connect("dropped", self.piece_drop_cb)
        self.game.connect("solved", self.do_solve)
        self.game.connect("cutter-changed", self.cutter_change_cb)
        self.game.show()

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = gtk.VBox()

        # Logo image
        img_logo = gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, expand=False, fill=False)

        # Control panel has the image controls
        control_panel = BorderFrame(
            border=BORDER_ALL_BUT_BOTTOM, border_color=COLOR_FRAME_CONTROLS, bg_color=COLOR_BG_CONTROLS
        )
        control_panel_box = gtk.VBox()

        scrolled = gtk.ScrolledWindow()
        scrolled.props.hscrollbar_policy = gtk.POLICY_NEVER
        scrolled.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
        scrolled.show()
        scrolled.add_with_viewport(control_panel_box)
        scrolled.child.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(COLOR_BG_CONTROLS))
        control_panel.add(scrolled)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        btn_box = gtk.Table(2, 5, False)
        btn_box.set_col_spacings(5)
        btn_box.set_row_spacings(5)
        btn_box.attach(gtk.Label(), 0, 1, 0, 2)
        # Cut type buttons
        self.btn_basic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "cut_basic.svg")))
        self.btn_basic_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_basic_cut), 1, 2, 0, 1, 0, 0)
        self.btn_simple_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "cut_simple.svg")))
        self.btn_simple_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_simple_cut), 2, 3, 0, 1, 0, 0)
        self.btn_classic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "cut_classic.svg")))
        self.btn_classic_cut.set_image(i)
        # Link cutter buttons with cutter styles
        self.btn_cut_mapping = {
            "basic": self.btn_basic_cut,
            "simple": self.btn_simple_cut,
            "classic": self.btn_classic_cut,
        }
        for k, v in self.btn_cut_mapping.items():
            v.connect("released", self.set_piece_cut, k)

        btn_box.attach(prepare_btn(self.btn_classic_cut), 3, 4, 0, 1, 0, 0)
        # Difficulty level buttons
        self.btn_easy_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "level_easy.svg")))
        self.btn_easy_level.set_active(True)
        self.btn_easy_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_easy_level), 1, 2, 1, 2, 0, 0)
        self.btn_normal_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "level_normal.svg")))
        self.btn_normal_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_normal_level), 2, 3, 1, 2, 0, 0)
        self.btn_hard_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "level_hard.svg")))
        self.btn_hard_level.set_image(i)
        # Link level buttons with levels
        self.btn_level_mapping = {3: self.btn_easy_level, 5: self.btn_normal_level, 8: self.btn_hard_level}
        for k, v in self.btn_level_mapping.items():
            v.connect("released", self.set_level, k)

        btn_box.attach(prepare_btn(self.btn_hard_level), 3, 4, 1, 2, 0, 0)

        btn_box.attach(gtk.Label(), 4, 5, 0, 2)
        control_panel_box.pack_start(btn_box, expand=False)

        self.thumb = ImageSelectorWidget(
            frame_color=COLOR_FRAME_THUMB,
            prepare_btn_cb=prepare_btn,
            method=utils.RESIZE_PAD,
            image_dir="images",
            parent=self._parent,
        )
        self.thumb.connect("category_press", self.do_select_category)
        self.thumb.connect("image_press", self.do_shuffle)
        control_panel_box.pack_start(self.thumb, expand=False)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # The game control buttons
        btn_box = gtk.Table(3, 4, False)
        btn_box.set_row_spacings(2)
        btn_box.attach(gtk.Label(), 0, 1, 0, 4)
        btn_box.attach(gtk.Label(), 2, 3, 0, 4)
        self.btn_solve = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_solve, _("Solve")])
        self.btn_solve.connect("clicked", self.do_solve)
        btn_box.attach(self.btn_solve, 1, 2, 0, 1, 0, 0)
        self.btn_shuffle = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        self.btn_shuffle.connect("clicked", self.do_shuffle)
        btn_box.attach(self.btn_shuffle, 1, 2, 1, 2, 0, 0)
        self.btn_add = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_add, _("My Picture")])
        self.btn_add.connect("clicked", self.do_add_image)
        btn_box.attach(self.btn_add, 1, 2, 2, 3, 0, 0)
        self.btn_hint = prepare_btn(gtk.ToggleButton(" "), 200)
        self.labels_to_translate.append([self.btn_hint, _("Board Hint")])
        self.btn_hint.connect("clicked", self.do_show_hint)
        btn_box.attach(self.btn_hint, 1, 2, 3, 4, 0, 0)
        control_panel_box.pack_start(btn_box, False)
        self.control_panel_box = control_panel_box

        # Control panel end
        panel.pack_start(control_panel, expand=True, fill=True)

        inner_table.attach(panel, 0, 1, 0, 1, 0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game)

        self.notebook = gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box)
        inner_table.attach(self.notebook, 1, 2, 0, 1)

        lang_combo = prepare_btn(LanguageComboBox("org.worldwideworkshop.olpc.JigsawPuzzle"))
        lang_combo.connect("changed", self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS, border_color=COLOR_FRAME_CONTROLS)
        hbox = gtk.HBox(False)
        vbox = gtk.VBox(False)
        vbox.pack_start(lang_combo, padding=8)
        hbox.pack_start(vbox, padding=8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0, 1, 1, 2, gtk.FILL, gtk.FILL)

        timer_box = BorderFrame(
            border=BORDER_ALL_BUT_LEFT, bg_color=COLOR_BG_CONTROLS, border_color=COLOR_FRAME_CONTROLS
        )
        timer_hbox = gtk.HBox(False)
        self.timer = TimerWidget(
            bg_color=COLOR_BG_BUTTONS[0][1], fg_color=COLOR_FG_BUTTONS[0][1], lbl_color=COLOR_BG_BUTTONS[1][1]
        )
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)
        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, padding=8)
        self.timer.connect("timer_toggle", self.timer_toggle_cb)

        self.msg_label = gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True)

        self.btn_lesson = prepare_btn(gtk.Button(" "))
        self.labels_to_translate.append([self.btn_lesson, _("Lesson Plans")])
        self.btn_lesson.connect("clicked", self.do_lesson_plan)
        timer_hbox.pack_start(self.btn_lesson, False, padding=8)
        vbox = gtk.VBox(False)
        vbox.pack_start(timer_hbox, padding=8)
        timer_box.add(vbox)
        inner_table.attach(timer_box, 1, 2, 1, 2, gtk.FILL, gtk.FILL)
        # panel.pack_start(lang_box, expand=False, fill=False)

        self.do_select_language(lang_combo)

        self.buddy_panel = BuddyPanel(BUDDYMODE_COLLABORATION)
        self.buddy_panel.show()

        if not parent._shared_activity:
            self.do_select_category(self)

        self.set_contest_mode(False)

        # Assert consistent state
        self.cutter_change_cb(None, self.game.get_cutter(), self.game.get_target_pieces_per_line())

    def set_message(self, msg, frommesh=False):
        if frommesh and self.get_game_state() != GAME_STARTED:
            return
        self.msg_label.set_label(msg)

    def _set_control_area(self, *args):
        """ The controls area below the logo needs different actions when in contest mode,
        and also if we are the contest initiators or not. """
        if self._contest_mode:
            if self.get_game_state() > GAME_IDLE or not self.is_initiator():
                self.set_readonly()
            if self.get_game_state() <= GAME_IDLE:
                if self.is_initiator():
                    if self.timer.is_reset():
                        self.set_message(_("Select image and press Start Game..."))
                    else:
                        self.set_game_state(GAME_STARTED)
                else:
                    self.set_message(_("Waiting for Puzzle image to be chosen..."))
                    self.set_button_translation(self.btn_add, "Buddies")
                    self.btn_add.get_child().set_label(_("Buddies"))

    def set_readonly(self):
        """ In collaborative mode, after an image is selected and the game started you can not change much """
        self.thumb.set_readonly(True)
        self.set_button_translation(self.btn_shuffle, "Game Running")
        self.btn_shuffle.get_child().set_label(_("Game Running"))
        self.btn_shuffle.set_sensitive(False)
        for b in self.btn_cut_mapping.values() + self.btn_level_mapping.values():
            if not (b.get_active() and self.is_initiator()):
                b.set_sensitive(False)
        self._readonly = True

    def is_readonly(self):
        return self._readonly

    def is_initiator(self):
        return self._parent.initiating

    @utils.trace
    def timer_toggle_cb(self, evt, running):
        logging.debug("Timer running: %s" % str(running))
        if self._contest_mode and running:
            self.set_game_state(GAME_STARTED)
        self._send_status_update()

    def set_contest_mode(self, mode):
        if getattr(self, "_contest_mode", None) != mode:
            self.timer.set_can_stop(not bool(mode))
            self._contest_mode = bool(mode)
            self._set_control_area()
            if self._contest_mode:
                self.btn_solve.set_sensitive(False)
                # self.set_button_translation(self.btn_solve, "Give Up")
                # self.btn_solve.get_child().set_label(_("Give Up"))
                self.set_button_translation(self.btn_shuffle, "Start Game")
                self.btn_shuffle.get_child().set_label(_("Start Game"))

    @utils.trace
    def set_game_state(self, state, force=False):
        if state[0] > self._state[0] or force:
            self._state = state
            self.emit("game-state-changed", state[0])
            self._set_control_area()
            if state == GAME_STARTED:
                self.set_button_translation(self.btn_add, "Buddies")
                self.btn_add.get_child().set_label(_("Buddies"))
                if self._contest_mode:
                    if self.is_initiator():
                        self._send_game_update()
            self._send_status_update()
        elif state[0] <= GAME_STARTED[0] and self._contest_mode and not self.is_initiator():
            c = gtk.gdk.Cursor(gtk.gdk.WATCH)
            self.window.set_cursor(c)

    def get_game_state(self):
        return self._state

    def do_select_category(self, o, *args):
        if isinstance(o, CategorySelector):
            self.thumb.set_image_dir(args[0])
            # if not self.thumb.category.has_images():
            #    self.do_add_image(None)
        else:
            if self.game.get_parent():
                s = CategorySelector(_("Choose a Subject"), self.thumb.get_image_dir(), path="images")
                s.connect("selected", self.do_select_category)
                s.show()
                self.game_box.push(s)
                s.grab_focus()
            else:
                self.game_box.pop()

    @utils.trace
    def _show_game(self, pixbuf=None, reshuffle=True):
        if not self.game.get_parent():
            self.game_box.pop()
            while gtk.events_pending():
                gtk.main_iteration(False)
        c = gtk.gdk.Cursor(gtk.gdk.WATCH)
        self.window.set_cursor(c)
        if not self.game.prepare_image(pixbuf, reshuffle):
            self._shuffling = False
            return
        self._shuffling = False
        self.window.set_cursor(None)
        # self.game.randomize()

    def do_shuffle(self, o, *args):
        # if self.thumb.has_image():
        #    print ("FN", self.thumb.category.filename)
        if (
            self._contest_mode
            and self.get_game_state() == GAME_IDLE
            and self.game.is_running()
            and o == self.btn_shuffle
            and self.timer.is_reset()
        ):
            # Start
            logging.debug("do_shuffle")
            self.timer.start()
        elif self.thumb.has_image():
            if not self._shuffling:
                logging.debug("do_shuffle start")
                self.timer.stop()
                self._shuffling = True
                self._show_game(self.thumb.get_image())
                self.timer.reset(False)
                self.do_show_hint(self.btn_hint)

    def do_solve(self, o, *args):
        if not self.game.is_running():
            return
        if not self.game.get_parent():
            self.game_box.pop()
        self.game.solve()
        self.timer.stop(True)
        if self._contest_mode:
            self.set_game_state(GAME_FINISHED)
            self.set_message(_("Puzzle Solved!"))
            self.control_panel_box.foreach(self.control_panel_box.remove)
            lbl = gtk.Label(_("Press Stop on the Toolbar to Exit Activity!"))
            lbl.modify_font(pango.FontDescription("bold 9"))
            lbl.set_line_wrap(True)
            lbl.set_justify(gtk.JUSTIFY_CENTER)
            lbl.set_size_request(200, -1)
            lbl.show()
            self.control_panel_box.pack_start(lbl, True)

    def do_add_image(self, o, *args):
        if self._contest_mode and self.get_game_state() >= GAME_STARTED:
            # Buddy Panel
            if not self.buddy_panel.get_parent():
                # self.timer.stop()
                self.game_box.push(self.buddy_panel)
            else:
                self.game_box.pop()
        else:
            self.thumb.add_image()

    @utils.trace
    def do_select_language(self, combo, *args):
        self.selected_lang_details = combo.translations[combo.get_active()]
        self.refresh_labels()

    def do_show_hint(self, o, *args):
        self.game.show_hint(o.get_active())

    def set_button_translation(self, btn, translation):
        for i in range(len(self.labels_to_translate)):
            if self.labels_to_translate[i][0] == btn:
                self.labels_to_translate[i][1] = translation
                break

    def refresh_labels(self, first_time=False):
        self._parent.set_title(_("Jigsaw Puzzle Activity"))
        for lbl in self.labels_to_translate:
            if isinstance(lbl[0], gtk.Button):
                lbl[0].get_child().set_label(_(lbl[1]))
            else:
                lbl[0].set_label(_(lbl[1]))
        if not self.game.get_parent() and not first_time:
            self.game_box.pop()
            if self.notebook.get_current_page() == 1:
                m = self.do_lesson_plan
            else:
                m = self.do_select_category
            m(self)

    def do_lesson_plan(self, btn):
        page = self.notebook.get_current_page()

        if page == 0:
            if self.notebook.get_n_pages() == 1:
                lessons = NotebookReaderWidget("lessons", self.selected_lang_details)
                lessons.connect("parent-set", self.do_lesson_plan_reparent)
                lessons.show_all()
                self.notebook.append_page(lessons)

        self.notebook.set_current_page(int(not page))

    def do_lesson_plan_reparent(self, widget, oldparent):
        if not self.btn_lesson.get_child():
            return
        if widget.parent is None:
            self.set_button_translation(self.btn_lesson, "Lesson Plans")
            self.btn_lesson.get_child().set_label(_("Lesson Plans"))
        else:
            self.set_button_translation(self.btn_lesson, "Close Lesson")
            self.btn_lesson.get_child().set_label(_("Close Lesson"))

    def set_piece_cut(self, btn, cutter, *args):
        if self.is_readonly():
            return
        self.game.set_cutter(cutter)
        if self.game.is_running():
            self.do_shuffle(btn)

    def cutter_change_cb(self, o, cutter, tppl):
        # tppl = target pieces per line
        for c, b in self.btn_cut_mapping.items():
            if c == cutter:
                b.set_sensitive(True)
                b.set_active(True)
            else:
                b.set_active(False)
        for c, b in self.btn_level_mapping.items():
            if c == tppl:
                b.set_sensitive(True)
                b.set_active(True)
            else:
                b.set_active(False)

    def set_level(self, btn, level, *args):
        if self.is_readonly():
            return
        self.game.set_target_pieces_per_line(level)
        if self.game.is_running():
            self.do_shuffle(btn)

    def piece_pick_cb(self, o, piece, from_mesh=False):
        if not self.timer.is_running():
            self.timer.start()
        if not from_mesh:
            self._send_pick_notification(piece)

    def piece_drop_cb(self, o, piece, from_mesh=False):
        if self._parent._shared_activity and not from_mesh:
            self._send_drop_notification(piece)

    def _freeze(self, journal=True):
        if journal:
            return {"thumb": self.thumb._freeze(), "timer": self.timer._freeze(), "game": self.game._freeze()}
        else:
            return {"timer": self.timer._freeze(), "game": self.game._freeze(img_cksum_only=True)}

    def _thaw(self, data):
        self.timer.reset()
        for k in ("thumb", "timer", "game"):
            if data.has_key(k):
                logging.debug("_thaw data for %s: %s" % (k, data))
                getattr(self, k)._thaw(data[k])
        if data.has_key("game"):  # and not data.has_key('thumb'):
            self.thumb.load_pb(self.game.board.cutboard.pb)
        if data.has_key("timer"):
            self._join_time = self.timer.ellapsed()
        if data.has_key("game") and data["game"]["piece_pos"]:
            self._show_game(reshuffle=False)

    @utils.trace
    def _send_status_update(self):
        """ Send a status update signal """
        if self._parent._shared_activity:
            if self.get_game_state() == GAME_STARTED:
                if self.thumb.has_image():
                    self.set_message(_("Game Started!"))
                else:
                    self.set_message(_("Waiting for Puzzle image to be transferred..."))
            self._parent.game_tube.StatusUpdate(self._state[1], self._join_time)

    @utils.trace
    def _send_game_update(self):
        """ A puzzle was selected, share it """
        if self._parent._shared_activity:
            # TODO: Send image
            self._parent.game_tube.GameUpdate(self._state[1])

    @utils.trace
    def _send_pick_notification(self, piece):
        """ """
        if self._parent._shared_activity:
            self._parent.game_tube.PiecePicked(piece.get_index())

    @utils.trace
    def _recv_pick_notification(self, index):
        for piece in self.game.get_floating_pieces():
            if piece.get_index() == index:
                logging.debug("Remote picked piece %s" % piece)
                piece.set_sensitive(False)

    @utils.trace
    def _send_drop_notification(self, piece):
        """ """
        if piece.placed:
            self._parent.game_tube.PiecePlaced(piece.get_index())
        else:
            self._parent.game_tube.PieceDropped(piece.get_index(), piece.get_position())

    @utils.trace
    def _recv_drop_notification(self, index, position=None):
        for piece in self.game.get_floating_pieces():
            if piece.get_index() == index:
                logging.debug("Moving piece %s" % piece)
                if position is None:
                    self.game.board.place_piece(piece)
                else:
                    self.game._move_cb(piece, position[0], position[1], absolute=True)
                    self.game._drop_cb(piece, from_mesh=True)
                piece.set_sensitive(True)
                break
示例#4
0
    def __init__(self, parent):
        super(JigsawPuzzleUI, self).__init__(border_color=COLOR_FRAME_OUTER)

        self._shuffling = False

        self._parent = parent
        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE
        self._readonly = False
        self._join_time = 0

        inner_table = gtk.Table(2, 2, False)
        self.add(inner_table)

        self.game = JigsawPuzzleWidget()
        self.game.connect("picked", self.piece_pick_cb, False)
        self.game.connect("dropped", self.piece_drop_cb)
        self.game.connect("solved", self.do_solve)
        self.game.connect("cutter-changed", self.cutter_change_cb)
        self.game.show()

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = gtk.VBox()

        # Logo image
        img_logo = gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, expand=False, fill=False)

        # Control panel has the image controls
        control_panel = BorderFrame(
            border=BORDER_ALL_BUT_BOTTOM, border_color=COLOR_FRAME_CONTROLS, bg_color=COLOR_BG_CONTROLS
        )
        control_panel_box = gtk.VBox()

        scrolled = gtk.ScrolledWindow()
        scrolled.props.hscrollbar_policy = gtk.POLICY_NEVER
        scrolled.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
        scrolled.show()
        scrolled.add_with_viewport(control_panel_box)
        scrolled.child.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(COLOR_BG_CONTROLS))
        control_panel.add(scrolled)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        btn_box = gtk.Table(2, 5, False)
        btn_box.set_col_spacings(5)
        btn_box.set_row_spacings(5)
        btn_box.attach(gtk.Label(), 0, 1, 0, 2)
        # Cut type buttons
        self.btn_basic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "cut_basic.svg")))
        self.btn_basic_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_basic_cut), 1, 2, 0, 1, 0, 0)
        self.btn_simple_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "cut_simple.svg")))
        self.btn_simple_cut.set_image(i)
        btn_box.attach(prepare_btn(self.btn_simple_cut), 2, 3, 0, 1, 0, 0)
        self.btn_classic_cut = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "cut_classic.svg")))
        self.btn_classic_cut.set_image(i)
        # Link cutter buttons with cutter styles
        self.btn_cut_mapping = {
            "basic": self.btn_basic_cut,
            "simple": self.btn_simple_cut,
            "classic": self.btn_classic_cut,
        }
        for k, v in self.btn_cut_mapping.items():
            v.connect("released", self.set_piece_cut, k)

        btn_box.attach(prepare_btn(self.btn_classic_cut), 3, 4, 0, 1, 0, 0)
        # Difficulty level buttons
        self.btn_easy_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "level_easy.svg")))
        self.btn_easy_level.set_active(True)
        self.btn_easy_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_easy_level), 1, 2, 1, 2, 0, 0)
        self.btn_normal_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "level_normal.svg")))
        self.btn_normal_level.set_image(i)
        btn_box.attach(prepare_btn(self.btn_normal_level), 2, 3, 1, 2, 0, 0)
        self.btn_hard_level = gtk.ToggleButton()
        i = gtk.Image()
        i.set_from_pixbuf(utils.load_image(os.path.join("icons", "level_hard.svg")))
        self.btn_hard_level.set_image(i)
        # Link level buttons with levels
        self.btn_level_mapping = {3: self.btn_easy_level, 5: self.btn_normal_level, 8: self.btn_hard_level}
        for k, v in self.btn_level_mapping.items():
            v.connect("released", self.set_level, k)

        btn_box.attach(prepare_btn(self.btn_hard_level), 3, 4, 1, 2, 0, 0)

        btn_box.attach(gtk.Label(), 4, 5, 0, 2)
        control_panel_box.pack_start(btn_box, expand=False)

        self.thumb = ImageSelectorWidget(
            frame_color=COLOR_FRAME_THUMB,
            prepare_btn_cb=prepare_btn,
            method=utils.RESIZE_PAD,
            image_dir="images",
            parent=self._parent,
        )
        self.thumb.connect("category_press", self.do_select_category)
        self.thumb.connect("image_press", self.do_shuffle)
        control_panel_box.pack_start(self.thumb, expand=False)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # The game control buttons
        btn_box = gtk.Table(3, 4, False)
        btn_box.set_row_spacings(2)
        btn_box.attach(gtk.Label(), 0, 1, 0, 4)
        btn_box.attach(gtk.Label(), 2, 3, 0, 4)
        self.btn_solve = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_solve, _("Solve")])
        self.btn_solve.connect("clicked", self.do_solve)
        btn_box.attach(self.btn_solve, 1, 2, 0, 1, 0, 0)
        self.btn_shuffle = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        self.btn_shuffle.connect("clicked", self.do_shuffle)
        btn_box.attach(self.btn_shuffle, 1, 2, 1, 2, 0, 0)
        self.btn_add = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_add, _("My Picture")])
        self.btn_add.connect("clicked", self.do_add_image)
        btn_box.attach(self.btn_add, 1, 2, 2, 3, 0, 0)
        self.btn_hint = prepare_btn(gtk.ToggleButton(" "), 200)
        self.labels_to_translate.append([self.btn_hint, _("Board Hint")])
        self.btn_hint.connect("clicked", self.do_show_hint)
        btn_box.attach(self.btn_hint, 1, 2, 3, 4, 0, 0)
        control_panel_box.pack_start(btn_box, False)
        self.control_panel_box = control_panel_box

        # Control panel end
        panel.pack_start(control_panel, expand=True, fill=True)

        inner_table.attach(panel, 0, 1, 0, 1, 0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game)

        self.notebook = gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box)
        inner_table.attach(self.notebook, 1, 2, 0, 1)

        lang_combo = prepare_btn(LanguageComboBox("org.worldwideworkshop.olpc.JigsawPuzzle"))
        lang_combo.connect("changed", self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS, border_color=COLOR_FRAME_CONTROLS)
        hbox = gtk.HBox(False)
        vbox = gtk.VBox(False)
        vbox.pack_start(lang_combo, padding=8)
        hbox.pack_start(vbox, padding=8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0, 1, 1, 2, gtk.FILL, gtk.FILL)

        timer_box = BorderFrame(
            border=BORDER_ALL_BUT_LEFT, bg_color=COLOR_BG_CONTROLS, border_color=COLOR_FRAME_CONTROLS
        )
        timer_hbox = gtk.HBox(False)
        self.timer = TimerWidget(
            bg_color=COLOR_BG_BUTTONS[0][1], fg_color=COLOR_FG_BUTTONS[0][1], lbl_color=COLOR_BG_BUTTONS[1][1]
        )
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)
        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, padding=8)
        self.timer.connect("timer_toggle", self.timer_toggle_cb)

        self.msg_label = gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True)

        self.btn_lesson = prepare_btn(gtk.Button(" "))
        self.labels_to_translate.append([self.btn_lesson, _("Lesson Plans")])
        self.btn_lesson.connect("clicked", self.do_lesson_plan)
        timer_hbox.pack_start(self.btn_lesson, False, padding=8)
        vbox = gtk.VBox(False)
        vbox.pack_start(timer_hbox, padding=8)
        timer_box.add(vbox)
        inner_table.attach(timer_box, 1, 2, 1, 2, gtk.FILL, gtk.FILL)
        # panel.pack_start(lang_box, expand=False, fill=False)

        self.do_select_language(lang_combo)

        self.buddy_panel = BuddyPanel(BUDDYMODE_COLLABORATION)
        self.buddy_panel.show()

        if not parent._shared_activity:
            self.do_select_category(self)

        self.set_contest_mode(False)

        # Assert consistent state
        self.cutter_change_cb(None, self.game.get_cutter(), self.game.get_target_pieces_per_line())
示例#5
0
    def __init__(self, parent):
        super(SliderPuzzleUI, self).__init__(3, 3, False)
        self._parent = parent

        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE

        inner_table = Gtk.Table(2, 2, False)
        self.add(inner_table)
        self.from_journal = True
        self.game = SliderPuzzleWidget(9, GAME_SIZE, GAME_SIZE)
        self.game.connect("solved", self.do_solve)
        self.game.connect("moved", self.slider_move_cb)
        self._parent.connect("key_press_event", self.game.process_key)
        self._parent.connect("key_press_event", self.process_key)
        self.game.show()
        desktop = BorderFrame(border_color=COLOR_FRAME_CONTROLS)
        desktop.show()
        desktop.add(self.game)
        self.game_wrapper = Gtk.VBox()
        self.game_wrapper.show()
        inner = Gtk.HBox()
        inner.show()
        #BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
        #                                border_color=COLOR_FRAME_CONTROLS,
        #                                bg_color=COLOR_BG_CONTROLS)
        inner.pack_start(desktop, True, False, 0)
        self.game_wrapper.pack_start(inner, True, False, 0)

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = Gtk.VBox()

        # Logo image
        img_logo = Gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, False, False, 0)

        # Control panel has the image controls
        control_panel = BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
                                    border_color=COLOR_FRAME_CONTROLS,
                                    bg_color=COLOR_BG_CONTROLS)
        control_panel_box = Gtk.VBox()
        control_panel.add(control_panel_box)

        spacer = Gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, False, False, 0)

        # ...

        # Slice buttons
        #btn_box = Gtk.Table(1,5,False)
        #btn_box.set_col_spacings(5)
        #btn_box.set_row_spacings(5)
        #btn_box.attach(Gtk.Label(), 0,1,0,2)

        #spacer = Gtk.Label()
        #spacer.set_size_request(-1, 15)
        #control_panel_box.pack_start(spacer, False, False, 0)
        #cutter = Gtk.HBox(False, 8)
        #cutter.pack_start(Gtk.Label(), True)
        #self.btn_9 = prepare_btn(Gtk.ToggleButton("9"),SLICE_BTN_WIDTH)
        #self.btn_9.set_active(True)
        #self.btn_9.connect("clicked", self.set_nr_pieces, 9)
        #btn_box.attach(self.btn_9, 1,2,0,1,0,0)
        #cutter.pack_start(self.btn_9, False, False)
        #self.btn_12 = prepare_btn(Gtk.ToggleButton("12"), SLICE_BTN_WIDTH)
        #self.btn_12.connect("clicked", self.set_nr_pieces, 12)
        #btn_box.attach(self.btn_12, 2,3,0,1,0,0)
        #cutter.pack_start(self.btn_12, False, False)
        #self.btn_16 = prepare_btn(Gtk.ToggleButton("16"), SLICE_BTN_WIDTH)
        #self.btn_16.connect("clicked", self.set_nr_pieces, 16)
        #btn_box.attach(self.btn_16, 3,4,0,1,0,0)
        #cutter.pack_start(self.btn_16, False, False)
        #cutter.pack_start(Gtk.Label(), True)
        #control_panel_box.pack_start(cutter, True)
        #spacer = Gtk.Label()
        #spacer.set_size_request(-1, 10)
        #control_panel_box.pack_start(spacer, False)
        #btn_box.attach(Gtk.Label(), 4,5,0,1)
        #control_panel_box.pack_start(btn_box, False, True, 0)

        self.thumb = ImageSelectorWidget(self._parent,
                                         frame_color=COLOR_FRAME_THUMB,
                                         prepare_btn_cb=prepare_btn,
                                         image_dir='images')
        #self.thumb.connect("category_press", self.do_select_category)
        #self.thumb.connect("image_press", self.set_nr_pieces)
        #control_panel_box.pack_start(self.thumb, False, True, 0)

        spacer = Gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, False, False, 0)

        # The game control buttons
        #btn_box = Gtk.Table(3,3,False)
        #btn_box.set_row_spacings(2)
        #btn_box.attach(Gtk.Label(), 0,1,0,3)
        #btn_box.attach(Gtk.Label(), 2,3,0,3)
        #self.btn_solve = prepare_btn(Gtk.Button(" "), 200)
        #self.labels_to_translate.append([self.btn_solve, _("Solve")])
        #self.btn_solve.connect("clicked", self.do_solve)
        #btn_box.attach(self.btn_solve, 1,2,0,1,0,0)
        #self.btn_shuffle = prepare_btn(Gtk.Button(" "), 200)
        #self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        #self.btn_shuffle.connect("clicked", self.do_shuffle)
        #btn_box.attach(self.btn_shuffle, 1,2,1,2,0,0)
        #self.btn_add = prepare_btn(Gtk.Button(" "), 200)
        #self.labels_to_translate.append([self.btn_add, _("My Picture")])
        #self.btn_add.connect("clicked", self.do_add_image)
        #btn_box.attach(self.btn_add, 1,2,2,3,0,0)
        #control_panel_box.pack_start(btn_box, False, True, 0)

        # Control panel end
        panel.pack_start(control_panel, True, True, 0)

        inner_table.attach(panel, 0, 1, 0, 1, 0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game_wrapper)

        lang_combo = prepare_btn(
            LanguageComboBox('org.worldwideworkshop.olpc.SliderPuzzle'))
        lang_combo.connect('changed', self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS,
                               border_color=COLOR_FRAME_CONTROLS)
        hbox = Gtk.HBox(False)
        vbox = Gtk.VBox(False)
        vbox.pack_start(lang_combo, True, True, 8)
        hbox.pack_start(vbox, True, True, 8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0, 1, 1, 2, Gtk.AttachOptions.FILL,
                           Gtk.AttachOptions.FILL)

        timer_box = BorderFrame(border=BORDER_ALL_BUT_LEFT,
                                bg_color=COLOR_BG_CONTROLS,
                                border_color=COLOR_FRAME_CONTROLS)
        timer_hbox = Gtk.HBox(False)
        self.timer = TimerWidget(bg_color=COLOR_BG_BUTTONS[0][1],
                                 fg_color=COLOR_FG_BUTTONS[0][1],
                                 lbl_color=COLOR_BG_BUTTONS[1][1])
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)

        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, True, 8)
        self.timer.connect('timer_toggle', self.timer_toggle_cb)

        self.msg_label = Gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True, True, 0)

        self.notebook = Gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box, None)
        inner_table.attach(self.notebook, 1, 2, 0, 1, Gtk.AttachOptions.FILL,
                           Gtk.AttachOptions.FILL)

        self.btn_lesson = prepare_btn(Gtk.Button(" "))
        self.labels_to_translate.append([self.btn_lesson, _("Lesson Plans")])
        self.btn_lesson.connect("clicked", self.do_lesson_plan)
        timer_hbox.pack_start(self.btn_lesson, False, True, 8)
        vbox = Gtk.VBox(False)
        vbox.pack_start(timer_hbox, True, True, 8)
        timer_box.add(vbox)
        inner_table.attach(timer_box, 1, 2, 1, 2,
                           Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND,
                           Gtk.AttachOptions.FILL)
        panel.pack_start(lang_box, False, False, 0)

        self.do_select_language(lang_combo)

        self.buddy_panel = BuddyPanel()
        self.buddy_panel.show()

        if not parent.shared_activity:
            self.do_select_category(self)
        else:
            self.set_message(_("Waiting for remote game..."))

        # Contest mode flags
        self.set_contest_mode(False)

        self._on_lesson_plan = False
示例#6
0
class SliderPuzzleUI(Gtk.Table):
    __gsignals__ = {
        'game-state-changed':
        (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (int, ))
    }

    def __init__(self, parent):
        super(SliderPuzzleUI, self).__init__(3, 3, False)
        self._parent = parent

        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE

        inner_table = Gtk.Table(2, 2, False)
        self.add(inner_table)
        self.from_journal = True
        self.game = SliderPuzzleWidget(9, GAME_SIZE, GAME_SIZE)
        self.game.connect("solved", self.do_solve)
        self.game.connect("moved", self.slider_move_cb)
        self._parent.connect("key_press_event", self.game.process_key)
        self._parent.connect("key_press_event", self.process_key)
        self.game.show()
        desktop = BorderFrame(border_color=COLOR_FRAME_CONTROLS)
        desktop.show()
        desktop.add(self.game)
        self.game_wrapper = Gtk.VBox()
        self.game_wrapper.show()
        inner = Gtk.HBox()
        inner.show()
        #BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
        #                                border_color=COLOR_FRAME_CONTROLS,
        #                                bg_color=COLOR_BG_CONTROLS)
        inner.pack_start(desktop, True, False, 0)
        self.game_wrapper.pack_start(inner, True, False, 0)

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = Gtk.VBox()

        # Logo image
        img_logo = Gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, False, False, 0)

        # Control panel has the image controls
        control_panel = BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
                                    border_color=COLOR_FRAME_CONTROLS,
                                    bg_color=COLOR_BG_CONTROLS)
        control_panel_box = Gtk.VBox()
        control_panel.add(control_panel_box)

        spacer = Gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, False, False, 0)

        # ...

        # Slice buttons
        #btn_box = Gtk.Table(1,5,False)
        #btn_box.set_col_spacings(5)
        #btn_box.set_row_spacings(5)
        #btn_box.attach(Gtk.Label(), 0,1,0,2)

        #spacer = Gtk.Label()
        #spacer.set_size_request(-1, 15)
        #control_panel_box.pack_start(spacer, False, False, 0)
        #cutter = Gtk.HBox(False, 8)
        #cutter.pack_start(Gtk.Label(), True)
        #self.btn_9 = prepare_btn(Gtk.ToggleButton("9"),SLICE_BTN_WIDTH)
        #self.btn_9.set_active(True)
        #self.btn_9.connect("clicked", self.set_nr_pieces, 9)
        #btn_box.attach(self.btn_9, 1,2,0,1,0,0)
        #cutter.pack_start(self.btn_9, False, False)
        #self.btn_12 = prepare_btn(Gtk.ToggleButton("12"), SLICE_BTN_WIDTH)
        #self.btn_12.connect("clicked", self.set_nr_pieces, 12)
        #btn_box.attach(self.btn_12, 2,3,0,1,0,0)
        #cutter.pack_start(self.btn_12, False, False)
        #self.btn_16 = prepare_btn(Gtk.ToggleButton("16"), SLICE_BTN_WIDTH)
        #self.btn_16.connect("clicked", self.set_nr_pieces, 16)
        #btn_box.attach(self.btn_16, 3,4,0,1,0,0)
        #cutter.pack_start(self.btn_16, False, False)
        #cutter.pack_start(Gtk.Label(), True)
        #control_panel_box.pack_start(cutter, True)
        #spacer = Gtk.Label()
        #spacer.set_size_request(-1, 10)
        #control_panel_box.pack_start(spacer, False)
        #btn_box.attach(Gtk.Label(), 4,5,0,1)
        #control_panel_box.pack_start(btn_box, False, True, 0)

        self.thumb = ImageSelectorWidget(self._parent,
                                         frame_color=COLOR_FRAME_THUMB,
                                         prepare_btn_cb=prepare_btn,
                                         image_dir='images')
        #self.thumb.connect("category_press", self.do_select_category)
        #self.thumb.connect("image_press", self.set_nr_pieces)
        #control_panel_box.pack_start(self.thumb, False, True, 0)

        spacer = Gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, False, False, 0)

        # The game control buttons
        #btn_box = Gtk.Table(3,3,False)
        #btn_box.set_row_spacings(2)
        #btn_box.attach(Gtk.Label(), 0,1,0,3)
        #btn_box.attach(Gtk.Label(), 2,3,0,3)
        #self.btn_solve = prepare_btn(Gtk.Button(" "), 200)
        #self.labels_to_translate.append([self.btn_solve, _("Solve")])
        #self.btn_solve.connect("clicked", self.do_solve)
        #btn_box.attach(self.btn_solve, 1,2,0,1,0,0)
        #self.btn_shuffle = prepare_btn(Gtk.Button(" "), 200)
        #self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        #self.btn_shuffle.connect("clicked", self.do_shuffle)
        #btn_box.attach(self.btn_shuffle, 1,2,1,2,0,0)
        #self.btn_add = prepare_btn(Gtk.Button(" "), 200)
        #self.labels_to_translate.append([self.btn_add, _("My Picture")])
        #self.btn_add.connect("clicked", self.do_add_image)
        #btn_box.attach(self.btn_add, 1,2,2,3,0,0)
        #control_panel_box.pack_start(btn_box, False, True, 0)

        # Control panel end
        panel.pack_start(control_panel, True, True, 0)

        inner_table.attach(panel, 0, 1, 0, 1, 0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game_wrapper)

        lang_combo = prepare_btn(
            LanguageComboBox('org.worldwideworkshop.olpc.SliderPuzzle'))
        lang_combo.connect('changed', self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS,
                               border_color=COLOR_FRAME_CONTROLS)
        hbox = Gtk.HBox(False)
        vbox = Gtk.VBox(False)
        vbox.pack_start(lang_combo, True, True, 8)
        hbox.pack_start(vbox, True, True, 8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0, 1, 1, 2, Gtk.AttachOptions.FILL,
                           Gtk.AttachOptions.FILL)

        timer_box = BorderFrame(border=BORDER_ALL_BUT_LEFT,
                                bg_color=COLOR_BG_CONTROLS,
                                border_color=COLOR_FRAME_CONTROLS)
        timer_hbox = Gtk.HBox(False)
        self.timer = TimerWidget(bg_color=COLOR_BG_BUTTONS[0][1],
                                 fg_color=COLOR_FG_BUTTONS[0][1],
                                 lbl_color=COLOR_BG_BUTTONS[1][1])
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)

        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, True, 8)
        self.timer.connect('timer_toggle', self.timer_toggle_cb)

        self.msg_label = Gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True, True, 0)

        self.notebook = Gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box, None)
        inner_table.attach(self.notebook, 1, 2, 0, 1, Gtk.AttachOptions.FILL,
                           Gtk.AttachOptions.FILL)

        self.btn_lesson = prepare_btn(Gtk.Button(" "))
        self.labels_to_translate.append([self.btn_lesson, _("Lesson Plans")])
        self.btn_lesson.connect("clicked", self.do_lesson_plan)
        timer_hbox.pack_start(self.btn_lesson, False, True, 8)
        vbox = Gtk.VBox(False)
        vbox.pack_start(timer_hbox, True, True, 8)
        timer_box.add(vbox)
        inner_table.attach(timer_box, 1, 2, 1, 2,
                           Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND,
                           Gtk.AttachOptions.FILL)
        panel.pack_start(lang_box, False, False, 0)

        self.do_select_language(lang_combo)

        self.buddy_panel = BuddyPanel()
        self.buddy_panel.show()

        if not parent.shared_activity:
            self.do_select_category(self)
        else:
            self.set_message(_("Waiting for remote game..."))

        # Contest mode flags
        self.set_contest_mode(False)

        self._on_lesson_plan = False

    def set_message(self, msg, frommesh=False):
        if frommesh and self.get_game_state() < GAME_STARTED:
            return
        self.msg_label.set_label(msg)

    def is_initiator(self):
        return self._parent.initiating

    def set_readonly(self, ro=True):
        self.thumb.set_readonly(ro)
        #for b in (self.btn_9, self.btn_12, self.btn_16):
        #    if not b.get_active():
        #        b.set_sensitive(False)

    @utils.trace
    def timer_toggle_cb(self, evt, running):
        logging.debug("Timer running: %s" % str(running))
        if self._contest_mode and running:
            self.set_game_state(GAME_STARTED)
        self._send_status_update()
        #if self._contest_mode:
        #    if running:
        #        if self.game.filename and not self.game_wrapper.get_parent():
        #            self.game_box.pop()
        #    else:
        #        if not self.buddy_panel.get_parent():
        #            self.game_box.push(self.buddy_panel)

    def _set_control_area(self, *args):
        """ The controls area below the logo needs different actions when in contest mode,
        and also if we are the contest initiators or not. """
        if self._contest_mode:
            if self.get_game_state() > GAME_IDLE:
                self.set_readonly()
            else:
                if self.is_initiator():
                    if self.timer.is_reset():
                        self.set_message(
                            _("Select image and press Start Game..."))
                    else:
                        self.set_game_state(GAME_STARTED)
                else:
                    self.set_message(
                        _("Waiting for Puzzle image to be chosen..."))
                    self.set_button_translation(self.btn_add, "Buddies")
                    self.btn_add.get_child().set_label(_("Buddies"))

    def set_game_state(self, state, force=False):
        if state[0] > self._state[0] or force:
            self._state = state
            self.emit('game-state-changed', state[0])
            self._set_control_area()
            if state == GAME_STARTED:
                self.set_button_translation(self.btn_add, "Buddies")
                self.btn_add.get_child().set_label(_("Buddies"))
            self._send_status_update()

    def get_game_state(self):
        return self._state

    def set_button_translation(self, btn, translation):
        for i in range(len(self.labels_to_translate)):
            if self.labels_to_translate[i][0] == btn:
                self.labels_to_translate[i][1] = translation
                break

    def set_contest_mode(self, mode):
        if getattr(self, '_contest_mode', None) != mode:
            self._contest_mode = bool(mode)
            self._set_control_area()
            if self._contest_mode:
                self.set_button_translation(self.btn_solve, "Give Up")
                self.btn_solve.get_child().set_label(_("Give Up"))
                self.set_button_translation(self.btn_shuffle, "Start Game")
                self.btn_shuffle.get_child().set_label(_("Start Game"))

    def is_contest_mode(self):
        return self._contest_mode  # and self.game.filename

    def do_select_language(self, combo, *args):
        self.selected_lang_details = combo.translations[combo.get_active()]
        self.refresh_labels()

    def refresh_labels(self, first_time=False):
        self._parent.set_title(_("Slider Puzzle Activity"))
        for lbl in self.labels_to_translate:
            if isinstance(lbl[0], Gtk.Button):
                lbl[0].get_child().set_label(_(lbl[1]))
            else:
                lbl[0].set_label(_(lbl[1]))
        if not self.game_wrapper.get_parent() and not first_time:
            self.game_box.pop()
            if self.notebook.get_current_page() == 1:
                m = self.do_lesson_plan
            else:
                m = self.do_select_category
            m(self)

    @utils.trace
    def set_nr_pieces(self,
                      btn=None,
                      nr_pieces=None,
                      path=None,
                      path_from_journal=None):
        #if isinstance(btn, gtk.ToggleButton) and not btn.get_active():
        #    return
        logger.debug('final path')
        if self.is_contest_mode() and nr_pieces == self.game.get_nr_pieces():
            return

        #if isinstance(btn, gtk.ToggleButton):
        #if not btn.get_active():
        #        if nr_pieces == self.game.get_nr_pieces():
        #            logging.debug("A")
        #            btn.set_active(True)
        #        return

        if nr_pieces is None:
            nr_pieces = self.game.get_nr_pieces()
        if btn is None:  #not isinstance(btn, gtk.ToggleButton):
            if self._contest_mode:
                self.set_game_state(GAME_STARTED)
                #for n, b in ((9, self.btn_9),(12, self.btn_12),(16, self.btn_16)):
                #    if n == nr_pieces and not b.get_active():
                #        logging.debug("B")
                #        b.set_sensitive(True)
                #        b.set_active(True)
                return
        #if self.thumb.has_image():
        logger.debug('nr ends1')
        if not self.game_wrapper.get_parent():
            self.game_box.pop()
            logger.debug('nr ends2')
        logger.debug('nr ends3')

        if not path:
            self.yy = self.pre_path
            logger.debug('nr ends0')
        else:
            self.yy = path
        if self.from_journal:
            self.yy = path_from_journal

        self.px = utils.load_image(self.yy)
        logger.debug('nr ends5')
        self.game.load_image(self.px)
        logger.debug('nr ends6')
        #self.thumb.set_game_widget(self.game)
        logger.debug('nr ends4')
        self.game.set_nr_pieces(nr_pieces)
        self.timer.reset(False)
        #if isinstance(btn, gtk.ToggleButton):
        #for n, b in ((9, self.btn_9),(12, self.btn_12),(16, self.btn_16)):
        #        if b is not btn:
        #            logging.debug("C")
        #            b.set_active(False)
        #            b.set_sensitive(not self._contest_mode)

    def _set_nr_pieces_pre(self, img_path):
        logger.debug('pre path')
        self.from_journal = False
        self.pre_path = img_path
        self.set_nr_pieces(nr_pieces=9, path=img_path)

    def do_shuffle(self, *args, **kwargs):
        if self._contest_mode:
            if self.get_game_state() > GAME_IDLE:
                # Restart
                self.set_game_state(GAME_STARTED, True)
                self._parent.frozen.thaw()
                self.timer.reset(True)
            elif self.game.filename is not None and self.timer.is_reset():
                # Start
                self.timer.start()
        #elif self.thumb.has_image():
        if not self.game_wrapper.get_parent():
            self.game_box.pop()
        self.game.load_image(self.px)
        #self.thumb.set_game_widget(self.game)
        self.game.randomize()
        self.timer.reset(False)

    def slider_move_cb(self, *args):
        if not self.timer.is_running():
            self.timer.start()

    def do_solve(self, btn):
        if self.game.filename is not None:
            if not self.game_wrapper.get_parent():
                self.game_box.pop()
            self.game.show_image()
            self.timer.stop(True)
            if self._contest_mode and self.get_game_state() == GAME_STARTED:
                if btn != self.btn_solve:
                    self.set_game_state(GAME_FINISHED)
                    self.set_message(_("Puzzle Solved!"))
                else:
                    self.set_game_state(GAME_QUIT)
                    self.set_message(_("Gave Up"))
        self._set_control_area()


#    @utils.trace
#    def do_select_category(self, owner, *args, **kwargs):
#        if isinstance(owner, CategorySelector):
#            self.thumb.set_image_dir(args[0])
#            #self.game_box.pop()
#            if not self.thumb.category.has_images():
#                self.do_add_image(None)
#        else:
#            if self.game_wrapper.get_parent():
#                s = CategorySelector("images", _("Choose a Subject"), self.thumb.get_image_dir())
#                s.connect("selected", self.do_select_category)
#                s.show()
#                self.game_box.push(s)
#                s.grab_focus()
#            else:
#                self.game_box.pop()

    def do_select_category(self, o, *args):
        if isinstance(o, CategorySelector):
            self.thumb.set_image_dir(args[0])
            #if not self.thumb.category.has_images():
            #    self.do_add_image(None)
        else:
            if self.game_wrapper.get_parent():
                logging.debug("Current cat dir=%s" %
                              self.thumb.get_image_dir())
                s = CategorySelector(_("Choose a Subject"),
                                     self.thumb.get_image_dir(),
                                     path="images")
                #extra=('images/Sequencing Puzzles',))
                s.connect("selected", self.do_select_category)
                s.show()
                self.game_box.push(s)
                s.grab_focus()
            else:
                self.game_box.pop()

    @utils.trace
    def do_add_image(self, widget, *args):
        """ Use to trigger and process the My Own Image selector.
        Also used for showing the buddies panel on contest mode"""
        self.from_journal = True
        if self._contest_mode and self.get_game_state() >= GAME_STARTED:
            # Buddy Panel
            if not self.buddy_panel.get_parent():
                self.timer.stop()
                self.game_box.push(self.buddy_panel)
            else:
                self.game_box.pop()
        elif self._contest_mode and not self.is_initiator():
            # do nothing
            pass
        else:
            self.add_image()
            #self.set_nr_pieces(nr_pieces = 9)
            self.do_shuffle()

        #if response is None:
        #    else:
        #        # My Own Image selector
        #        imgfilter = gtk.FileFilter()
        #        imgfilter.set_name(_("Image Files"))
        #        imgfilter.add_mime_type('image/*')
        #        fd = gtk.FileChooserDialog(title=_("Select Image File"), parent=self._parent,
        #                                   action=gtk.FILE_CHOOSER_ACTION_OPEN,
        #                                   buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        #
        #        fd.set_current_folder(os.path.expanduser("~/"))
        #        fd.set_modal(True)
        #        fd.add_filter(imgfilter)
        #        fd.connect("response", self.do_add_image)
        #        fd.resize(800,600)
        #        fd.show()
        #else:
        #    if response == gtk.RESPONSE_ACCEPT:
        #        if self.thumb.load_image(widget.get_filename()):
        #            self.do_shuffle()
        #        else:
        #            err = gtk.MessageDialog(self._parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
        #                                    _("Not a valid image file"))
        #            err.run()
        #            err.destroy()
        #            return
        #    widget.destroy()
    def add_image(self, *args):  #widget=None, response=None, *args):
        """ Use to trigger and process the My Own Image selector. """

        if hasattr(mime, 'GENERIC_TYPE_IMAGE'):
            filter = {'what_filter': mime.GENERIC_TYPE_IMAGE}
        else:
            filter = {}

        chooser = ObjectChooser(self._parent, **filter)
        try:
            result = chooser.run()
            if result == Gtk.ResponseType.ACCEPT:
                jobject = chooser.get_selected_object()
                if jobject and jobject.file_path:
                    #if self.load_image(str(jobject.file_path), True):
                    self.set_nr_pieces(nr_pieces=9,
                                       path_from_journal=str(
                                           jobject.file_path))
                    pass
                # else:
                #     err = Gtk.MessageDialog(self._parent, Gtk.DialogFlags.MODAL, Gtk.MESSAGE_ERROR, Gtk.BUTTONS_OK,
                #                             _("Not a valid image file"))
                #     err.run()
                #     err.destroy()
                #     return
        finally:
            chooser.destroy()
            del chooser

    def do_lesson_plan(self, btn):
        if self._on_lesson_plan:
            return
        try:
            self._on_lesson_plan = True
            if self._contest_mode and self.get_game_state() < GAME_STARTED:
                return
            page = self.notebook.get_current_page()
            if page == 0:
                self.timer.stop()
                self.timer.props.sensitive = False
                if self.notebook.get_n_pages() == 1:
                    lessons = NotebookReaderWidget('lessons',
                                                   self.selected_lang_details)
                    lessons.connect('parent-set', self.do_lesson_plan_reparent)
                    lessons.show_all()
                    self.notebook.append_page(lessons, None)
            else:
                self.timer.props.sensitive = True
            self.notebook.set_current_page(int(not page))
        finally:
            self._on_lesson_plan = False

    def do_lesson_plan_reparent(self, widget, oldparent):
        if widget.parent is None:
            self.set_button_translation(self.btn_lesson, "Lesson Plans")
            self.btn_lesson.get_child().set_label(_("Lesson Plans"))
        else:
            self.set_button_translation(self.btn_lesson, "Close Lesson")
            self.btn_lesson.get_child().set_label(_("Close Lesson"))

    def process_key(self, w, e):
        """ The callback for key processing. The button shortcuts are all defined here. """
        k = Gdk.keyval_name(e.keyval)
        if not isinstance(self._parent.get_focus(), Gtk.Editable):
            if k == '1':
                self.set_nr_pieces(nr_pieces=9)
                return True
            if k == '2':
                self.set_nr_pieces(nr_pieces=12)
                return True
            if k == '3':
                self.set_nr_pieces(nr_pieces=16)
                return True
            if k == 'Return':
                self.set_nr_pieces(None)
                return True

            if k in ('Escape', 'q'):
                gtk.main_quit()
                return True
            return False

    @utils.trace
    def _freeze(self, journal=True):
        """ returns a json writable object representation capable of being used to restore our current status """
        return (self.thumb._freeze(), self.game._freeze(journal=journal),
                self.game.get_nr_pieces(), self.timer._freeze())

    def _thaw(self, obj):
        """ retrieves a frozen status from a python object, as per _freeze """
        logging.debug('_thaw: %s' % obj)

        if not obj[1]['image']:
            return

        if not obj[1].has_key('image'):
            self.game.load_image(self.thumb.get_image())
        self.set_nr_pieces(None, obj[2])
        logging.debug(obj[1].keys())
        wimg = obj[1].has_key('image')
        self.game._thaw(obj[1])
        if wimg:
            logging.debug("Forcing thumb image from the one in game")
            self.thumb.load_pb(self.game.image)

        self.timer.reset()
        self.timer._thaw(obj[3])
        self.game_box.pop()

    @utils.trace
    def _send_status_update(self):
        """ Send a status update signal """
        if self._parent.shared_activity:
            if self.get_game_state() == GAME_STARTED:
                if self.thumb.has_image():
                    self.set_message(_("Game Started!"))
            self._parent.game_tube.StatusUpdate(self._state[1],
                                                self.timer.is_running(),
                                                self.timer.ellapsed())
示例#7
0
    def __init__(self, parent):
        super(SliderPuzzleUI, self).__init__(3,3,False)
        self._parent = parent

        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE

        inner_table = gtk.Table(2,2,False)
        self.add(inner_table)

        self.game = SliderPuzzleWidget(9, GAME_SIZE, GAME_SIZE)
        self.game.connect("solved", self.do_solve)
        self.game.connect("moved", self.slider_move_cb)
        self._parent.connect("key_press_event",self.game.process_key)
        self._parent.connect("key_press_event",self.process_key)
        self.game.show()
        desktop = BorderFrame(border_color=COLOR_FRAME_CONTROLS)
        desktop.show()
        desktop.add(self.game)
        self.game_wrapper = gtk.VBox()
        self.game_wrapper.show()
        inner = gtk.HBox()
        inner.show()
        #BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
        #                                border_color=COLOR_FRAME_CONTROLS,
        #                                bg_color=COLOR_BG_CONTROLS)
        inner.pack_start(desktop, expand=True, fill=False)
        self.game_wrapper.pack_start(inner, expand=True, fill=False)

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = gtk.VBox()
        
        # Logo image
        img_logo = gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, expand=False, fill=False)

        # Control panel has the image controls
        control_panel = BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
                                    border_color=COLOR_FRAME_CONTROLS,
                                    bg_color=COLOR_BG_CONTROLS)
        control_panel_box = gtk.VBox()
        control_panel.add(control_panel_box)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # ...

        # Slice buttons
        btn_box = gtk.Table(1,5,False)
        btn_box.set_col_spacings(5)
        btn_box.set_row_spacings(5)
        btn_box.attach(gtk.Label(), 0,1,0,2)

        #spacer = gtk.Label()
        #spacer.set_size_request(-1, 15)
        #control_panel_box.pack_start(spacer, expand=False, fill=False)
        #cutter = gtk.HBox(False, 8)
        #cutter.pack_start(gtk.Label(), True)
        self.btn_9 = prepare_btn(gtk.ToggleButton("9"),SLICE_BTN_WIDTH)
        self.btn_9.set_active(True)
        self.btn_9.connect("clicked", self.set_nr_pieces, 9)
        btn_box.attach(self.btn_9, 1,2,0,1,0,0)
        #cutter.pack_start(self.btn_9, False, False)
        self.btn_12 = prepare_btn(gtk.ToggleButton("12"), SLICE_BTN_WIDTH)
        self.btn_12.connect("clicked", self.set_nr_pieces, 12)
        btn_box.attach(self.btn_12, 2,3,0,1,0,0)
        #cutter.pack_start(self.btn_12, False, False)
        self.btn_16 = prepare_btn(gtk.ToggleButton("16"), SLICE_BTN_WIDTH)
        self.btn_16.connect("clicked", self.set_nr_pieces, 16)
        btn_box.attach(self.btn_16, 3,4,0,1,0,0)
        #cutter.pack_start(self.btn_16, False, False)
        #cutter.pack_start(gtk.Label(), True)
        #control_panel_box.pack_start(cutter, True)
        #spacer = gtk.Label()
        #spacer.set_size_request(-1, 10)
        #control_panel_box.pack_start(spacer, False)
        btn_box.attach(gtk.Label(), 4,5,0,1)
        control_panel_box.pack_start(btn_box, expand=False)





        self.thumb = ImageSelectorWidget(self._parent,frame_color=COLOR_FRAME_THUMB, prepare_btn_cb=prepare_btn, image_dir='images')
        self.thumb.connect("category_press", self.do_select_category)
        self.thumb.connect("image_press", self.set_nr_pieces)
        control_panel_box.pack_start(self.thumb, False)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # The game control buttons
        btn_box = gtk.Table(3,3,False)
        btn_box.set_row_spacings(2)
        btn_box.attach(gtk.Label(), 0,1,0,3)
        btn_box.attach(gtk.Label(), 2,3,0,3)
        self.btn_solve = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_solve, _("Solve")])
        self.btn_solve.connect("clicked", self.do_solve)
        btn_box.attach(self.btn_solve, 1,2,0,1,0,0)
        self.btn_shuffle = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        self.btn_shuffle.connect("clicked", self.do_shuffle)
        btn_box.attach(self.btn_shuffle, 1,2,1,2,0,0)
        self.btn_add = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_add, _("My Picture")])
        self.btn_add.connect("clicked", self.do_add_image)
        btn_box.attach(self.btn_add, 1,2,2,3,0,0)
        control_panel_box.pack_start(btn_box, False)

        # Control panel end
        panel.pack_start(control_panel, expand=True, fill=True)

        inner_table.attach(panel, 0,1,0,1,0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game_wrapper)

        lang_combo = prepare_btn(LanguageComboBox('org.worldwideworkshop.olpc.SliderPuzzle'))
        lang_combo.connect('changed', self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS,
                               border_color=COLOR_FRAME_CONTROLS)
        hbox = gtk.HBox(False)
        vbox = gtk.VBox(False)
        vbox.pack_start(lang_combo, padding=8)
        hbox.pack_start(vbox, padding=8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0,1,1,2,gtk.FILL, gtk.FILL)

        timer_box = BorderFrame(border=BORDER_ALL_BUT_LEFT,
                                bg_color=COLOR_BG_CONTROLS,
                                border_color=COLOR_FRAME_CONTROLS)
        timer_hbox = gtk.HBox(False)
        self.timer = TimerWidget(bg_color=COLOR_BG_BUTTONS[0][1],
                                 fg_color=COLOR_FG_BUTTONS[0][1],
                                 lbl_color=COLOR_BG_BUTTONS[1][1])
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)
        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, padding=8)
        self.timer.connect('timer_toggle', self.timer_toggle_cb)

        self.msg_label = gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True)
        
        self.notebook = gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box)
        inner_table.attach(self.notebook, 1,2,0,1, gtk.FILL, gtk.FILL)

        self.btn_lesson = prepare_btn(gtk.Button(" "))
        self.labels_to_translate.append([self.btn_lesson, _("Lesson Plans")])
        self.btn_lesson.connect("clicked", self.do_lesson_plan)
        timer_hbox.pack_start(self.btn_lesson, False, padding=8)
        vbox = gtk.VBox(False)
        vbox.pack_start(timer_hbox, padding=8)
        timer_box.add(vbox)
        inner_table.attach(timer_box, 1,2,1,2,gtk.FILL|gtk.EXPAND, gtk.FILL)
        #panel.pack_start(lang_box, expand=False, fill=False)

        self.do_select_language(lang_combo)
        
        self.buddy_panel = BuddyPanel()
        self.buddy_panel.show()

        if not parent._shared_activity:
            self.do_select_category(self)
        else:
            self.set_message(_("Waiting for remote game..."))

        # Contest mode flags
        self.set_contest_mode(False)

        self._on_lesson_plan = False
示例#8
0
class SliderPuzzleUI (gtk.Table):
    __gsignals__ = {'game-state-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (int,))}
    
    def __init__(self, parent):
        super(SliderPuzzleUI, self).__init__(3,3,False)
        self._parent = parent

        # We want the translatables to be detected but not yet translated
        global _
        _ = lambda x: x
        self.labels_to_translate = []

        self._state = GAME_IDLE

        inner_table = gtk.Table(2,2,False)
        self.add(inner_table)

        self.game = SliderPuzzleWidget(9, GAME_SIZE, GAME_SIZE)
        self.game.connect("solved", self.do_solve)
        self.game.connect("moved", self.slider_move_cb)
        self._parent.connect("key_press_event",self.game.process_key)
        self._parent.connect("key_press_event",self.process_key)
        self.game.show()
        desktop = BorderFrame(border_color=COLOR_FRAME_CONTROLS)
        desktop.show()
        desktop.add(self.game)
        self.game_wrapper = gtk.VBox()
        self.game_wrapper.show()
        inner = gtk.HBox()
        inner.show()
        #BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
        #                                border_color=COLOR_FRAME_CONTROLS,
        #                                bg_color=COLOR_BG_CONTROLS)
        inner.pack_start(desktop, expand=True, fill=False)
        self.game_wrapper.pack_start(inner, expand=True, fill=False)

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = gtk.VBox()
        
        # Logo image
        img_logo = gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, expand=False, fill=False)

        # Control panel has the image controls
        control_panel = BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
                                    border_color=COLOR_FRAME_CONTROLS,
                                    bg_color=COLOR_BG_CONTROLS)
        control_panel_box = gtk.VBox()
        control_panel.add(control_panel_box)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # ...

        # Slice buttons
        btn_box = gtk.Table(1,5,False)
        btn_box.set_col_spacings(5)
        btn_box.set_row_spacings(5)
        btn_box.attach(gtk.Label(), 0,1,0,2)

        #spacer = gtk.Label()
        #spacer.set_size_request(-1, 15)
        #control_panel_box.pack_start(spacer, expand=False, fill=False)
        #cutter = gtk.HBox(False, 8)
        #cutter.pack_start(gtk.Label(), True)
        self.btn_9 = prepare_btn(gtk.ToggleButton("9"),SLICE_BTN_WIDTH)
        self.btn_9.set_active(True)
        self.btn_9.connect("clicked", self.set_nr_pieces, 9)
        btn_box.attach(self.btn_9, 1,2,0,1,0,0)
        #cutter.pack_start(self.btn_9, False, False)
        self.btn_12 = prepare_btn(gtk.ToggleButton("12"), SLICE_BTN_WIDTH)
        self.btn_12.connect("clicked", self.set_nr_pieces, 12)
        btn_box.attach(self.btn_12, 2,3,0,1,0,0)
        #cutter.pack_start(self.btn_12, False, False)
        self.btn_16 = prepare_btn(gtk.ToggleButton("16"), SLICE_BTN_WIDTH)
        self.btn_16.connect("clicked", self.set_nr_pieces, 16)
        btn_box.attach(self.btn_16, 3,4,0,1,0,0)
        #cutter.pack_start(self.btn_16, False, False)
        #cutter.pack_start(gtk.Label(), True)
        #control_panel_box.pack_start(cutter, True)
        #spacer = gtk.Label()
        #spacer.set_size_request(-1, 10)
        #control_panel_box.pack_start(spacer, False)
        btn_box.attach(gtk.Label(), 4,5,0,1)
        control_panel_box.pack_start(btn_box, expand=False)





        self.thumb = ImageSelectorWidget(self._parent,frame_color=COLOR_FRAME_THUMB, prepare_btn_cb=prepare_btn, image_dir='images')
        self.thumb.connect("category_press", self.do_select_category)
        self.thumb.connect("image_press", self.set_nr_pieces)
        control_panel_box.pack_start(self.thumb, False)

        spacer = gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, expand=False, fill=False)

        # The game control buttons
        btn_box = gtk.Table(3,3,False)
        btn_box.set_row_spacings(2)
        btn_box.attach(gtk.Label(), 0,1,0,3)
        btn_box.attach(gtk.Label(), 2,3,0,3)
        self.btn_solve = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_solve, _("Solve")])
        self.btn_solve.connect("clicked", self.do_solve)
        btn_box.attach(self.btn_solve, 1,2,0,1,0,0)
        self.btn_shuffle = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_shuffle, _("Shuffle")])
        self.btn_shuffle.connect("clicked", self.do_shuffle)
        btn_box.attach(self.btn_shuffle, 1,2,1,2,0,0)
        self.btn_add = prepare_btn(gtk.Button(" "), 200)
        self.labels_to_translate.append([self.btn_add, _("My Picture")])
        self.btn_add.connect("clicked", self.do_add_image)
        btn_box.attach(self.btn_add, 1,2,2,3,0,0)
        control_panel_box.pack_start(btn_box, False)

        # Control panel end
        panel.pack_start(control_panel, expand=True, fill=True)

        inner_table.attach(panel, 0,1,0,1,0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game_wrapper)

        lang_combo = prepare_btn(LanguageComboBox('org.worldwideworkshop.olpc.SliderPuzzle'))
        lang_combo.connect('changed', self.do_select_language)
        # Push the gettext translator into the global namespace
        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS,
                               border_color=COLOR_FRAME_CONTROLS)
        hbox = gtk.HBox(False)
        vbox = gtk.VBox(False)
        vbox.pack_start(lang_combo, padding=8)
        hbox.pack_start(vbox, padding=8)
        lang_box.add(hbox)
        inner_table.attach(lang_box, 0,1,1,2,gtk.FILL, gtk.FILL)

        timer_box = BorderFrame(border=BORDER_ALL_BUT_LEFT,
                                bg_color=COLOR_BG_CONTROLS,
                                border_color=COLOR_FRAME_CONTROLS)
        timer_hbox = gtk.HBox(False)
        self.timer = TimerWidget(bg_color=COLOR_BG_BUTTONS[0][1],
                                 fg_color=COLOR_FG_BUTTONS[0][1],
                                 lbl_color=COLOR_BG_BUTTONS[1][1])
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)
        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, padding=8)
        self.timer.connect('timer_toggle', self.timer_toggle_cb)

        self.msg_label = gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True)
        
        self.notebook = gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box)
        inner_table.attach(self.notebook, 1,2,0,1, gtk.FILL, gtk.FILL)

        self.btn_lesson = prepare_btn(gtk.Button(" "))
        self.labels_to_translate.append([self.btn_lesson, _("Lesson Plans")])
        self.btn_lesson.connect("clicked", self.do_lesson_plan)
        timer_hbox.pack_start(self.btn_lesson, False, padding=8)
        vbox = gtk.VBox(False)
        vbox.pack_start(timer_hbox, padding=8)
        timer_box.add(vbox)
        inner_table.attach(timer_box, 1,2,1,2,gtk.FILL|gtk.EXPAND, gtk.FILL)
        #panel.pack_start(lang_box, expand=False, fill=False)

        self.do_select_language(lang_combo)
        
        self.buddy_panel = BuddyPanel()
        self.buddy_panel.show()

        if not parent._shared_activity:
            self.do_select_category(self)
        else:
            self.set_message(_("Waiting for remote game..."))

        # Contest mode flags
        self.set_contest_mode(False)

        self._on_lesson_plan = False

    def set_message (self, msg, frommesh=False):
        if frommesh and self.get_game_state() < GAME_STARTED:
            return
        self.msg_label.set_label(msg)

    def is_initiator (self):
        return self._parent.initiating

    def set_readonly (self, ro=True):
        self.thumb.set_readonly(ro)
        for b in (self.btn_9, self.btn_12, self.btn_16):
            if not b.get_active():
                b.set_sensitive(False)

    @utils.trace
    def timer_toggle_cb (self, evt, running):
        logging.debug("Timer running: %s" % str(running))
        if self._contest_mode and running:
            self.set_game_state(GAME_STARTED)
        self._send_status_update()
        #if self._contest_mode:
        #    if running:
        #        if self.game.filename and not self.game_wrapper.get_parent():
        #            self.game_box.pop()
        #    else:
        #        if not self.buddy_panel.get_parent():
        #            self.game_box.push(self.buddy_panel)

    def _set_control_area (self, *args):
        """ The controls area below the logo needs different actions when in contest mode,
        and also if we are the contest initiators or not. """
        if self._contest_mode:
            if self.get_game_state() > GAME_IDLE:
                self.set_readonly()
            else:
                if self.is_initiator():
                    if self.timer.is_reset():
                        self.set_message(_("Select image and press Start Game..."))
                    else:
                        self.set_game_state(GAME_STARTED)
                else:
                    self.set_message(_("Waiting for Puzzle image to be chosen..."))
                    self.set_button_translation(self.btn_add, "Buddies")
                    self.btn_add.get_child().set_label(_("Buddies"))

    def set_game_state (self, state, force=False):
        if state[0] > self._state[0] or force:
            self._state = state
            self.emit('game-state-changed', state[0])
            self._set_control_area()
            if state == GAME_STARTED:
                self.set_button_translation(self.btn_add, "Buddies")
                self.btn_add.get_child().set_label(_("Buddies"))
            self._send_status_update()

    def get_game_state (self):
        return self._state

    def set_button_translation (self, btn, translation):
        for i in range(len(self.labels_to_translate)):
            if self.labels_to_translate[i][0] == btn:
                self.labels_to_translate[i][1] = translation
                break

    def set_contest_mode (self, mode):
        if getattr(self, '_contest_mode', None) != mode:
            self._contest_mode = bool(mode)
            self._set_control_area()
            if self._contest_mode:
                self.set_button_translation(self.btn_solve, "Give Up")
                self.btn_solve.get_child().set_label(_("Give Up"))
                self.set_button_translation(self.btn_shuffle, "Start Game")
                self.btn_shuffle.get_child().set_label(_("Start Game"))
        
    def is_contest_mode (self):
        return self._contest_mode# and self.game.filename

    def do_select_language (self, combo, *args):
        self.selected_lang_details = combo.translations[combo.get_active()]
        self.refresh_labels()

    def refresh_labels (self, first_time=False):
        self._parent.set_title(_("Slider Puzzle Activity"))
        for lbl in self.labels_to_translate:
            if isinstance(lbl[0], gtk.Button):
                lbl[0].get_child().set_label(_(lbl[1]))
            else:
                lbl[0].set_label(_(lbl[1]))
        if not self.game_wrapper.get_parent() and not first_time:
            self.game_box.pop()
            if self.notebook.get_current_page() == 1:
                m = self.do_lesson_plan
            else:
                m = self.do_select_category
            m(self)

    @utils.trace
    def set_nr_pieces (self, btn, nr_pieces=None):
        #if isinstance(btn, gtk.ToggleButton) and not btn.get_active():
        #    return
        if self.is_contest_mode() and isinstance(btn, gtk.ToggleButton) and nr_pieces == self.game.get_nr_pieces():
            return
        if isinstance(btn, gtk.ToggleButton):
            if not btn.get_active():
                if nr_pieces == self.game.get_nr_pieces():
                    logging.debug("A")
                    btn.set_active(True)
                return
        if nr_pieces is None:
            nr_pieces = self.game.get_nr_pieces()
        if btn is None: #not isinstance(btn, gtk.ToggleButton):
            if self._contest_mode:
                self.set_game_state(GAME_STARTED)
            for n, b in ((9, self.btn_9),(12, self.btn_12),(16, self.btn_16)):
                if n == nr_pieces and not b.get_active():
                    logging.debug("B")
                    b.set_sensitive(True)
                    b.set_active(True)
                    return
        if self.thumb.has_image():
            if not self.game_wrapper.get_parent():
                self.game_box.pop()
            self.game.load_image(self.thumb.get_image())
            #self.thumb.set_game_widget(self.game)
        self.game.set_nr_pieces(nr_pieces)
        self.timer.reset(False)
        if isinstance(btn, gtk.ToggleButton):
            for n, b in ((9, self.btn_9),(12, self.btn_12),(16, self.btn_16)):
                if b is not btn:
                    logging.debug("C")
                    b.set_active(False)
                    b.set_sensitive(not self._contest_mode)

    def do_shuffle (self, *args, **kwargs):
        if self._contest_mode:
            if self.get_game_state() > GAME_IDLE:
                # Restart
                self.set_game_state(GAME_STARTED, True)
                self._parent.frozen.thaw()
                self.timer.reset(True)
            elif self.game.filename is not None and self.timer.is_reset():
                # Start
                self.timer.start()
        elif self.thumb.has_image():
            if not self.game_wrapper.get_parent():
                self.game_box.pop()
            self.game.load_image(self.thumb.get_image())
            #self.thumb.set_game_widget(self.game)
            self.game.randomize()
            self.timer.reset(False)

    def slider_move_cb (self, *args):
        if not self.timer.is_running():
            self.timer.start()
        
    def do_solve (self, btn):
        if self.game.filename is not None:
            if not self.game_wrapper.get_parent():
                self.game_box.pop()
            self.game.show_image()
            self.timer.stop(True)
            if self._contest_mode and self.get_game_state() == GAME_STARTED:
                if btn != self.btn_solve:
                    self.set_game_state(GAME_FINISHED)
                    self.set_message(_("Puzzle Solved!"))
                else:
                    self.set_game_state(GAME_QUIT)
                    self.set_message(_("Gave Up"))
        self._set_control_area()

#    @utils.trace
#    def do_select_category(self, owner, *args, **kwargs):
#        if isinstance(owner, CategorySelector):
#            self.thumb.set_image_dir(args[0])
#            #self.game_box.pop()
#            if not self.thumb.category.has_images():
#                self.do_add_image(None)
#        else:
#            if self.game_wrapper.get_parent():
#                s = CategorySelector("images", _("Choose a Subject"), self.thumb.get_image_dir())
#                s.connect("selected", self.do_select_category)
#                s.show()
#                self.game_box.push(s)
#                s.grab_focus()
#            else:
#                self.game_box.pop()

    def do_select_category (self, o, *args):
        if isinstance(o, CategorySelector):
            self.thumb.set_image_dir(args[0])
            #if not self.thumb.category.has_images():
            #    self.do_add_image(None)
        else:
            if self.game_wrapper.get_parent():
                logging.debug("Current cat dir=%s" % self.thumb.get_image_dir())
                s = CategorySelector(_("Choose a Subject"),
                                     self.thumb.get_image_dir(),
                                     path="images")
                                     #extra=('images/Sequencing Puzzles',))
                s.connect("selected", self.do_select_category)
                s.show()
                self.game_box.push(s)
                s.grab_focus()
            else:
                self.game_box.pop()

    @utils.trace
    def do_add_image (self, widget, *args):
        """ Use to trigger and process the My Own Image selector.
        Also used for showing the buddies panel on contest mode"""
        if self._contest_mode and self.get_game_state() >= GAME_STARTED:
            # Buddy Panel
            if not self.buddy_panel.get_parent():
                self.timer.stop()
                self.game_box.push(self.buddy_panel)
            else:
                self.game_box.pop()
        elif self._contest_mode and not self.is_initiator():
            # do nothing
            pass
        else:
            self.thumb.add_image()
            self.do_shuffle()
            
        #if response is None:
        #    else:
        #        # My Own Image selector
        #        imgfilter = gtk.FileFilter()
        #        imgfilter.set_name(_("Image Files"))
        #        imgfilter.add_mime_type('image/*')
        #        fd = gtk.FileChooserDialog(title=_("Select Image File"), parent=self._parent,
        #                                   action=gtk.FILE_CHOOSER_ACTION_OPEN,
        #                                   buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        #
        #        fd.set_current_folder(os.path.expanduser("~/"))
        #        fd.set_modal(True)
        #        fd.add_filter(imgfilter)
        #        fd.connect("response", self.do_add_image)
        #        fd.resize(800,600)
        #        fd.show()
        #else:
        #    if response == gtk.RESPONSE_ACCEPT:
        #        if self.thumb.load_image(widget.get_filename()):
        #            self.do_shuffle()
        #        else:
        #            err = gtk.MessageDialog(self._parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
        #                                    _("Not a valid image file"))
        #            err.run()
        #            err.destroy()
        #            return
        #    widget.destroy()

    def do_lesson_plan (self, btn):
        if self._on_lesson_plan:
            return
        try:
            self._on_lesson_plan = True
            if self._contest_mode and self.get_game_state() < GAME_STARTED:
                return
            page = self.notebook.get_current_page()
            if page == 0:
                self.timer.stop()
                self.timer.props.sensitive = False
                if self.notebook.get_n_pages() == 1:
                    lessons = NotebookReaderWidget('lessons',
                            self.selected_lang_details)
                    lessons.connect('parent-set', self.do_lesson_plan_reparent)
                    lessons.show_all()
                    self.notebook.append_page(lessons)
            else:
                self.timer.props.sensitive = True
            self.notebook.set_current_page(int(not page))
        finally:
            self._on_lesson_plan = False

    def do_lesson_plan_reparent (self, widget, oldparent):
        if widget.parent is None:
            self.set_button_translation(self.btn_lesson, "Lesson Plans")
            self.btn_lesson.get_child().set_label(_("Lesson Plans"))
        else:
            self.set_button_translation(self.btn_lesson, "Close Lesson")
            self.btn_lesson.get_child().set_label(_("Close Lesson"))

    def process_key (self, w, e):
        """ The callback for key processing. The button shortcuts are all defined here. """
        k = gtk.gdk.keyval_name(e.keyval)
        if not isinstance(self._parent.get_focus(), gtk.Editable):
            if k == '1':
                self.btn_9.clicked()
                return True
            if k == '2':
                self.btn_12.clicked()
                return True
            if k == '3':
                self.btn_16.clicked()
                return True
            if k == 'period':
                self.thumb.next()
                return True
            if k == 'comma':
                self.thumb.previous()
                return True
            if k == 'Return':
                self.set_nr_pieces(None)
                return True
            if k == 'slash':
                self.do_select_category(None)
                return True
            if k == 'question':
                self.btn_add.clicked()
                return True
            if k == 'equal':
                self.btn_solve.clicked()
                return True
            if k in ('Escape', 'q'):
                gtk.main_quit()
                return True
        return False

    @utils.trace
    def _freeze (self, journal=True):
        """ returns a json writable object representation capable of being used to restore our current status """
        return (self.thumb._freeze(), self.game._freeze(journal=journal), self.game.get_nr_pieces(), self.timer._freeze())

    def _thaw (self, obj):
        """ retrieves a frozen status from a python object, as per _freeze """
        logging.debug('_thaw: %s' % obj)

        if not obj[1]['image']:
            return

        if not obj[1].has_key('image'):
            self.game.load_image(self.thumb.get_image())
        self.set_nr_pieces(None, obj[2])
        logging.debug(obj[1].keys())
        wimg = obj[1].has_key('image')
        self.game._thaw(obj[1])
        if wimg:
            logging.debug("Forcing thumb image from the one in game")
            self.thumb.load_pb(self.game.image)

        self.timer.reset()
        self.timer._thaw(obj[3])
        self.game_box.pop()
        
    @utils.trace
    def _send_status_update (self):
        """ Send a status update signal """
        if self._parent._shared_activity:
            if self.get_game_state() == GAME_STARTED:
                if self.thumb.has_image():
                    self.set_message(_("Game Started!"))
            self._parent.game_tube.StatusUpdate(self._state[1], self.timer.is_running(), self.timer.ellapsed())
    def __init__(self, parent):
        super(SliderPuzzleUI, self).__init__(3, 3, False)
        self._parent = parent

        # We want the translatables to be detected but not yet translated
        global _

        def _(x):
            return x

        self.labels_to_translate = []

        self._state = GAME_IDLE

        inner_table = Gtk.Table(2, 2, False)
        self.add(inner_table)
        self.from_journal = False
        self.game = SliderPuzzleWidget(9, GAME_SIZE, GAME_SIZE)
        self.game.connect("solved", self.do_solve)
        self.game.connect("moved", self.slider_move_cb)
        self._parent.connect("key_press_event", self.game.process_key)
        self._parent.connect("key_press_event", self.process_key)
        self.game.show()
        desktop = BorderFrame(border_color=COLOR_FRAME_CONTROLS)
        desktop.show()
        desktop.add(self.game)
        self.game_wrapper = Gtk.VBox()
        self.game_wrapper.show()
        inner = Gtk.HBox()
        inner.show()

        inner.pack_start(desktop, True, False, 0)
        self.game_wrapper.pack_start(inner, True, False, 0)

        # panel is a holder for everything on the left side down to (not inclusive) the language dropdown
        panel = Gtk.VBox()

        # Logo image
        img_logo = Gtk.Image()
        img_logo.set_from_file("icons/logo.png")
        img_logo.show()
        panel.pack_start(img_logo, False, False, 0)

        # Control panel has the image controls
        control_panel = BorderFrame(border=BORDER_ALL_BUT_BOTTOM,
                                    border_color=COLOR_FRAME_CONTROLS,
                                    bg_color=COLOR_BG_CONTROLS)
        control_panel_box = Gtk.VBox()
        control_panel.add(control_panel_box)

        spacer = Gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, False, False, 0)

        self.thumb = ImageSelectorWidget(self._parent,
                                         frame_color=COLOR_FRAME_THUMB,
                                         prepare_btn_cb=prepare_btn,
                                         image_dir='images')
        control_panel_box.pack_start(self.thumb, False, True, 0)

        spacer = Gtk.Label()
        spacer.set_size_request(-1, 5)
        control_panel_box.pack_start(spacer, False, False, 0)

        # Control panel end
        panel.pack_start(control_panel, True, True, 0)

        inner_table.attach(panel, 0, 1, 0, 1, 0)

        self.game_box = BorderFrame(border_color=COLOR_FRAME_GAME)
        self.game_box.add(self.game_wrapper)

        lang_combo = prepare_btn(
            LanguageComboBox('org.worldwideworkshop.olpc.SliderPuzzle'))

        del _
        lang_combo.install()
        lang_box = BorderFrame(bg_color=COLOR_BG_CONTROLS,
                               border_color=COLOR_FRAME_CONTROLS)
        hbox = Gtk.HBox(False)
        vbox = Gtk.VBox(False)
        vbox.pack_start(lang_combo, True, True, 8)
        hbox.pack_start(vbox, True, True, 8)
        lang_box.add(hbox)

        timer_box = BorderFrame(border=BORDER_ALL_BUT_LEFT,
                                bg_color=COLOR_BG_CONTROLS,
                                border_color=COLOR_FRAME_CONTROLS)
        timer_hbox = Gtk.HBox(False)
        self.timer = TimerWidget(bg_color=COLOR_BG_BUTTONS[0][1],
                                 fg_color=COLOR_FG_BUTTONS[0][1],
                                 lbl_color=COLOR_BG_BUTTONS[1][1])
        self.timer.set_sensitive(False)
        self.timer.set_border_width(3)

        self.labels_to_translate.append((self.timer, _("Time: ")))
        timer_hbox.pack_start(self.timer, False, True, 8)
        self.timer.connect('timer_toggle', self.timer_toggle_cb)

        self.msg_label = Gtk.Label()
        self.msg_label.show()
        timer_hbox.pack_start(self.msg_label, True, True, 0)

        self.notebook = Gtk.Notebook()
        self.notebook.show()
        self.notebook.props.show_border = False
        self.notebook.props.show_tabs = False
        self.notebook.append_page(self.game_box, None)
        inner_table.attach(self.notebook, 1, 2, 0, 1, Gtk.AttachOptions.FILL,
                           Gtk.AttachOptions.FILL)
        vbox = Gtk.VBox(False)
        vbox.pack_start(timer_hbox, True, True, 8)
        timer_box.add(vbox)
        inner_table.attach(timer_box, 1, 2, 1, 2,
                           Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND,
                           Gtk.AttachOptions.FILL)

        self.buddy_panel = BuddyPanel()
        self.buddy_panel.show()

        # Contest mode flags
        self.set_contest_mode(False)
        self.initial_path = os.path.join(get_bundle_path(), 'images',
                                         'image_aisc_h250_w313_lg.gif')
        self.set_nr_pieces(nr_pieces=9, path=self.initial_path)
        self.pre_path = self.initial_path

        self._on_lesson_plan = False