def __getPresentation(self, tabId): """Compose the HTML presentation for a tab identifier. @return HTML content as a string. """ # Kludge for the game-options icon. There should be a way to # map the icon more flexibly so this hardcoding wouldn't be # needed. if tabId == "game-options": game = "game-jdoom" if pr.getActive(): for c in pr.getActive().getComponents(): if c[:5] == "game-": game = c break imageName = language.translate(game + "-icon") else: imageName = language.translate(tabId + "-icon") return ( '<table width="100%" border=0 cellspacing=3 cellpadding=1>' + "<tr><td width=35><img width=32 height=32 " + 'src="%s"></td><td align="left" valign="center">%s</td>' % (paths.findBitmap(imageName), language.translate(tabId)) + "</tr></table>" )
def getBitmapPath(self, identifier, scaledSize=None): """Locates a bitmap and scales it, if necessary. @param identifier Bitmap identifier. @param scaledSize Tuple (width, height). If specified, determines the size of the image. If this does not match the size of the existing image on disk, a new image file will be created. @return Path of the image file. """ if scaledSize is None: return paths.findBitmap(identifier) # A scaled size has been specified. # Let's generate the scaled name of the bitmap. ident = 'scaled%ix%i-' % scaledSize + identifier # Try to locate an existing copy of the image. imagePath = paths.findBitmap(ident) if imagePath != '': return imagePath # We have to generate it. First try loading the original image. originalPath = paths.findBitmap(identifier) if originalPath == '': # No such image. return '' # Scale and save. PNG should work well with all source images. image = wx.Image(originalPath) originalSize = (image.GetWidth(), image.GetHeight()) if originalSize[0] == scaledSize[0] and originalSize[1] == scaledSize[1]: # No need to scale. return originalPath if scaledSize[0] < originalSize[0] or scaledSize[1] < originalSize[1]: # Upscale first to cause some extra blurring. image.Rescale(originalSize[0]*2, originalSize[1]*2, wx.IMAGE_QUALITY_HIGH) image.Rescale(scaledSize[0], scaledSize[1], wx.IMAGE_QUALITY_HIGH) imagePath = os.path.join(paths.getUserPath(paths.GRAPHICS), ident + '.png') image.SaveFile(imagePath, wx.BITMAP_TYPE_PNG) return imagePath
def getBitmapPath(self, identifier, scaledSize=None): """Locates a bitmap and scales it, if necessary. @param identifier Bitmap identifier. @param scaledSize Tuple (width, height). If specified, determines the size of the image. If this does not match the size of the existing image on disk, a new image file will be created. @return Path of the image file. """ if scaledSize is None: return paths.findBitmap(identifier) # A scaled size has been specified. # Let's generate the scaled name of the bitmap. ident = "scaled%ix%i-" % scaledSize + identifier # Try to locate an existing copy of the image. imagePath = paths.findBitmap(ident) if imagePath != "": return imagePath # We have to generate it. First try loading the original image. originalPath = paths.findBitmap(identifier) if originalPath == "": # No such image. return "" # Scale and save. PNG should work well with all source images. image = wx.Image(originalPath) originalSize = (image.GetWidth(), image.GetHeight()) if originalSize[0] == scaledSize[0] and originalSize[1] == scaledSize[1]: # No need to scale. return originalPath if scaledSize[0] < originalSize[0] or scaledSize[1] < originalSize[1]: # Upscale first to cause some extra blurring. image.Rescale(originalSize[0] * 2, originalSize[1] * 2, wx.IMAGE_QUALITY_HIGH) image.Rescale(scaledSize[0], scaledSize[1], wx.IMAGE_QUALITY_HIGH) imagePath = os.path.join(paths.getUserPath(paths.GRAPHICS), ident + ".png") image.SaveFile(imagePath, wx.BITMAP_TYPE_PNG) return imagePath
def setImage(self, imageName): """Change the image displayed in the widget. @param imageName Base name of the image file. It must be located in one of the graphics directories. """ bmp = wx.Image(paths.findBitmap(imageName)).ConvertToBitmap() self.bitmap.Freeze() self.bitmap.SetBitmap(bmp) self.panel.SetMinSize(bmp.GetSize()) self.bitmap.Thaw() self.panel.Refresh()
def get(self, identifier): """Finds the index number of the specified image. If the image hasn't yet been loaded, it is loaded now. @param identifier Identifier of the image. """ try: return self.bitmaps.index(identifier) except ValueError: # Load it now. Images are affected by the localisation. if language.isDefined(identifier): imageName = language.translate(identifier) else: imageName = identifier fileName = paths.findBitmap(imageName) if len(fileName) == 0: # Fallback icon. fileName = paths.findBitmap('deng') bmp = wx.Bitmap(fileName) self.imageList.Add(bmp) self.bitmaps.append(identifier) return len(self.bitmaps) - 1
def get(self, identifier): """Finds the index number of the specified image. If the image hasn't yet been loaded, it is loaded now. @param identifier Identifier of the image. """ try: return self.bitmaps.index(identifier) except ValueError: # Load it now. Images are affected by the localisation. if language.isDefined(identifier): imageName = language.translate(identifier) else: imageName = identifier fileName = paths.findBitmap(imageName) if len(fileName) == 0: # Fallback icon. fileName = paths.findBitmap("deng") bmp = wx.Bitmap(fileName) self.imageList.Add(bmp) self.bitmaps.append(identifier) return len(self.bitmaps) - 1
def __init__(self, parent, imageName): """Construct a new Image widget. @param imageName Base name of the image file. It must be located in one of the graphics directories. """ # Create a new panel so we can control the background color. self.panel = wx.Panel(parent, -1) self.panel.SetBackgroundColour(wx.WHITE) sb.widget.base.Widget.__init__(self, self.panel) # See if we can find the right image. bmp = wx.Image(paths.findBitmap(imageName)).ConvertToBitmap() self.bitmap = wx.StaticBitmap(self.panel, -1, bmp) self.panel.SetMinSize(bmp.GetSize())
def __getPresentation(self, tabId): """Compose the HTML presentation for a tab identifier. @return HTML content as a string. """ # Kludge for the game-options icon. There should be a way to # map the icon more flexibly so this hardcoding wouldn't be # needed. if tabId == 'game-options': game = 'game-jdoom' if pr.getActive(): for c in pr.getActive().getComponents(): if c[:5] == 'game-': game = c break imageName = language.translate(game + '-icon') else: imageName = language.translate(tabId + '-icon') return ('<table width="100%" border=0 cellspacing=3 cellpadding=1>' + '<tr><td width=35><img width=32 height=32 ' + 'src="%s"></td><td align="left" valign="center">%s</td>' % (paths.findBitmap(imageName), language.translate(tabId)) + '</tr></table>')
def runWizard(): """Run the wizard dialog.""" # Make sure the help panel isn't updated during the wizard. #events.send(events.Command('freeze')) suggested = { 'doom1': 'DOOM.WAD', 'doom1-share': 'DOOM1.WAD', 'doom1-ultimate': 'DOOM.WAD', 'doom2': 'DOOM2.WAD', 'doom2-tnt': 'TNT.WAD', 'doom2-plut': 'PLUTONIA.WAD', 'heretic-ext': 'HERETIC.WAD', 'heretic-share': 'HERETIC.WAD', 'heretic': 'HERETIC.WAD', 'hexen': 'HEXEN.WAD', 'hexen-demo': 'HEXEN.WAD', 'hexen-dk': 'HEXEN.WAD', 'hacx': 'HACX.WAD', 'chex': 'CHEX.WAD' } events.mute() # Make the Defaults profile active. pr.setActive(pr.getDefaults()) wiz = WizardDialog(language.translate('setup-wizard'), paths.findBitmap('wizard')) # Language selection page. langPage = WizardPage(wiz, 'wizard-language') area = langPage.getArea() area.createText('wizard-language-explanation', maxLineLength=65).resizeToBestSize() sar, languageCheckBox = area.createSetting(st.getSetting('language')) languageCheckBox.getFromProfile(pr.getActive()) # Game selection. gamePage = ProfileWizardPage(wiz, 'wizard-games', None) gamePage.follows(langPage) area = gamePage.getArea() area.createText('wizard-select-games', maxLineLength=65).resizeToBestSize() area.setBorderDirs(ui.BORDER_NOT_BOTTOM) games = area.createList('', style=sb.widget.list.List.STYLE_CHECKBOX) area.setBorderDirs(ui.BORDER_NOT_TOP) games.setMinSize(50, 180) gamePage.setGameList(games) def allGames(): # Check the entire list. for item in games.getItems(): games.checkItem(item, True) def clearGames(): # Uncheck the entire list. for item in games.getItems(): games.checkItem(item, False) controls = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=2) controls.setWeight(0) button = controls.createButton('wizard-games-all', wb.Button.STYLE_MINI) button.addReaction(allGames) button.resizeToBestSize() button = controls.createButton('wizard-games-clear', wb.Button.STYLE_MINI) button.addReaction(clearGames) button.resizeToBestSize() # The pages will be linked together. previousPage = gamePage deathKingsWad = None # We'll do this dynamically. checkedProfiles = ['doom1', 'doom2', 'heretic', 'hexen'] # Only display the system profiles in the wizard (not any user # profiles). profiles = pr.getProfiles(lambda p: p.isSystemProfile()) for p in profiles: if p is not pr.getDefaults(): games.addItem(p.getId(), p.getId() in checkedProfiles) # Create a page for the profile. page = ProfileWizardPage(wiz, p.getId(), games) # Link the pages together. page.follows(previousPage) previousPage = page area = page.getArea() area.createText('wizard-locate-iwad', maxLineLength=65).resizeToBestSize() # The suggestion. if suggested.has_key(p.getId()): sugArea = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=2) sugArea.setExpanding(False) sugArea.setWeight(1) sugArea.createText('wizard-suggested-iwad', ':', align=wt.Text.RIGHT) sugArea.setWeight(2) sug = sugArea.createText('') sug.setText(suggested[p.getId()]) sar, page.iwadText = area.createSetting(st.getSetting('iwad')) if p.getId() == 'hexen-dk': area.setBorder(12, ui.BORDER_ALL) area.createLine() area.setBorder(6, ui.BORDER_ALL) area.createText('deathkings-selection-title').setHeadingStyle() # Death Kings is an extension to Hexen. It uses the # same Hexen IWAD, but also an addon IWAD. area.createText('wizard-locate-iwad-deathkings', maxLineLength=65).resizeToBestSize() entry = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=4) entry.setExpanding(False) entry.setWeight(1) entry.setBorderDirs(ui.BORDER_NOT_LEFT) deathKingsWad = entry.createTextField('') entry.setWeight(0) entry.setBorderDirs(ui.BORDER_TOP_BOTTOM) browseButton = entry.createButton('browse-button', wb.Button.STYLE_MINI) def browseDeathKings(): # Open a file browser. selection = sb.util.dialog.chooseFile('deathkings-selection-title', '', True, [('file-type-wad', 'wad')]) if len(selection) > 0: deathKingsWad.setText(selection) browseButton.addReaction(browseDeathKings) # Addon paths. pathsPage = ProfileWizardPage(wiz, 'wizard-addon-paths', games) pathsPage.follows(previousPage) area = pathsPage.getArea() area.createText('wizard-addon-paths-explanation', maxLineLength=65).resizeToBestSize() area.setBorderDirs(ui.BORDER_NOT_BOTTOM) pathList = area.createList('addon-paths-list') pathList.setMinSize(100, 120) # Insert the current custom paths into the list. for p in paths.getAddonPaths(): pathList.addItem(p) def addAddonPath(): selection = sb.util.dialog.chooseFolder('addon-paths-add-prompt', '') if selection: pathList.addItem(selection) pathList.selectItem(selection) def removeAddonPath(): selection = pathList.getSelectedItem() if selection: pathList.removeItem(selection) area.setWeight(0) area.setBorderDirs(ui.BORDER_NOT_TOP) commands = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=2) commands.setWeight(0) # Button for adding new paths. button = commands.createButton('new-addon-path', wb.Button.STYLE_MINI) button.addReaction(addAddonPath) # Button for removing a path. button = commands.createButton('delete-addon-path', wb.Button.STYLE_MINI) button.addReaction(removeAddonPath) # Launch options. quitPage = WizardPage(wiz, 'wizard-launching') quitPage.follows(pathsPage) area = quitPage.getArea() area.createText('wizard-launching-explanation').resizeToBestSize() sar, quitCheckBox = area.createSetting(st.getSetting('quit-on-launch')) quitCheckBox.getFromProfile(pr.getActive()) # List of unusable profiles, due to a missing IWAD. unusableProfiles = [] # When the page changes in the wizard, change the active profile. def changeActiveProfile(page): prof = pr.get(page.getId()) if prof: pr.setActive(prof) else: pr.setActive(pr.getDefaults()) # Update page with values from the current profile. page.update() wiz.setPageReaction(changeActiveProfile) if wiz.run(langPage) == 'ok': events.unmute() # Show the profiles that now have an IWAD. for prof in profiles: if prof.getValue('iwad', False) != None: pr.show(prof.getId()) if prof.getId() in unusableProfiles: unusableProfiles.remove(prof.getId()) else: pr.hide(prof.getId()) if prof.getId() not in unusableProfiles and \ prof.getId() in games.getSelectedItems(): unusableProfiles.append(prof.getId()) # Install the Death Kings WAD? if deathKingsWad: try: ident = ao.install(deathKingsWad.getText()) # Attach the WAD as an addon. kingsProfile = pr.get('hexen-dk') kingsProfile.useAddon(ident) except: # TODO: Handle error. pass # Update custom addon paths. currentAddonPaths = paths.getAddonPaths() wasModified = False for path in pathList.getItems(): if path not in currentAddonPaths: paths.addAddonPath(path) wasModified = True for path in currentAddonPaths: if path not in pathList.getItems(): paths.removeAddonPath(path) wasModified = True if wasModified: # Load addons from new paths. ao.refresh() events.send(events.Notify('addon-paths-changed')) # The wizard will only be shown once automatically. pr.getDefaults().setValue(HAS_BEEN_RUN, 'yes', False) else: # Wizard was canceled. events.unmute() pr.refresh() # This'll destroy all the pages of the wizard as well. wiz.destroy() # Enable help panel updates again. #events.send(events.Command('unfreeze')) # Tell the user about unusable profiles. if len(unusableProfiles) > 0: dialog, area = sb.util.dialog.createButtonDialog( 'wizard-unlaunchable-profiles', ['ok'], 'ok', resizable=False) # Compose a list of the unlaunchable profiles. profList = '' unusableProfiles.sort(lambda a, b: cmp(language.translate(a), language.translate(b))) for p in unusableProfiles: profList += "\n" + language.translate(p) msg = area.createText() msg.setText(language.translate('wizard-unlaunchable-profiles-listed') + "\n" + profList) msg.resizeToBestSize() dialog.run()