def start(self): """ Start a new game. """ self.saveConfiguration() # reset the start button image updateImage(self.startImage, 'Start', TOOL_SIZE) # get the grid information from the configuration box. activeConfiguration = self.configurationBox.get_active_iter() cols, rows, nMines = tuple(self.configurations[activeConfiguration])[2:] mines = [True] * nMines mines.extend([False] * (cols * rows - nMines)) random.shuffle(mines) # reset the status bar self.exposedCount.set_text('0') self.exposedLabel.set_text('/ ' + str(cols * rows - nMines)) self.hintCount.set_text('0') self.flagCount.set_text('0') self.flagLabel.set_text('/ ' + str(nMines)) # destroy any pre-existing game if self.gameGrid != None: self.gameGrid.destroy() # 'force' re-size at the start of the game self.previousAllocation = None # make the new game self.gameGrid = GridWindow(parent=self, cols=cols, rows=rows, mines=mines) self.gridContainer.add_with_viewport(self.gameGrid) # configure the toolbar widgets sensitivity self.hintButton.set_sensitive(True) # enable hints during a game self.pbcButton.set_sensitive(False) # can't change pbc during a game self.configurationBox.set_button_sensitivity(Gtk.SensitivityType.OFF) # start the game self.gameGrid.start() self.gameGrid.giveHint() self.window.show_all()
class UXBgtk: """ The main game UI. """ def __init__(self): """ Initialize the UI. """ self.initializeGUI() self.restoreConfiguration() self.window.show_all() def initializeGUI(self): """ Load the main GUI elements from the .glade file. """ self.builder = Gtk.Builder() self.builder.add_from_file(UI_BUILD_FILE) self.builder.connect_signals(self) # these are the toolbar widgets... # game start self.startButton = self.builder.get_object('startButton') self.startImage = getImage('Start') updateImage(self.startImage, 'Start', TOOL_SIZE) self.startButton.add(self.startImage) # hint request self.hintButton = self.builder.get_object('hintButton') self.hintImage = getImage('Hint') updateImage(self.hintImage, 'Hint', TOOL_SIZE) self.hintButton.add(self.hintImage) self.hintButton.set_sensitive(False) # periodic boundary condition toggle self.pbcButton = self.builder.get_object('pbcButton') self.pbcImage = getImage('PBC_Off') updateImage(self.pbcImage, 'PBC_Off', TOOL_SIZE) self.pbcButton.add(self.pbcImage) self.pbcButton.set_sensitive(True) # the configurationBox and its model self.configurations = self.builder.get_object('configurations') self.configurationBox = self.builder.get_object('configurationBox') # an alternative quit button self.resetButton = self.builder.get_object('resetButton') self.resetImage = getImage('Reset') updateImage(self.resetImage, 'Reset', TOOL_SIZE) self.resetButton.add(self.resetImage) # these are the status bar widgets... # ...exposed count self.exposedIcon = self.setupStatusBarIcon('exposedIcon', 'Exposed') self.exposedCount = self.builder.get_object('exposedCount') self.exposedLabel = self.builder.get_object('exposedLabel') # ...hint count self.hintIcon = self.setupStatusBarIcon('hintIcon', 'Query') self.hintCount = self.builder.get_object('hintCount') # ...flag count self.flagIcon = self.setupStatusBarIcon('flagIcon', 'Flag') self.flagCount = self.builder.get_object('flagCount') self.flagLabel = self.builder.get_object('flagLabel') # the game grid (blank for now) self.gridContainer = self.builder.get_object('gridContainer') self.gameGrid = None self.previousAllocation = self.gridContainer.get_allocation() # get references to the toolbar and status bar for size data. self.toolbar = self.builder.get_object('toolBox') self.statusbar = self.builder.get_object('statusBox') # get a reference to the main window itself and display the window self.window = self.builder.get_object('window') def setupStatusBarIcon(self, iconName, imageName): """ Add an icon image to a status bar button. """ icon = self.builder.get_object(iconName) image = getImage(imageName) updateImage(image, imageName, STATUS_SIZE) icon.add(image) return icon def restoreConfiguration(self): """ Get the UI and game parameters from the last time the game was played. """ self.configuration = SafeConfigParser() configList = self.configuration.read([CONFIG_FILE], encoding='utf-8') if configList: # restore the last saved window size if self.configuration[UI_SECTION][WINDOW_SIZE]: geometry = \ self.configuration[UI_SECTION][WINDOW_SIZE].split(',') x, y = (int(coord) for coord in geometry) self.window.resize(x, y) # restore the game parameters... # ...periodic boundary toggle if self.configuration[GAME_PARAMS_SECTION][PBC]: self.pbcButton.set_active( ast.literal_eval( self.configuration[GAME_PARAMS_SECTION][PBC])) # ...grid size and number of mines if self.configuration[GAME_PARAMS_SECTION][CONFIGURATION]: self.configurationBox.set_active( int(self.configuration[GAME_PARAMS_SECTION][CONFIGURATION])) else: # first time, create a vanilla configuration self.configuration.add_section(UI_SECTION) self.configuration.add_section(GAME_PARAMS_SECTION) self.saveConfiguration() def saveConfiguration(self): """ Save any changes to the configuration options. """ self.configuration.set(UI_SECTION, WINDOW_SIZE, ', '.join(str(coord) for coord in self.window.get_size())) self.configuration.set(GAME_PARAMS_SECTION, PBC, str(self.pbcButton.get_active())) self.configuration.set(GAME_PARAMS_SECTION, CONFIGURATION, str(self.configurationBox.get_active())) # FIXME: Issue13498 workaround behaviour of os.makedirs in Python3.2 try: os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True) except OSError as e: if e.errno != errno.EEXIST: raise with open(CONFIG_FILE, 'w', encoding='utf-8') as configurationFile: self.configuration.write(configurationFile) def start(self): """ Start a new game. """ self.saveConfiguration() # reset the start button image updateImage(self.startImage, 'Start', TOOL_SIZE) # get the grid information from the configuration box. activeConfiguration = self.configurationBox.get_active_iter() cols, rows, nMines = tuple(self.configurations[activeConfiguration])[2:] mines = [True] * nMines mines.extend([False] * (cols * rows - nMines)) random.shuffle(mines) # reset the status bar self.exposedCount.set_text('0') self.exposedLabel.set_text('/ ' + str(cols * rows - nMines)) self.hintCount.set_text('0') self.flagCount.set_text('0') self.flagLabel.set_text('/ ' + str(nMines)) # destroy any pre-existing game if self.gameGrid != None: self.gameGrid.destroy() # 'force' re-size at the start of the game self.previousAllocation = None # make the new game self.gameGrid = GridWindow(parent=self, cols=cols, rows=rows, mines=mines) self.gridContainer.add_with_viewport(self.gameGrid) # configure the toolbar widgets sensitivity self.hintButton.set_sensitive(True) # enable hints during a game self.pbcButton.set_sensitive(False) # can't change pbc during a game self.configurationBox.set_button_sensitivity(Gtk.SensitivityType.OFF) # start the game self.gameGrid.start() self.gameGrid.giveHint() self.window.show_all() def on_window_destroy(self, widget): """ Handler for closing window. A quick clean kill of the entire app. """ Gtk.main_quit() def on_startButton_clicked(self, widget): """ Handler for the start button. """ self.start() def on_hintButton_clicked(self, widget): """ Handler for the hint button. """ self.gameGrid.giveHint() def on_pbcButton_toggled(self, widget): """ Handler for the periodic boundary condition button. """ if self.pbcButton.get_active(): updateImage(self.pbcImage, 'PBC_On', TOOL_SIZE) else: updateImage(self.pbcImage, 'PBC_Off', TOOL_SIZE) def explodeGame(self): """ Make an explosion effect on the screen as the grid is destroyed. """ # obtain the size of the playing area size = (self.gridContainer.get_allocated_width(), self.gridContainer.get_allocated_height()) # make the explosion flashImage flashImage = getImage('Explosion') updateImage(flashImage, 'Explosion', size) self.gridContainer.add_with_viewport(flashImage) # flash the explosion 5 times for i in range(5): # display the explosion updateImage(self.startImage, 'Click', TOOL_SIZE) flashImage.show() pause(100) # wait 200ms without blocking the Gtk event loop # hide the explosion updateImage(self.startImage, 'Lose', TOOL_SIZE) flashImage.hide() pause(100) # wait 200ms without blocking the Gtk event loop # ... then destroy the explosion image flashImage.destroy() def on_resetButton_clicked(self, widget): """ Handler for the reset button. A theatrical way to kill the current game. """ # get rid of the old game if self.gameGrid != None: self.gameGrid.destroy() self.explodeGame() # configure the toolbar widgets sensitivity self.hintButton.set_sensitive(False) self.pbcButton.set_sensitive(True) self.configurationBox.set_button_sensitivity(Gtk.SensitivityType.ON) def on_configurationBox_changed(self, widget): """ Reset stuff that needs to be reset for creating the game grid. """ pass # no further action needed atm def on_window_check_resize(self, widget): """ Handler for resizing the game grid images. """ # do nothing if the game grid is not ready if not self.gameGrid: return # check to see if this is a real resize allocation = self.gridContainer.get_allocation() if (self.previousAllocation != None and allocation.width == self.previousAllocation.width and allocation.height == self.previousAllocation.height): return else: self.previousAllocation = allocation self.gameGrid.resize(allocation) self.saveConfiguration()