Example #1
0
    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
Example #3
0
    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()
Example #5
0
    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
Example #7
0
    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())
Example #9
0
    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())
Example #10
0
    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>')
Example #11
0
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()