Logo Search packages:      
Sourcecode: gameclock version File versions  Download package

def gameclock::GameclockGtkUI::main (   self  ) 

simple stub to fire up the main gtk event loop

Definition at line 351 of file gameclock.py.

00351                   :
        """simple stub to fire up the main gtk event loop"""
        gtk.main()

    def quit(self, widget, a = None, b = None, c = None):
        gtk.main_quit()

    def add_clock_evbox(self, evbox):
        self.clock_evbox_cnt += 1
        cols = 2 # all the time
        rows = (self.clock_evbox_cnt - 1)/ cols + 1
        self.clock_table.resize(rows, cols)
        l = ( self.clock_evbox_cnt % cols + 1 ) % cols
        r = l + 1
        t = rows - 1
        b = rows
        self.clock_table.attach(evbox, l, r, t, b)
    
    def __init__(self, fullscreen = False):
        """create the main user interface with GTK"""
        self.loop_timeout = sec_loop_timeout
        self.fullscreen = fullscreen

        # create a new window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

        # handle window close events
        self.window.connect("delete_event", lambda a, b: False)    
        self.window.connect("destroy", self.quit)
    
        # Sets the border width of the window.
        self.window.set_border_width(10)

        # the key shortcuts, space is bound to the button, below
        accel_group = gtk.AccelGroup()
        accel_group.connect_group(ord('q'), gtk.gdk.CONTROL_MASK, 0, self.quit)
        accel_group.connect_group(ord('p'), 0, 0, self.handle_pause)
        accel_group.connect_group(ord('r'), gtk.gdk.CONTROL_MASK, 0, self.handle_reset)
        accel_group.connect_group(ord('f'), 0, 0, self.handle_fullscreen)
        self.window.add_accel_group(accel_group)

        self.window.connect('key_press_event', self.handle_key_press)

        # main window consists of a vbox containing two hbox
        vlayout = gtk.VBox(False, 0)
        self.window.add(vlayout)

        # turn counter
        self.turns = gtk.Label()
        vlayout.pack_start(self.turns, False, False, 0)

        # the clocks
        self.clock_table = gtk.Table(1, 2, True)
        self.clock_table.show()
        vlayout.pack_start(self.clock_table, True, True, 0)

        try:
            players = int(self.players_val.get_value())
        except:
            players = default_players

        # the clock engines
        p = self.cur_clock = self.first_clock = GameclockGtkUI.ClockUI(self)
        for i in range(players-1):
            p.next = GameclockGtkUI.ClockUI(self)
            p = p.next

        self.setup_game()

        # all controls is regular controls + start/stop
        all_controls = gtk.VBox(False, 0)
        all_controls.show()
        self.controls = gtk.HBox(False, 0)
        self.controls.show()
        vlayout.pack_start(all_controls, False, False, 0)

        # the widgets to change the starting time
        (hours, minutes, seconds) = map(int, time.strftime("%H:%M:%S", time.gmtime(default_time/1000)).split(":"))
        # XXX: spinbuttons limited to 24h-1s because of limitations of strftime
        self.hours_val = gtk.Adjustment(hours, 0, 23, 1, 10, 0)
        self.minutes_val = gtk.Adjustment(minutes, 0, 59, 1, 10, 0)
        self.seconds_val = gtk.Adjustment(seconds, 0, 59, 1, 10, 0)
        self.hours_val.connect("value_changed", self.handle_clock_change)
        self.minutes_val.connect("value_changed", self.handle_clock_change)
        self.seconds_val.connect("value_changed", self.handle_clock_change)
        hours_val_btn = gtk.SpinButton(self.hours_val, 0.0, 0)
        minutes_val_btn = gtk.SpinButton(self.minutes_val, 0.0, 0)
        seconds_val_btn = gtk.SpinButton(self.seconds_val, 0.0, 0)
        hours_val_btn.show()
        minutes_val_btn.show()
        seconds_val_btn.show()

        clock_controls = gtk.HBox(False, 0)
        clock_controls.pack_start(hours_val_btn, False, False, 10)
        clock_controls.pack_start(minutes_val_btn, False, False, 10)
        clock_controls.pack_start(seconds_val_btn, False, False, 10)
        clock_controls.show()

        clock_controls_box = gtk.VBox(False, 0)
        label = gtk.Label("Time limit")
        label.show()

        clock_controls_box.pack_start(label, False, False, 10)
        clock_controls_box.pack_start(clock_controls, False, False, 10)
        clock_controls_box.show()

        self.controls.pack_start(clock_controls_box)

        # the main toggle button, used by various signal handlers
        self.startstop = gtk.Button("Start (space)")
        self.startstop.add_accelerator("activate", accel_group, ord(' '), 0, 0)
        # we keep the signal id to turn it off on first click
        self.start_signal = self.startstop.connect("clicked", self.handle_start_game, None)
        self.startstop.show()
        all_controls.pack_start(self.startstop, False, False, 0)
        # now we can pack the other controls
        all_controls.pack_start(self.controls, True, True, 0)

        # The game mode radio buttons
        type_layout = gtk.VBox(False, 10)
        type_layout.set_border_width(10)
        type_layout.show()

        label = gtk.Label("Game type")
        label.show()
        type_layout.pack_start(label, True, True, 0)

        button = None
        for type in [ "Classic", "Blitz", "Hourglass" ]:
            button = gtk.RadioButton(button, type)
            if default_game == "%sGame" % type:
                button.set_active(True)
            button.connect("toggled", self.handle_type, type)
            type_layout.pack_start(button, True, True, 0)
            button.show()

        # fisher is special: we need to pack more stuff on its line
        fisher_layout = gtk.HBox(False, 10)
        type_layout.pack_start(fisher_layout, True, True, 0)

        button = gtk.RadioButton(button, "Fisher")
        button.connect("toggled", self.handle_type, "Fisher")
        fisher_layout.pack_start(button, True, True, 0)
        button.show()

        self.fisher_label = gtk.Label('Delay: ')
        fisher_layout.pack_start(self.fisher_label, True, False, 0)

        self.fisher_val = gtk.Adjustment(default_fisher, 1, 10000, 1, 10, 0)
        self.fisher_val_btn = gtk.SpinButton(self.fisher_val, 0.0, 0)
        self.fisher_val.connect("value_changed", self.handle_fisher_change)
        fisher_layout.pack_start(self.fisher_val_btn, False, False, 0)
        fisher_layout.show()

        self.controls.pack_start(type_layout)

        misc_box = gtk.VBox(False, 0)
        misc_box.show()

        ms_ctrl = gtk.CheckButton("Display _miliseconds")
        ms_ctrl.connect('toggled', self.handle_miliseconds)
        ms_ctrl.show()
        misc_box.pack_start(ms_ctrl)

        label = gtk.Label('Number of players: ')
        label.show()
        misc_box.pack_start(label, False, False, 10)

        self.players_val = gtk.Adjustment(default_players, 1, 10000, 1, 10, 0)
        players_val_btn = gtk.SpinButton(self.players_val, 0.0, 0)
        self.players_val.connect("value_changed", self.handle_players_change)
        players_val_btn.show()
        misc_box.pack_start(players_val_btn, False, False, 0)

        self.controls.pack_start(misc_box, False, False, 0)

        # the main toggle button, used by various signal handlers
        starter = gtk.Button("Toggle starting player")
        starter.connect("clicked", self.handle_switch_clock)
        starter.show()
        self.controls.pack_start(starter, True, True, 0)

        # little help
        label = gtk.Label("<b>shift</b> and <b>space</b> keys end turns; <b>p</b> pauses; <b>control-q</b> quits; <b>control-r</b> resets the game; <b>f</b> enables fullscreen mode")
        label.set_use_markup(True)
        label.show()
        vlayout.pack_start(label, False, False, 0)
        vlayout.show()
    
        if self.fullscreen:
            self.window.fullscreen()
        self.window.show()

    def maybe_print(self, text):
        if verbose:
            t = ""
            state = ""
            if verbose > 1:
                t = "[%f] " % time.time()
                if verbose > 2:
                    state = "\n  game engine state: %s" % self.game
            print t + text + state

    def refresh(self):
        if self.game.miliseconds:
            font = "sans 48"
        else:
            font = "sans 72"

        p = self.first_clock
        q = self.game.first_clock
        while p:
            p.label.modify_font(pango.FontDescription(font))
            p.label.set_label(q.text)
            p = p.next
            q = q.next
        
        self.turns.set_label("Turn %d" % self.game.get_turns())
        self.hilight()
        
    def refresh_current(self):
        """refresh the active clock
        
        this handler is ran periodically through a timeout signal to make sure that the current clock is updated
        """

        if isinstance(self.game, HourglassGame):
            p = self.game.first_clock
            while p:
                p.update()
                p = p.next
            self.refresh()
            return True

        self.cur_clock.label.set_label(self.game.cur_clock.update())
        active = self.cur_clock.label.get_parent()
        if self.game.cur_clock.dead:
            active.modify_bg(gtk.STATE_NORMAL, active.get_colormap().alloc_color("red"))
        return True

    def hilight(self):
        """hilight the proper clocks with proper colors
        
        this is 'transparent' for the inactive clock and colored for the
        active clock. the color depends on wether the clock is 'dead' or
        not
        """
        p = self.first_clock
        q = self.game.first_clock
        while p:
            evbox = p.label.get_parent()
            if p == self.cur_clock:
                if q.dead:
                    color = "red"
                else:
                    color = "green"
                color = evbox.get_colormap().alloc_color(color)
            else:
                color = None
            evbox.modify_bg(gtk.STATE_NORMAL, color)
            p = p.next
            q = q.next

    def setup_game(self):
        """initial setup of the clocks, game and labels"""

        try:
            # this may be a reset, init from old values
            miliseconds = self.game.miliseconds
            name = self.game.__class__.__name__
        except AttributeError:
            miliseconds = False
            # it is here we define the default game
            name = default_game

        if name == "FisherGame":
            self.game = FisherGame(self.count_players(), miliseconds, self.get_fisher())
        else:
            self.game = eval("%s(%d, %d)" % (name, self.count_players(), miliseconds))
        self.maybe_print("game setup with %d players" % self.count_players())
        self.refresh()

    def count_players(self):
        """return the number of players configured"""
        try:
            return int(self.players_val.get_value())
        except:
            return default_players

    def get_fisher(self):
        """return the current fisher delay selected in the UI or the default if there is no UI yet"""
        try:
            return int(self.fisher_val.get_value() * 1000)
        except:
            return default_fisher

    def handle_key_press(self, widgets, event):
        keyname = gtk.gdk.keyval_name(event.keyval)
        if keyname == 'Shift_L':
            if self.game.cur_clock == self.game.first_clock:
                self.handle_end_turn()
        elif keyname == 'Shift_R':
            if self.game.cur_clock != self.game.first_clock:
                self.handle_end_turn()
        elif keyname == 'Escape':
            self.handle_reset()
        self.maybe_print("key %s (%d) was pressed" % (keyname, event.keyval))

    def handle_fullscreen(self, widget, event, a, b):
        if self.fullscreen:
            self.window.unfullscreen()
        else:
            self.window.fullscreen()
        self.fullscreen = not self.fullscreen

    # XXX: those could be simplified by tagging the radio with the
    # mode, which would be passed along
    def handle_type(self, widget, data=None):
        if widget.get_active():
            if data == "Fisher":
                # special case: different arguments
                self.game = FisherGame(self.count_players(), self.game.miliseconds, self.get_fisher())
                self.fisher_val_btn.show()
                self.fisher_label.show()
            else:
                self.game = eval("%sGame(%d, %d)" % (data, self.count_players(), self.game.miliseconds))
                self.fisher_val_btn.hide()
                self.fisher_label.hide()
            self.maybe_print("using %s mode" % data)
        return

    def handle_fisher_change(self, widget, data=None):
        self.game.fisher = int(widget.get_value() * 1000)
            
    def handle_players_change(self, widget, data=None):
        p = self.first_clock
        q = self.game.first_clock
        count = 1
        players = int(widget.get_value())
        # reach the last node
        while count < players and p.next:
            self.maybe_print("count: %d, players: %d" % (count, players))
            p = p.next
            q = q.next
            count += 1
        while count == players and p.next:
            self.maybe_print("too many clocks, killing a clock")
            tmp = p.next
            p.next = p.next.next
            del tmp
            tmp = q.next
            q.next = q.next.next
            del tmp
        if p.next:
            p = p.next
            q = q.next
            count += 1
        self.maybe_print("count: %d, players: %d" % (count, players))
        while count < players:
            self.maybe_print("adding a new clock")
            p.next = GameclockGtkUI.ClockUI(self)
            q.next = Clock(self.game)
            # XXX: this would be cleaner if a copy was implemented in the Clock object
            q.next.time = q.time
            q.next.update()
            p = p.next
            q = q.next
            count += 1
        cols = 2
        rows = (count - 1)/ cols + 1
        self.clock_table.resize(rows, cols)
        self.refresh()
        self.maybe_print("now at %d clocks, table size is %dX%d" % (count, rows, cols))

    def handle_end_turn(self, widget = None, data=None):
        """handle end turn events
        
        this passes the message to the gaming engine as quickly as
        possible then goes around updating the UI
        """
        if not self.first_clock.next:
            self.game.pause()
        else:
            self.game.end_turn()
        # update the current clock pointer
        self.cur_clock = self.cur_clock.next
        if not self.cur_clock:
            self.cur_clock = self.first_clock

        # some reason it doesn't work to just update the old clock label, we need to update both
        self.refresh()
        self.hilight()
        self.maybe_print("ended turn")
        
    def handle_switch_clock(self, widget):
        """change the current clock
        
        simply switch the clock in the game engine and rehilight
        """
        self.game.switch_clock()
        self.cur_clock = self.cur_clock.next
        if not self.cur_clock:
            self.cur_clock = self.first_clock
        self.hilight()
        self.maybe_print("changing starting clock")

    def handle_start_game(self, widget, data=None):
        """start the game
        
        this is the handler for the main button when the game has not
        been started yet
        
        it will change the button to an "end turn" button and connect
        the 'end_turn' function to it
        
        it will also start the game engine itself
        """
        self.timeout_source = gobject.timeout_add(self.loop_timeout, self.refresh_current)
        self.startstop.handler_block(self.start_signal)
        self.end_turn_signal = self.startstop.connect("clicked", self.handle_end_turn, None)

        if self.game.count_players() == 1:
            self.startstop.set_label('Pause timer (space)')
        else:
            self.startstop.set_label('End turn (space)')

        self.game.start()
        self.turns.set_label("Turn %d" % self.game.get_turns())
        self.turns.show()
        self.controls.hide()
        self.maybe_print("starting game, refresh rate %dms" % self.loop_timeout)

    def handle_pause(self, widget, data=None, a=None, b=None):
        """pause handler
        
        just a stub for the game engine for now
        """
        self.maybe_print("pausing game")
        self.game.pause()

    def handle_reset(self, widget=None, data=None, a=None, b=None):
        """game reset handler

        this is a bit more complicated:
        * destroy and recreate the game engine
        * remove the auto-refresh and reconnect the right signals
        * fix the main label
        * show the controls and fix the hilight
        """
        self.maybe_print("reseting game")
        self.setup_game()
        self.cur_clock = self.first_clock
        try:
            gobject.source_remove(self.timeout_source) # stop the refresh
            self.startstop.handler_block(self.end_turn_signal)
        except AttributeError:
            pass
        else:
            self.start_signal = self.startstop.connect("clicked", self.handle_start_game, None)
        self.startstop.set_label('Start (space)')
        self.handle_clock_change() # refresh the labels and time counters based on the chosen times
        self.controls.show()
        self.hilight()

    def handle_clock_change(self, widget = None):
        global default_time
        hours = self.hours_val.get_value()
        minutes = self.minutes_val.get_value()
        seconds = self.seconds_val.get_value()
        default_time = ( ( hours * 60 * 60 ) + ( minutes * 60 ) + seconds ) * 1000

        # XXX: note that we edit all clocks at the same time
        p = self.game.first_clock
        while p:
            p.time = default_time
            p.update()
            p = p.next
        self.refresh()

    def handle_miliseconds(self, widget):
        if widget.get_active():
            self.loop_timeout = ms_loop_timeout
        else:
            self.loop_timeout = sec_loop_timeout

        self.game.miliseconds = widget.get_active()
        p = self.game.first_clock
        while p:
            p.update()
            p = p.next
        self.refresh()
        self.maybe_print("activating miliseconds display")

def usage():


Generated by  Doxygen 1.6.0   Back to index