Esempio n. 1
0
    def onCopyCalib(self, event):
        """Creates a new calibration entry for the monitor.
        Note that the calibration date will reflect the save date/time
        """

        # use time as initial guess at name
        calibTime = time.localtime()
        calibTimeStr = monitors.strFromDate(calibTime)

        # then use dialogue so user can override
        msg = _translate(
            'Name of this calibration (for monitor "%(name)s") will be:)')
        infoStr = msg % {'name': self.currentMon.name}
        dlg = wx.TextEntryDialog(self, message=infoStr,
                                 defaultValue=calibTimeStr,
                                 caption=_translate('Input text'))
        if dlg.ShowModal() == wx.ID_OK:
            newCalibName = dlg.GetValue()
            # update the GUI to reflect new calibration
            self.currentMon.copyCalib(newCalibName)
            self.currentMon.setCalibDate(calibTime)

            self.onChangeCalibSelection(1, newCalibName)
            self.updateCalibList()
            self.unSavedMonitor = True
        dlg.Destroy()
Esempio n. 2
0
    def __init__(self, parent, levels):

        wx.Dialog.__init__(self, parent, -1,
                           _translate('Recorded luminance values'),
                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
        pad = 5
        panel = wx.Panel(self, -1)
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(self.makeCalibBox(parent=panel, levels=levels), 1,
                      wx.EXPAND | wx.ALL, pad)

        butBox = wx.BoxSizer(wx.HORIZONTAL)
        btnOK = wx.Button(panel, wx.ID_OK, _translate(" OK "))
        btnOK.SetDefault()
        btnCANC = wx.Button(panel, wx.ID_CANCEL, _translate(" Cancel "))

        butBox.Add(btnOK, 1, wx.BOTTOM | wx.ALIGN_RIGHT, pad)
        butBox.Add(btnCANC, 1, wx.BOTTOM | wx.RIGHT | wx.ALIGN_RIGHT, pad)
        mainSizer.Add(butBox, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM,
                      border=10)

        # finalise panel layout
        panel.SetAutoLayout(True)
        panel.SetSizerAndFit(mainSizer)
        mainSizer.Layout()
        self.SetSize(self.GetBestSize())
Esempio n. 3
0
 def onNewMon(self, event):
     # open a dialogue to get the name
     dlg = wx.TextEntryDialog(self, _translate('New monitor name:'),
                              caption=_translate('Input text'))
     if dlg.ShowModal() == wx.ID_OK:
         self.currentMonName = dlg.GetValue()
         self.ctrlMonList.Append(self.currentMonName)
         self.ctrlMonList.SetStringSelection(self.currentMonName)
         self.currentMon = monitors.Monitor(
             self.currentMonName, verbose=True)
         self.updateCalibList()
         self.onChangeCalibSelection(event=1)
         self.unSavedMonitor = True
     dlg.Destroy()
Esempio n. 4
0
    def __init__(self, title=_translate('PsychoPy Dialog'),
                 pos=None, size=None, style=None,
                 labelButtonOK=_translate(" OK "),
                 labelButtonCancel=_translate(" Cancel "),
                 screen=-1):

        global app  # avoid recreating for every gui
        app = ensureQtApp()
        QtWidgets.QDialog.__init__(self, None, Qt.WindowTitleHint)

        self.inputFields = []
        self.inputFieldTypes = []
        self.inputFieldNames = []
        self.data = []
        self.irow = 0

        # QtWidgets.QToolTip.setFont(QtGui.QFont('SansSerif', 10))

        # add buttons for OK and Cancel
        self.buttonBox = QtWidgets.QDialogButtonBox(Qt.Horizontal,
                                                    parent=self)
        self.okbutton = QtWidgets.QPushButton(labelButtonOK,
                                              parent=self)
        self.cancelbutton = QtWidgets.QPushButton(labelButtonCancel,
                                                  parent=self)
        self.buttonBox.addButton(self.okbutton,
                                 QtWidgets.QDialogButtonBox.ActionRole)
        self.buttonBox.addButton(self.cancelbutton,
                                 QtWidgets.QDialogButtonBox.ActionRole)
        self.okbutton.clicked.connect(self.accept)
        self.cancelbutton.clicked.connect(self.reject)

        if style:
            raise RuntimeWarning("Dlg does not currently support the "
                                 "style kwarg.")

        self.pos = pos
        self.size = size
        self.screen = screen
        # self.labelButtonOK = labelButtonOK
        # self.labelButtonCancel = labelButtonCancel

        self.layout = QtWidgets.QGridLayout()
        self.layout.setColumnStretch(1, 1)
        self.layout.setSpacing(10)
        self.layout.setColumnMinimumWidth(1, 250)

        self.setLayout(self.layout)

        self.setWindowTitle(title)
Esempio n. 5
0
    def test_set(self):
        lang = localization.getID('En_US')
        assert lang == 'en'

        for lang in ['En_US', 'Ja_JP', 'ja_JP']:
            setlang = localization.getID(lang)
            out = _translate(welcome)
            assert setlang == lang.lower()[:2]
            assert out == trans[setlang]
Esempio n. 6
0
 def __init__(self, title=_translate('PsychoPy dialogue'),
              pos=None, size=wx.DefaultSize,
              style=wx.DEFAULT_DIALOG_STYLE | wx.DIALOG_NO_PARENT,
              labelButtonOK=_translate(" OK "),
              labelButtonCancel=_translate(" Cancel ")):
     style = style | wx.RESIZE_BORDER
     global app  # avoid recreating for every gui
     app = ensureWxApp()
     super().__init__(parent=None, id=-1, title=title, style=style)
     self.inputFields = []
     self.inputFieldTypes = []
     self.inputFieldNames = []
     self.data = []
     # prepare a frame in which to hold objects
     self.sizer = wx.BoxSizer(wx.VERTICAL)
     # self.addText('')  # insert some space at top of dialogue
     self.pos = pos
     self.labelButtonOK = labelButtonOK
     self.labelButtonCancel = labelButtonCancel
Esempio n. 7
0
    def onBtnFindPhotometer(self, event):

        # safer to get by index, but GetStringSelection will work for
        # nonlocalized techincal names:
        photName = self.ctrlPhotomType.GetStringSelection()
        # not sure how
        photPort = self.ctrlPhotomPort.GetValue().strip()
        # [0] == Scan all ports
        if not photPort or photPort == self._photomChoices[0]:
            photPort = None
        elif photPort.isdigit():
            photPort = int(photPort)
        # search all ports
        self.comPortLabel.SetLabel(_translate('Scanning ports...'))
        self.Update()
        self.photom = hardware.findPhotometer(device=photName, ports=photPort)
        if self.photom is not None and self.photom.OK:
            self.btnFindPhotometer.Disable()
            self.btnCalibrateGamma.Enable(True)
            self.btnTestGamma.Enable(True)
            if hasattr(self.photom, 'getLastSpectrum'):
                self.btnCalibrateColor.Enable(True)
            msg = _translate('%(photomType)s found on %(photomPort)s')
            self.comPortLabel.SetLabel(msg %
                                       {'photomType': self.photom.type,
                                        'photomPort': self.photom.portString})
        else:
            self.comPortLabel.SetLabel(_translate('No photometers found'))
            self.photom = None

        # does this device need a dark calibration?
        if (hasattr(self.photom, 'getNeedsCalibrateZero') and
                self.photom.getNeedsCalibrateZero()):
            # prompt user if we need a dark calibration for the device
            if self.photom.getNeedsCalibrateZero():
                dlg = wx.Dialog(self, title=_translate(
                    'Dark calibration of ColorCAL'))
                msg = _translate('Your ColorCAL needs to be calibrated first.'
                                 ' Please block all light from getting into '
                                 'the lens and press OK.')
                while self.photom.getNeedsCalibrateZero():
                    txt = _translate('Dark calibration of ColorCAL')
                    dlg = dialogs.MessageDialog(self, message=msg,
                                                title=txt,
                                                type='Info')
                    # info dlg has only an OK button
                    resp = dlg.ShowModal()
                    if resp == wx.ID_CANCEL:
                        self.photom = None
                        self.comPortLabel.SetLabel('')
                        return 0
                    elif resp == wx.ID_OK:
                        self.photom.calibrateZero()
                    # this failed at least once. Try again.
                    msg = _translate('Try again. Cover the lens fully and '
                                     'press OK')
Esempio n. 8
0
 def summary(self, items=None):
     """Return a list of (item, color) for gui display. For non-fatal items
     """
     config = {}
     for item in items:
         config[item[0]] = [item[1], item[2], item[3]]  # [3] = warn or not
     green = '#009933'
     red = '#CC3300'
     check = u"\u2713   "
     summary = [(check + _translate('video card drivers'), green)]
     ofInterest = ('python version', 'available memory', 'openGL version',
                   'visual sync (refresh)', 'refresh stability (SD)',
                   'no dropped frames', 'internet access')
     # ofInterest.append('background processes')
     for item in ofInterest:
         if not item in config.keys():
             continue  # eg, microphone latency
         if config[item][2]:  # warn True
             summary.append(("X   " + _translate(item), red))
         else:
             summary.append((check + _translate(item), green))
     return summary
Esempio n. 9
0
def fileOpenDlg(tryFilePath="",
                tryFileName="",
                prompt=_translate("Select file to open"),
                allowed=None):
    """A simple dialogue allowing read access to the file system.

    :parameters:

        tryFilePath: string
            default file path on which to open the dialog

        tryFileName: string
            default file name, as suggested file

        prompt: string (default "Select file to open")
            can be set to custom prompts

        allowed: string (available since v1.62.01)
            a string to specify file filters.
            e.g. "Text files (\*.txt) ;; Image files (\*.bmp \*.gif)"
            See http://pyqt.sourceforge.net/Docs/PyQt4/qfiledialog.html
            #getOpenFileNames
            for further details

    If tryFilePath or tryFileName are empty or invalid then
    current path and empty names are used to start search.

    If user cancels, then None is returned.
    """
    global qtapp  # avoid recreating for every gui
    qtapp = ensureQtApp()

    if allowed is None:
        allowed = ("All files (*.*);;"
                   "PsychoPy Data (*.psydat);;"
                   "txt (*.txt *.dlm *.csv);;"
                   "pickled files (*.pickle *.pkl);;"
                   "shelved files (*.shelf)")
    fdir = os.path.join(tryFilePath, tryFileName)
    filesToOpen = QtWidgets.QFileDialog.getOpenFileNames(parent=None,
                                                         caption=prompt,
                                                         directory=fdir,
                                                         filter=allowed)
    if type(filesToOpen) == tuple:  # some versions(?) of PyQt return (files, filter)
        filesToOpen = filesToOpen[0]

    filesToOpen = [str(fpath) for fpath in filesToOpen
                   if os.path.exists(fpath)]
    if len(filesToOpen) == 0:
        return None
    return filesToOpen
Esempio n. 10
0
    def __init__(self, parent, monitor):
        self.method = 'auto'
        self.nPoints = 8
        assert isinstance(monitor, monitors.Monitor)
        self.useBits = monitor.getUseBits()

        wx.Dialog.__init__(self, parent, -1, _translate('Gamma Calibration'),
                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
        mainSizer = wx.FlexGridSizer(cols=2, hgap=1, vgap=1)

        # select method of calib (auto, semi-auto, manual)
        # todo: make the input  tablefor manual method
        self.methodChoiceBx = wx.Choice(self, -1, choices=['auto', 'semi'])
        self.methodChoiceBx.SetStringSelection('auto')
        wx.EVT_CHOICE(self, self.methodChoiceBx.GetId(), self.onMethodChange)

        self.ctrlUseBits = wx.CheckBox(self, -1, _translate('Use Bits++'))
        self.ctrlUseBits.SetValue(self.useBits)

        msg = _translate('Number of calibration points:')
        self.labelNPoints = wx.StaticText(self, -1, msg)
        self.ctrlNPoints = intctrl.IntCtrl(self, -1, value=8)

        msg = _translate('Screen number (primary is 1)')
        self.labelScrN = wx.StaticText(self, -1, msg)
        self.ctrlScrN = intctrl.IntCtrl(self, -1, value=1)

        msg = _translate('Patch size (fraction of screen):')
        self.labelStimSize = wx.StaticText(self, -1, msg)
        self.ctrlStimSize = wx.TextCtrl(self, -1, '0.3')

        pad = 5
        mainSizer.Add((0, 0), 1, wx.ALL, pad)
        mainSizer.Add(self.methodChoiceBx, 1, wx.ALL, pad)
        mainSizer.Add(self.labelScrN, 1, wx.ALL, pad)
        mainSizer.Add(self.ctrlScrN, 1, wx.ALL, pad)
        mainSizer.Add(self.labelNPoints, 1, wx.ALL, pad)
        mainSizer.Add(self.ctrlNPoints, 1, wx.ALL, pad)
        mainSizer.Add(self.labelStimSize, 1, wx.ALL, pad)
        mainSizer.Add(self.ctrlStimSize, 1, wx.ALL, pad)
        mainSizer.Add((0, 0), 1, wx.ALL, pad)
        mainSizer.Add(self.ctrlUseBits, 1, wx.ALL, pad)

        btnOK = wx.Button(self, wx.ID_OK, _translate(" OK "))
        btnOK.SetDefault()
        mainSizer.Add(btnOK, 1, wx.TOP | wx.BOTTOM | wx.ALIGN_RIGHT, pad)
        btnCANC = wx.Button(self, wx.ID_CANCEL, _translate(" Cancel "))
        mainSizer.Add(btnCANC, 1,
                      wx.TOP | wx.BOTTOM | wx.RIGHT | wx.ALIGN_RIGHT, pad)
        self.Center()
        # mainSizer.Fit(self)
        self.SetAutoLayout(True)
        self.SetSizerAndFit(mainSizer)
Esempio n. 11
0
    def makeCalibBox(self, parent, levels):
        '''do my best to make a calibration box'''
        gammaBox = wx.StaticBox(parent, -1, _translate('Luminance Values'))
        gammaBox.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL))
        gammaBoxSizer = wx.StaticBoxSizer(gammaBox, wx.VERTICAL)

        theCols = map(str, levels)
        self.gammaGrid = SimpleGrid(parent, id=-1,
                                    cols=theCols,
                                    rows=['lum', 'R', 'G', 'B'])
        gammaBoxSizer.Add(self.gammaGrid)
        grid.EVT_GRID_CELL_CHANGE(self.gammaGrid, self.onChangeGammaGrid)
        gammaBoxSizer.Layout()

        return gammaBoxSizer
Esempio n. 12
0
def fileSaveDlg(initFilePath="", initFileName="",
                prompt=_translate("Select file to save"),
                allowed=None):
    """A simple dialogue allowing write access to the file system.
    (Useful in case you collect an hour of data and then try to
    save to a non-existent directory!!)

    :parameters:

        initFilePath: string
            default file path on which to open the dialog

        initFileName: string
            default file name, as suggested file

        prompt: string (default "Select file to open")
            can be set to custom prompts

        allowed: string
            A string to specify file filters.
            e.g. "BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif"
            See http://www.wxpython.org/docs/api/wx.FileDialog-class.html
            for further details

    If initFilePath or initFileName are empty or invalid then
    current path and empty names are used to start search.

    If user cancels the None is returned.
    """
    if allowed is None:
        allowed = "All files (*.*)|*.*"
        # "txt (*.txt)|*.txt"
        # "pickled files (*.pickle, *.pkl)|*.pickle"
        # "shelved files (*.shelf)|*.shelf"
    global app  # avoid recreating for every gui
    app = ensureWxApp()
    dlg = wx.FileDialog(None, prompt, initFilePath,
                        initFileName, allowed, wx.SAVE)
    if dlg.ShowModal() == OK:
        # get names of images and their directory
        outName = dlg.GetFilename()
        outPath = dlg.GetDirectory()
        dlg.Destroy()
        # tmpApp.Destroy()  # this causes an error message for some reason
        fullPath = os.path.join(outPath, outName)
    else:
        fullPath = None
    return fullPath
Esempio n. 13
0
 def onDeleteCalib(self, event):
     calToDel = self.ctrlCalibList.GetStringSelection()
     # warn user that data will be lost
     msg = _translate('Are you sure you want to delete this calibration? '
                      '(cannot be undone)')
     dlg = dialogs.MessageDialog(parent=self,
                                 message=msg,
                                 type='Warning')
     if dlg.ShowModal() == wx.ID_YES:
         # delete it
         self.currentMon.delCalib(calToDel)
         # load most recent calibration instead
         # this will load calibration "-1" (last calib)
         self.onChangeCalibSelection(event=None, newCalib=-1)
         self.updateCalibList()
     dlg.Destroy()
Esempio n. 14
0
 def onCloseWindow(self, event):
     if self.unSavedMonitor:
         # warn user that data will be lost
         msg = _translate(
             'Save changes to monitor settings before quitting?')
         dlg = dialogs.MessageDialog(self, message=msg, type='Warning')
         resp = dlg.ShowModal()
         if resp == wx.ID_CANCEL:
             return 1  # return before quitting
         elif resp == wx.ID_YES:
             # save then quit
             self.currentMon.saveMon()
         elif resp == wx.ID_NO:
             pass  # don't save just quit
         dlg.Destroy()
     self.onCopyMon()  # save current monitor name to clipboard
     self.Destroy()
Esempio n. 15
0
    def plotSpectra(self, event=None):
        msg = _translate('%(monName)s %(calibName)s Spectra')
        figTitle = msg % {'monName': self.currentMonName,
                          'calibName': self.currentCalibName}
        plotWindow = PlotFrame(self, 1003, figTitle)
        figure = Figure(figsize=(5, 5), dpi=80)
        figureCanvas = FigureCanvas(plotWindow, -1, figure)
        plt = figure.add_subplot(111)
        plt.hold('off')

        nm, spectraRGB = self.currentMon.getSpectra()
        if nm != None:
            plt.plot(nm, spectraRGB[0, :], 'r-', linewidth=1.5)
            plt.hold('on')
            plt.plot(nm, spectraRGB[1, :], 'g-', linewidth=2)
            plt.plot(nm, spectraRGB[2, :], 'b-', linewidth=2)
        figureCanvas.draw()  # update the canvas
        plotWindow.addCanvas(figureCanvas)
Esempio n. 16
0
 def onDeleteMon(self, event):
     monToDel = self.currentMonName
     msg = _translate('Are you sure you want to delete all details for %s? '
                      '(cannot be undone)')
     dlg = dialogs.MessageDialog(parent=self, message=msg % monToDel,
                                 type='Warning')
     response = dlg.ShowModal()
     dlg.Destroy()
     if response == wx.ID_YES:
         # delete it
         monitorFileName = os.path.join(monitors.monitorFolder,
                                        monToDel + ".calib")
         os.remove(monitorFileName)
         self.currentMon = None
         self.currentMonName = None
         self.updateMonList()
         # load most recent calibration instead
         # this will load calibration "-1" (last calib)
         self.onChangeMonSelection(event=None)
         self.updateCalibList()
Esempio n. 17
0
def fileOpenDlg(tryFilePath="",
                tryFileName="",
                prompt=_translate("Select file(s) to open"),
                allowed=None):
    """A simple dialogue allowing read access to the file system.

    :parameters:
        tryFilePath: string
            default file path on which to open the dialog
        tryFileName: string
            default file name, as suggested file
        prompt: string (default "Select file to open")
            can be set to custom prompts
        allowed: string (available since v1.62.01)
            a string to specify file filters.
            e.g. "BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif"
            See http://www.wxpython.org/docs/api/wx.FileDialog-class.html
            for further details

    If tryFilePath or tryFileName are empty or invalid then
    current path and empty names are used to start search.

    If user cancels, then None is returned.
    """
    if allowed is None:
        allowed = ("PsychoPy Data (*.psydat)|*.psydat|"
                   "txt (*.txt,*.dlm,*.csv)|*.txt;*.dlm;*.csv|"
                   "pickled files (*.pickle, *.pkl)|*.pickle|"
                   "shelved files (*.shelf)|*.shelf|"
                   "All files (*.*)|*.*")
    global app  # avoid recreating for every gui
    app = ensureWxApp()
    dlg = wx.FileDialog(None, prompt, tryFilePath, tryFileName, allowed,
                        wx.OPEN | wx.FILE_MUST_EXIST | wx.MULTIPLE)
    if dlg.ShowModal() == OK:
        # get names of images and their directory
        fullPaths = dlg.GetPaths()
    else:
        fullPaths = None
    dlg.Destroy()
    return fullPaths
Esempio n. 18
0
 def onChangeMonSelection(self, event):
     if self.unSavedMonitor:
         if self.currentMonName == self.ctrlMonList.GetStringSelection():
             # it didnt' really change
             return 1
         # warn user that data will be lost
         msg = _translate('Save changes to monitor?')
         dlg = dialogs.MessageDialog(self, msg, type='Warning')
         resp = dlg.ShowModal()
         dlg.Destroy()
         if resp == wx.ID_CANCEL:
             # revert and return
             self.ctrlMonList.SetStringSelection(self.currentMonName)
             return False  # return before quitting
         elif resp == wx.ID_YES:
             # save then change
             self.currentMon.saveMon()
         elif resp == wx.ID_NO:
             pass  # don't save just change
     self.currentMonName = self.ctrlMonList.GetStringSelection()
     self.loadMonitor(self.currentMonName)
Esempio n. 19
0
    def makeMenuBar(self):
        menuBar = wx.MenuBar()
        fileMenu = wx.Menu()
        fileMenu.Append(idMenuSave,
                        _translate('Save\tCtrl+S'),
                        _translate('Save the current monitor'))
        wx.EVT_MENU(self, idMenuSave, self.onSaveMon)
        _hint = _translate(
            'Close Monitor Center (but not other PsychoPy windows)')
        fileMenu.Append(wx.ID_CLOSE,
                        _translate('Close Monitor Center\tCtrl+W'),
                        _hint)
        wx.EVT_MENU(self, wx.ID_CLOSE, self.onCloseWindow)
        menuBar.Append(fileMenu, _translate('&File'))

        # Edit
        editMenu = wx.Menu()
        id = wx.NewId()
        _hint = _translate("Copy the current monitor's name to clipboard")
        editMenu.Append(id, _translate('Copy\tCtrl+C'), _hint)
        wx.EVT_MENU(self, id, self.onCopyMon)
        menuBar.Append(editMenu, _translate('&Edit'))

        self.SetMenuBar(menuBar)
Esempio n. 20
0
def fileSaveDlg(initFilePath="", initFileName="",
                prompt=_translate("Select file to save"),
                allowed=None):
    """A simple dialogue allowing write access to the file system.
    (Useful in case you collect an hour of data and then try to
    save to a non-existent directory!!)

    :parameters:
        initFilePath: string
            default file path on which to open the dialog
        initFileName: string
            default file name, as suggested file
        prompt: string (default "Select file to open")
            can be set to custom prompts
        allowed: string
            a string to specify file filters.
            e.g. "Text files (\*.txt) ;; Image files (\*.bmp \*.gif)"
            See http://pyqt.sourceforge.net/Docs/PyQt4/qfiledialog.html
            #getSaveFileName
            for further details

    If initFilePath or initFileName are empty or invalid then
    current path and empty names are used to start search.

    If user cancels the None is returned.
    """
    if allowed is None:
        allowed = ("All files (*.*);;"
                   "txt (*.txt);;"
                   "pickled files (*.pickle *.pkl);;"
                   "shelved files (*.shelf)")
    global qtapp  # avoid recreating for every gui
    qtapp = ensureQtApp()

    fdir = os.path.join(initFilePath, initFileName)
    r = QtWidgets.QFileDialog.getSaveFileName(parent=None, caption=prompt,
                                              directory=fdir, filter=allowed)
    return str(r) or None
Esempio n. 21
0
 def OnInit(self):
     frame = MainFrame(None, _translate('PsychoPy Monitor Center'))
     frame.Show(True)
     self.SetTopWindow(frame)
     return True
Esempio n. 22
0
    def runDiagnostics(self, win, verbose=False):
        """Return list of (key, val, msg, warn) tuple, set self.warnings

        All tuple elements will be of <type str>.

        msg can depend on val; warn==True indicates a concern.
        Plain text is returned, expected to be used in html <table>.
        Hyperlinks can be embedded as <a href="...">
        """

        report = []  # add item tuples in display order

        # get lots of info and do quick-to-render visual (want 0 frames drop):
        #     for me, grating draw times are: mean 0.53 ms, SD 0.77 ms
        items = info.RunTimeInfo(win=win, refreshTest='grating',
                                 verbose=True, userProcsDetailed=True)

        totalRAM = items['systemMemTotalRAM']
        freeRAM = items['systemMemFreeRAM']
        warn = False
        if freeRAM == 'unknown':
            if totalRAM != 'unknown':
                totalRAM = "%.1fG" % (totalRAM / 1024.)
            txt = _translate(
                'could not assess available physical RAM; total %s')
            msg = txt % totalRAM
            report.append(('available memory', 'unknown', msg, warn))
        else:
            txt = _translate(
                'physical RAM available for configuration test '
                '(of %.1fG total)')
            msg = txt % (totalRAM / 1024.)
            if freeRAM < 300:  # in M
                txt = _translate(
                    'Warning: low available physical RAM for '
                    'configuration test (of %.1fG total)')
                msg = txt % (totalRAM / 1024.)
                warn = True
            report.append(('available memory', unicode(freeRAM) + 'M',
                           msg, warn))

        # ----- PSYCHOPY: -----
        warn = False
        report.append(('PsychoPy', '', '', False))  # not localized
        report.append(('psychopy', __version__,
                       _translate('avoid upgrading during an experiment'),
                       False))
        msg = _translate(
            'can be set in <a href="http://www.psychopy.org/general/'
            'prefs.html#application-settings-app">Preferences -> App</a>')
        report.append(('locale', items['systemLocale'], msg, False))
        msg = ''
        if items['pythonVersion'] < '2.5' or items['pythonVersion'] >= '3':
            msg = _translate('Warning: python 2.6 or 2.7 required; '
                             '2.5 is not supported but might work')
            warn = True
        if 'EPD' in items['pythonFullVersion']:
            msg += ' Enthought Python Distribution'
        elif 'PsychoPy2.app' in items['pythonExecutable']:
            msg += ' (PsychoPy StandAlone)'
        bits, linkage = platform.architecture()
        # if not bits.startswith('32'):
        #    msg = 'Warning: 32-bit python required; ' + msg
        report.append(
            ('python version',
             items['pythonVersion'] + ' &nbsp;(%s)' % bits,
             msg, warn))
        warn = False
        if verbose:
            msg = ''
            if items['pythonWxVersion'] < '2.8.10':
                msg = _translate('Warning: wx 2.8.10 or higher required')
                warn = True
            report.append(('wx', items['pythonWxVersion'], '', warn))
            report.append(
                ('pyglet', items['pythonPygletVersion'][:32], '', False))
            report.append(('rush', str(items['psychopyHaveExtRush']),
                           _translate('for high-priority threads'), False))

        # ----- VISUAL: -----
        report.append(('Visual', '', '', False))
        warn = False
        # openGL settings:
        msg = ''
        if items['openGLVersion'] < '2.':
            msg = _translate(
                'Warning: <a href="http://www.psychopy.org/general/timing'
                '/reducingFrameDrops.html?highlight=OpenGL+2.0">OpenGL '
                '2.0 or higher is ideal</a>.')
            warn = True
        report.append(('openGL version', items['openGLVersion'], msg, warn))
        report.append(('openGL vendor', items['openGLVendor'], '', False))
        report.append(('screen size', ' x '.join(
            map(str, items['windowSize_pix'])), '', False))
        # report.append(('wait blanking', str(items['windowWaitBlanking']), '',
        #   False))

        warn = False
        msg = ''
        if not items['windowHaveShaders']:
            msg = _translate(
                'Warning: <a href="http://www.psychopy.org/general/timing'
                '/reducingFrameDrops.html?highlight=shader">Rendering of'
                ' complex stimuli will be slow</a>.')
            warn = True
        report.append(('have shaders', str(
            items['windowHaveShaders']), msg, warn))

        warn = False
        msg = _translate(
            'during the drifting <a href="http://www.psychopy.org/api/'
            'visual/gratingstim.html">GratingStim</a>')
        if items['windowRefreshTimeMedian_ms'] < 3.3333333:
            msg = _translate(
                "Warning: too fast? visual sync'ing with the monitor"
                " seems unlikely at 300+ Hz")
            warn = True
        report.append(('visual sync (refresh)', "%.2f ms/frame" %
                       items['windowRefreshTimeMedian_ms'], msg, warn))
        msg = _translate('SD &lt; 0.5 ms is ideal (want low variability)')
        warn = False
        if items['windowRefreshTimeSD_ms'] > .5:
            msg = _translate(
                'Warning: the refresh rate has high frame-to-frame '
                'variability (SD &gt; 0.5 ms)')
            warn = True
        report.append(('refresh stability (SD)', "%.2f ms" %
                       items['windowRefreshTimeSD_ms'], msg, warn))

        # draw 100 dots as a minimally demanding visual test:
        # first get baseline frame-rate (safe as possible, no drawing):
        avg, sd, median = visual.getMsPerFrame(win)
        dots100 = visual.DotStim(
            win, nDots=100, speed=0.005, dotLife=12, dir=90,
            coherence=0.2, dotSize=8, fieldShape='circle', autoLog=False)
        win.recordFrameIntervals = True
        win.frameIntervals = []
        win.flip()
        for i in xrange(180):
            dots100.draw()
            win.flip()
        msg = _translate(
            'during <a href="http://www.psychopy.org/api/visual/'
            'dotstim.html">DotStim</a> with 100 random dots')
        warn = False
        intervalsMS = np.array(win.frameIntervals) * 1000
        nTotal = len(intervalsMS)
        nDropped = sum(intervalsMS > (1.5 * median))
        if nDropped:
            msg = _translate(
                'Warning: could not keep up during <a href="http://'
                'www.psychopy.org/api/visual/dotstim.html">DotStim</a>'
                ' with 100 random dots.')
            warn = True
        report.append(('no dropped frames', '%i / %i' % (nDropped, nTotal),
                       msg, warn))
        win.recordFrameIntervals = False

        if verbose:
            report.append(('openGL max vertices',
                           str(items['openGLmaxVerticesInVertexArray']),
                           '', False))
            keyList = ('GL_ARB_multitexture', 'GL_EXT_framebuffer_object',
                       'GL_ARB_fragment_program', 'GL_ARB_shader_objects',
                       'GL_ARB_vertex_shader', 'GL_ARB_texture_float',
                       'GL_ARB_texture_non_power_of_two', 'GL_STEREO')
            for key in keyList:
                val = items['openGLext.' + key]  # boolean
                if not val:
                    val = '<strong>' + str(val) + '</strong>'
                report.append((key, str(val), '', False))

        # ----- AUDIO: -----
        report.append(('Audio', '', '', False))
        msg = ''
        warn = False
        if not 'systemPyoVersion' in items:
            msg = _translate(
                'Warning: pyo is needed for sound and microphone.')
            warn = True
            items['systemPyoVersion'] = _translate('(missing)')
        # elif items['systemPyoVersion'] < '0.6.2':
        #    msg = 'pyo 0.6.2 compiled with --no-messages will
        #    suppress start-up messages'
        report.append(('pyo', items['systemPyoVersion'], msg, warn))
        # TO-DO: add microphone + playback as sound test

        # ----- NUMERIC: -----
        report.append(('Numeric', '', '', False))
        report.append(('numpy', items['pythonNumpyVersion'],
                       _translate('vector-based (fast) calculations'), False))
        report.append(('scipy', items['pythonScipyVersion'],
                       _translate('scientific / numerical'), False))
        report.append(('matplotlib', items['pythonMatplotlibVersion'],
                       _translate('plotting; fast contains(), overlaps()'),
                       False))

        # ----- SYSTEM: -----
        report.append(('System', '', '', False))
        report.append(('platform', items['systemPlatform'], '', False))
        msg = _translate('for online help, usage statistics, software '
                         'updates, and google-speech')
        warn = False
        if items['systemHaveInternetAccess'] is not True:
            items['systemHaveInternetAccess'] = 'False'
            msg = _translate('Warning: could not connect (no proxy attempted)')
            warn = True
            # TO-DO: dlg to query whether to try to auto-detect (can take a
            # while), or allow manual entry of proxy str, save into prefs
        val = str(items['systemHaveInternetAccess'])
        report.append(('internet access', val, msg, warn))
        report.append(('auto proxy',
                       str(self.prefs.connections['autoProxy']),
                       _translate('try to auto-detect a proxy if needed; see'
                                  ' <a href="http://www.psychopy.org/general'
                                  '/prefs.html#connection-settings-connection'
                                  's">Preferences -> Connections</a>'),
                       False))
        if not self.prefs.connections['proxy'].strip():
            prx = '&nbsp;&nbsp;--'
        else:
            prx = unicode(self.prefs.connections['proxy'])
        report.append(('proxy setting', prx,
                       _translate('current manual proxy setting from <a '
                                  'href="http://www.psychopy.org/general/'
                                  'prefs.html#connection-settings-connections'
                                  '">Preferences -> Connections</a>'), False))

        txt = 'CPU speed test'
        report.append((txt, "%.3f s" % items['systemTimeNumpySD1000000_sec'],
                       _translate('numpy.std() of 1,000,000 data points'),
                       False))
        # TO-DO: more speed benchmarks
        # - load large image file from disk
        # - transfer image to GPU

        # ----- IMPORTS (relevant for developers & non-StandAlone): -----
        if verbose:  # always False for a real first-run
            report.append((_translate('Python packages'), '', '', False))
            packages = ['PIL', 'openpyxl', 'lxml', 'setuptools', 'pytest',
                        'sphinx', 'psignifit', 'pyserial', 'pp',
                        'pynetstation', 'labjack']
            if sys.platform == 'win32':
                packages.append('pywin32')
                packages.append('winioport')
            for pkg in packages:
                try:
                    if pkg == 'PIL':
                        exec('import PIL.Image')
                        ver = PIL.Image.VERSION
                    # elif pkg == 'lxml':
                    #
                    elif pkg == 'pp':
                        exec('import pp; ver = pp.version')
                    elif pkg == 'pynetstation':
                        exec('from psychopy.hardware import egi')
                        ver = 'import ok'
                    elif pkg == 'pyserial':
                        exec('import serial')
                        ver = serial.VERSION
                    elif pkg == 'pywin32':
                        exec('import win32api')
                        ver = 'import ok'
                    else:
                        exec('import ' + pkg)
                        try:
                            ver = eval(pkg + '.__version__')
                        except Exception:
                            ver = 'import ok'
                    report.append((pkg, ver, '', False))
                except (ImportError, AttributeError):
                    msg = _translate('could not import package %s')
                    report.append((pkg, '&nbsp;&nbsp;--', msg % pkg, False))

        # rewrite to avoid assumption of locale en_US:
        self.warnings = list(
            set([key for key, val, msg, warn in report if warn]))

        return report
Esempio n. 23
0
    def plotGamma(self, event=None):
        msg = _translate('%(monName)s %(calibName)s Gamma Functions')
        figTitle = msg % {'monName': self.currentMonName,
                          'calibName': self.currentCalibName}
        plotWindow = PlotFrame(self, 1003, figTitle)

        figure = Figure(figsize=(5, 5), dpi=80)
        figureCanvas = FigureCanvas(plotWindow, -1, figure)
        plt = figure.add_subplot(111)
        plt.hold('off')

        gammaGrid = self.currentMon.getGammaGrid()
        lumsPre = self.currentMon.getLumsPre()
        levelsPre = self.currentMon.getLevelsPre()
        lumsPost = self.currentMon.getLumsPost()
        if lumsPre != None:
            colors = 'krgb'
            xxSmooth = monitors.numpy.arange(0, 255.5, 0.5)
            eq = self.currentMon.getLinearizeMethod()
            for gun in range(4):  # includes lum
                gamma = gammaGrid[gun, 2]
                minLum = gammaGrid[gun, 0]
                maxLum = gammaGrid[gun, 1]
                if eq <= 2:
                    # plot fitted curve
                    curve = monitors.gammaFun(xxSmooth, minLum, maxLum, gamma,
                                              eq=eq, a=None, b=None, k=None)
                    plt.plot(xxSmooth, curve, colors[gun] + '-',
                             linewidth=1.5)
                if self.currentMon.getLinearizeMethod() == 4:
                    a, b, k = gammaGrid[gun, 3:]
                    # plot fitted curve
                    curve = monitors.gammaFun(xxSmooth, minLum, maxLum, gamma,
                                              eq=eq, a=a, b=b, k=k)
                    plt.plot(xxSmooth, curve, colors[gun] + '-',
                             linewidth=1.5)
                else:
                    pass
                    # polyFit = self.currentMon._gammaInterpolator[gun]
                    # curve = xxSmooth*0.0
                    # for expon, coeff in enumerate(polyFit):
                    #    curve += coeff*xxSmooth**expon
                    # plt.plot(xxSmooth, curve, colors[gun]+'-', linewidth=1.5)
                # plot POINTS
                plt.plot(levelsPre, lumsPre[gun, :], colors[gun] + 'o',
                         linewidth=1.5)

            lumsPost = self.currentMon.getLumsPost()
            levelsPost = self.currentMon.getLevelsPost()
        if lumsPost != None:
            for gun in range(4):  # includes lum,r,g,b
                lums = lumsPost[gun, :]
                gamma = gammaGrid[gun, 2]
                gamma = gammaGrid[gun, 2]
                minLum = min(lums)
                maxLum = max(lums)
                # plot CURVE
                plt.plot([levelsPost[0], levelsPost[-1]],
                         [minLum, maxLum], colors[gun] + '--', linewidth=1.5)
                # plot POINTS
                plt.plot(levelsPost, lums, 'o', markerfacecolor='w',
                         markeredgecolor=colors[gun], linewidth=1.5)
        figureCanvas.draw()  # update the canvas
        plotWindow.addCanvas(figureCanvas)
Esempio n. 24
0
    def __init__(self, fullscr=True, interactive=True, log=True):
        super(BenchmarkWizard, self).__init__(interactive=interactive)
        self.firstrun = False
        self.prefs = prefs
        self.appName = 'PsychoPy2'
        self.name = self.appName + _translate(' Benchmark Wizard')

        dlg = gui.Dlg(title=self.name)
        dlg.addText('')
        dlg.addText(_translate('Benchmarking takes ~20-30 seconds to gather'))
        dlg.addText(_translate('configuration and performance data. Begin?'))
        dlg.addText('')
        if interactive:
            dlg.show()
            if not dlg.OK:
                return

        self._prepare()
        win = visual.Window(fullscr=fullscr, allowGUI=False,
                            monitor='testMonitor', autoLog=False)

        # do system info etc first to get fps, add to list later because
        # it's nicer for benchmark results to appears at top of the report:
        diagnostics = self.runDiagnostics(win, verbose=True)
        info = {}
        for k, v, m, w in diagnostics:
            # list of tuples --> dict, ignore msg m, warning w
            info[k] = v
        fps = 1000. / float(info['visual sync (refresh)'].split()[0])

        itemsList = [('Benchmark', '', '', False)]
        itemsList.append(('benchmark version', '0.1', _translate(
            'dots &amp; configuration'), False))
        itemsList.append(('full-screen', str(fullscr),
                          _translate('visual window for drawing'), False))

        if int(info['no dropped frames'].split('/')[0]) != 0:  # eg, "0 / 180"
            start = 50  # if 100 dots had problems earlier, here start lower
        else:
            start = 200
        for shape in ('circle', 'square'):
            # order matters: circle crashes first
            dotsList = self.runLotsOfDots(win, fieldShape=shape,
                                          starting=start, baseline=fps)
            itemsList.extend(dotsList)
            # start square where circle breaks down
            start = int(dotsList[-1][1])
        itemsList.extend(diagnostics)
        win.close()

        itemsDict = {}
        for itm in itemsList:
            if 'proxy setting' in itm[0] or not itm[1]:
                continue
            itemsDict[itm[0]] = itm[1].replace('<strong>', '').replace(
                '</strong>', '').replace('&nbsp;', '').replace('&nbsp', '')

        # present dialog, upload only if opt-in:
        dlg = gui.Dlg(title=self.name)
        dlg.addText('')
        dlg.addText(_translate(
            'Benchmark complete! (See the Coder output window.)'))

        self.htmlReport(itemsList)
        self.reportPath = os.path.join(self.prefs.paths['userPrefsDir'],
                                       'benchmarkReport.html')
        self.save()
        dlg = gui.Dlg(title=self.name)
        dlg.addText('')
        dlg.addText(_translate(
            'Click OK to view full configuration and benchmark data.'))
        dlg.addText(_translate('Click Cancel to stay in PsychoPy.'))
        dlg.addText('')
        if interactive:
            dlg.show()
            if dlg.OK:
                url = 'file://' + self.reportPath
                wx.LaunchDefaultBrowser(url)
Esempio n. 25
0
    def htmlReport(self, items=None, fatal=False):
        """Return an html report given a list of (key, val, msg, warn) items.

        format triggers: 'Critical issue' in fatal gets highlighted
                         warn == True -> highlight key and val
                         val == msg == '' -> use key as section heading
        """

        imgfile = os.path.join(self.prefs.paths['resources'],
                               'psychopySplash.png')
        _head = (u'<html><head><meta http-equiv="Content-Type" '
                 'content="text/html; charset=utf-8"></head><body>' +
                 '<a href="http://www.psychopy.org"><img src="%s" '
                 'width=396 height=156></a>')
        self.header = _head % imgfile
        # self.iconhtml = '<a href="http://www.psychopy.org"><img src="%s"
        #   width=48 height=48></a>' % self.iconfile
        _foot = _translate('This page was auto-generated by the '
                           'PsychoPy configuration wizard on %s')
        self.footer = ('<center><font size=-1>' +
                       _foot % data.getDateStr(format="%Y-%m-%d, %H:%M") +
                       '</font></center>')

        htmlDoc = self.header
        if fatal:
            # fatal is a list of strings:
            htmlDoc += ('<h2><font color="red">' +
                        _translate('Configuration problem') + '</font></h2><hr>')
            for item in fatal:
                item = item.replace('Critical issue', '<p><strong>')
                item += _translate('Critical issue') + '</strong>'
                htmlDoc += item + "<hr>"
        else:
            # items is a list of tuples:
            htmlDoc += ('<h2><font color="green">' +
                        _translate('Configuration report') + '</font></h2>\n')
            numWarn = len(self.warnings)
            if numWarn == 0:
                htmlDoc += _translate('<p>All values seem reasonable (no '
                                      'warnings, but there might still be '
                                      'room for improvement).</p>\n')
            elif numWarn == 1:
                _warn = _translate('1 suboptimal value was detected</font>, '
                                   'see details below (%s).</p>\n')
                htmlDoc += ('<p><font color="red">' +
                            _warn % (self.warnings[0]))
            elif numWarn > 1:
                _warn = _translate('%(num)i suboptimal values were detected'
                                   '</font>, see details below (%(warn)s).'
                                   '</p>\n')
                htmlDoc += ('<p><font color="red">' +
                            _warn % {'num': numWarn,
                                     'warn': ', '.join(self.warnings)})
            htmlDoc += '''<script type="text/javascript">
                // Loops through all rows in document and changes display
                // property of rows with a specific ID
                // toggle('ok', '') will display all rows
                // toggle('ok', 'none') hides ok rows, leaving Warning
                // rows shown
                function toggle(ID, display_value) {
                    var tr=document.getElementsByTagName('tr'),
                        i;
                    for (i=0;i<tr.length;i++) {
                        if (tr[i].id == ID) tr[i].style.display = display_value;
                    }
                }
                </script>
                <p>
                <button onClick="toggle('ok', 'none');">'''
            htmlDoc += _translate('Only show suboptimal values') + \
                '</button>' + \
                '''<button onClick="toggle('ok', '');">''' + \
                _translate('Show all information') + '</button></p>'
            htmlDoc += _translate('''<p>Resources:
                  Contributed <a href="http://upload.psychopy.org/benchmark/report.html">benchmarks</a>
                | <a href="http://www.psychopy.org/documentation.html">On-line documentation</a>
                | Download <a href="http://www.psychopy.org/PsychoPyManual.pdf">PDF manual</a>
                | <a href="http://groups.google.com/group/psychopy-users">Search the user-group archives</a>
                </p>''')
            htmlDoc += '<hr><p></p>    <table cellspacing=8 border=0>\n'
            htmlDoc += '    <tr><td><font size=+1><strong>' + \
                       _translate('Configuration test</strong> or setting') +\
                '</font></td><td><font size=+1><strong>' + _translate('Version or value') +\
                '</strong></font></td><td><font size=+1><em>' + \
                _translate('Notes') + '</em></font></td>'
            for (key, val, msg, warn) in items:
                if val == msg == '':
                    key = '<font color="darkblue" size="+1"><strong>' + \
                        _translate(key) + '</strong></font>'
                else:
                    key = '&nbsp;&nbsp;&nbsp;&nbsp;' + _translate(key)
                if warn:
                    key = '<font style=color:red><strong>' + \
                        _translate(key) + '</strong></font>'
                    val = '<font style=color:red><strong>' + val + '</strong></font>'
                    id = 'Warning'
                else:
                    id = 'ok'
                htmlDoc += '        <tr id="%s"><td>' % id
                htmlDoc += key + '</td><td>' + val + '</td><td><em>' + msg + '</em></td></tr>\n'
            htmlDoc += '    </table><hr>'
        htmlDoc += self.footer
        if not fatal and numWarn:
            htmlDoc += """<script type="text/javascript">toggle('ok', 'none'); </script>"""
        htmlDoc += '</body></html>'

        self.reportText = htmlDoc
Esempio n. 26
0
    def __init__(self, firstrun=False, interactive=True, log=True):
        """Check drivers, show GUIs, run diagnostics, show report.
        """
        super(ConfigWizard, self).__init__()
        self.firstrun = firstrun
        self.prefs = prefs
        self.appName = 'PsychoPy2'
        self.name = self.appName + _translate(' Configuration Wizard')
        self.reportPath = os.path.join(
            self.prefs.paths['userPrefsDir'], 'firstrunReport.html')
        # self.iconfile = os.path.join(self.prefs.paths['resources'],
        #       'psychopy.png')
        # dlg.SetIcon(wx.Icon(self.iconfile, wx.BITMAP_TYPE_PNG)) # no error
        # but no effect

        dlg = gui.Dlg(title=self.name)
        dlg.addText('')
        if firstrun:
            dlg.addText(_translate("Welcome to PsychoPy2!"), color='blue')
            dlg.addText('')
            dlg.addText(_translate("It looks like you are running PsychoPy "
                                   "for the first time."))
            dlg.addText(_translate("This wizard will help you get started "
                                   "quickly and smoothly."))
        else:
            dlg.addText(_translate("Welcome to the configuration wizard."))

        # test for fatal configuration errors:
        fatalItemsList = []
        cardInfo = gl_info.get_renderer().replace('OpenGL Engine', '').strip()
        if not driversOkay():
            dlg.addText('')
            dlg.addText(_translate("The first configuration check is your "
                                   "video card's drivers. The current"),
                        color='red')
            dlg.addText(_translate("drivers cannot support PsychoPy, so "
                                   "you'll need to update the drivers."),
                        color='red')
            msg = _translate("""<p>Critical issue:\n</p><p>Your video card (%(card)s) has drivers
                that cannot support the high-performance features that PsychoPy depends on.
                Fortunately, it's typically free and straightforward to get new drivers
                directly from the manufacturer.</p>
                <p><strong>To update the drivers:</strong>
                <li> You'll need administrator privileges.
                <li> On Windows, don't use the windows option to check for updates
                  - it can report that there are no updates available.
                <li> If your card is made by NVIDIA, go to
                  <a href="http://www.nvidia.com/Drivers">the NVIDIA website</a>
                  and use the 'auto detect' option. Try here for
                  <a href="http://support.amd.com/">ATI / Radeon drivers</a>. Or try
                  <a href="http://www.google.com/search?q=download+drivers+%(card2)s">
                  this google search</a> [google.com].
                <li> Download and install the driver.
                <li> Reboot the computer.
                <li> Restart PsychoPy.</p>
                <p>If you updated the drivers and still get this message, you'll
                  need a different video card to use PsychoPy. Click
                <a href="http://www.psychopy.org/installation.html#recommended-hardware">here
                for more information</a> [psychopy.org].</p>
            """)
            fatalItemsList.append(msg % {'card': cardInfo,
                                         'card2': cardInfo.replace(' ', '+')})
        if not cardOkay():
            msg = _translate("""<p>Critical issue:\n</p>""")
            msg += cardInfo
            fatalItemsList.append(msg)
            pass
        # other fatal conditions? append a 'Critical issue' msg to itemsList
        if not fatalItemsList:
            dlg.addText(_translate("We'll go through a series of configura"
                                   "tion checks in about 10 seconds. "))
            dlg.addText('')
            if firstrun:  # explain things more
                dlg.addText(_translate('Note: The display will switch to '
                                       'full-screen mode and will '))
                dlg.addText(_translate("then switch back. You don't need "
                                       "to do anything."))
            dlg.addText(_translate('Optional: For best results, please quit'
                                   ' all email programs, web-browsers, '))
            dlg.addText(_translate(
                'Dropbox, backup or sync services, and others.'))
            dlg.addText('')
            dlg.addText(_translate('Click OK to start, or Cancel to skip.'))
            if not self.firstrun:
                dlg.addField(label=_translate('Full details'),
                             initial=self.prefs.app['debugMode'])
        else:
            dlg.addText('')
            dlg.addText(_translate(
                'Click OK for more information, or Cancel to skip.'))

        # show the first dialog:
        dlg.addText('')
        if interactive:
            dlg.show()
        if fatalItemsList:
            self.htmlReport(fatal=fatalItemsList)
            self.save()
            # user ends up in browser:
            url = 'file://' + self.reportPath
            if interactive:
                wx.LaunchDefaultBrowser(url)
            return
        if interactive and not dlg.OK:
            return  # no configuration tests run

        # run the diagnostics:
        verbose = interactive and not self.firstrun and dlg.data[0]
        win = visual.Window(fullscr=interactive, allowGUI=False,
                            monitor='testMonitor', autoLog=log)
        itemsList = self.runDiagnostics(win, verbose)  # sets self.warnings
        win.close()
        self.htmlReport(itemsList)
        self.save()

        # display summary & options:
        dlg = gui.Dlg(title=self.name)
        dlg.addText('')
        dlg.addText(_translate('Configuration testing complete!'))
        summary = self.summary(items=itemsList)
        numWarn = len(self.warnings)
        if numWarn == 0:
            msg = _translate('All values seem reasonable (no warnings).')
        elif numWarn == 1:
            txt = _translate('1 suboptimal value was detected (%s)')
            msg = txt % self.warnings[0]
        else:
            txt = _translate(
                '%(num)i suboptimal values were detected (%(warn)s, ...)')
            msg = txt % {'num': len(self.warnings),
                         'warn': self.warnings[0]}
        dlg.addText(msg)
        for item in summary:
            dlg.addText(item[0], item[1])  # (key, color)
        dlg.addText('')
        dlg.addText(_translate(
            'Click OK for full details (will open in a web-browser),'))
        dlg.addText(_translate('or Cancel to stay in PsychoPy.'))
        dlg.addText('')
        if interactive:
            dlg.show()
            if dlg.OK:
                url = 'file://' + self.reportPath
                wx.LaunchDefaultBrowser(url)
        return
Esempio n. 27
0
    def __init__(self, parent, title):
        # create a default monitor with no name
        self.currentMon = monitors.Monitor('', verbose=False)
        self.currentMonName = None  # use to test if monitor is placeholder
        self.currentCalibName = None
        self.unSavedMonitor = False
        self.comPort = 1
        self.photom = None

        # start building the frame
        wx.Frame.__init__(self, parent, -1, title, size=wx.DefaultSize,
                          style=wx.DEFAULT_FRAME_STYLE)

        self.makeMenuBar()

        if NOTEBOOKSTYLE:
            # make the notebook
            self.noteBook = wx.Notebook(self, -1)

            # add the info page
            self.infoPanel = wx.Panel(self.noteBook, -1)
            self.noteBook.AddPage(self.infoPanel, _translate('Monitor Info'))
            infoSizer = wx.BoxSizer(wx.HORIZONTAL)
            infoSizer.Add(self.makeAdminBox(self.infoPanel), 1, wx.EXPAND)
            infoSizer.Add(self.makeInfoBox(self.infoPanel), 1, wx.EXPAND)
            self.infoPanel.SetAutoLayout(True)
            self.infoPanel.SetSizerAndFit(infoSizer)

            # add the calibration page
            self.calibPanel = wx.Panel(self.noteBook, -1)
            self.noteBook.AddPage(self.calibPanel, _translate('Calibration'))
            calibSizer = self.makeCalibBox(self.calibPanel)
            self.calibPanel.SetAutoLayout(True)
            self.calibPanel.SetSizerAndFit(calibSizer)

            self.noteBookSizer.Layout()
            self.noteBookSizer.Fit(self)
        else:
            # just one page
            self.infoPanel = wx.Panel(self, -1)
            mainSizer = wx.BoxSizer(wx.HORIZONTAL)
            leftSizer = wx.BoxSizer(wx.VERTICAL)
            rightSizer = wx.BoxSizer(wx.VERTICAL)
            _style = wx.EXPAND | wx.ALL
            leftSizer.Add(self.makeAdminBox(self.infoPanel), 1, _style, 2)
            leftSizer.Add(self.makeInfoBox(self.infoPanel), 1, _style, 2)
            rightSizer.Add(self.makeCalibBox(self.infoPanel), 1, _style, 2)
            #
            mainSizer.Add(leftSizer, 1, _style, 2)
            mainSizer.Add(rightSizer, 1, _style, 2)

            # finalise panel layout
            mainSizer.Layout()
            self.infoPanel.SetAutoLayout(True)
            self.infoPanel.SetSizerAndFit(mainSizer)

        # if wx version 2.5+:
        self.SetSize(self.GetBestSize())
        # self.CreateStatusBar()
        # self.SetStatusText("Maybe put tooltips down here one day")
        if os.path.isfile('psychopy.ico'):
            try:
                self.SetIcon(wx.Icon('psychopy.ico', wx.BITMAP_TYPE_ICO))
            except Exception:
                pass

        wx.EVT_CLOSE(self, self.onCloseWindow)
        self.updateMonList()
Esempio n. 28
0
    def makeAdminBox(self, parent):
        # make the box for the controls
        boxLabel = wx.StaticBox(parent, -1, _translate('Choose Monitor'))
        boxLabel.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL))
        adminBox = wx.StaticBoxSizer(boxLabel)

        # build the controls
        self.ctrlMonList = wx.ListBox(parent, idCtrlMonList,
                                      choices=['iiyama571', 'sonyG500'],
                                      size=(350, 100))
        wx.EVT_LISTBOX(self, idCtrlMonList, self.onChangeMonSelection)

        monButtonsBox = wx.BoxSizer(wx.VERTICAL)

        self.btnNewMon = wx.Button(parent, idBtnNewMon, _translate('New...'))
        wx.EVT_BUTTON(self, idBtnNewMon, self.onNewMon)
        monButtonsBox.Add(self.btnNewMon)
        self.btnNewMon.SetToolTipString(
            _translate("Create a new monitor"))

        self.btnSaveMon = wx.Button(parent, idBtnSaveMon, _translate('Save'))
        wx.EVT_BUTTON(self, idBtnSaveMon, self.onSaveMon)
        monButtonsBox.Add(self.btnSaveMon)
        msg = _translate("Save all calibrations for this monitor")
        self.btnSaveMon.SetToolTipString(msg)

        self.btnDeleteMon = wx.Button(parent, idBtnDeleteMon,
                                      _translate('Delete'))
        wx.EVT_BUTTON(self, idBtnDeleteMon, self.onDeleteMon)
        monButtonsBox.Add(self.btnDeleteMon)
        msg = _translate("Delete this monitor entirely")
        self.btnDeleteMon.SetToolTipString(msg)

        self.ctrlCalibList = wx.ListBox(parent, idCtrlCalibList,
                                        choices=[''],
                                        size=(350, 100))
        wx.EVT_LISTBOX(self, idCtrlCalibList, self.onChangeCalibSelection)
        calibButtonsBox = wx.BoxSizer(wx.VERTICAL)

        self.btnCopyCalib = wx.Button(parent, idBtnCopyCalib,
                                      _translate('Copy...'))
        wx.EVT_BUTTON(self, idBtnCopyCalib, self.onCopyCalib)
        calibButtonsBox.Add(self.btnCopyCalib)
        msg = _translate("Creates a new calibration entry for this monitor")
        self.btnCopyCalib.SetToolTipString(msg)

        self.btnDeleteCalib = wx.Button(
            parent, idBtnDeleteCalib, _translate('Delete'))
        wx.EVT_BUTTON(self, idBtnDeleteCalib, self.onDeleteCalib)
        calibButtonsBox.Add(self.btnDeleteCalib)
        msg = _translate("Remove this calibration entry (finalized when "
                         "monitor is saved)")
        self.btnDeleteCalib.SetToolTipString(msg)

        # add controls to box
        adminBoxMainSizer = wx.FlexGridSizer(cols=2, hgap=6, vgap=6)
        adminBoxMainSizer.AddMany([(1, 10), (1, 10),  # 2 empty boxes 1x10pix
                                   self.ctrlMonList, monButtonsBox,
                                   self.ctrlCalibList, calibButtonsBox])
        adminBox.Add(adminBoxMainSizer)
        return adminBox
Esempio n. 29
0
    def makeInfoBox(self, parent):
        # create the box
        infoBox = wx.StaticBox(parent, -1, _translate('Monitor Info'))
        infoBox.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL))
        infoBoxSizer = wx.StaticBoxSizer(infoBox, wx.VERTICAL)

        # scr distance
        labelScrDist = wx.StaticText(parent, -1,
                                     _translate("Screen Distance (cm):"),
                                     style=wx.ALIGN_RIGHT)
        self.ctrlScrDist = wx.TextCtrl(parent, idCtrlScrDist, "")
        wx.EVT_TEXT(self, idCtrlScrDist, self.onChangeScrDist)

        # scr width
        labelScrWidth = wx.StaticText(parent, -1,
                                      _translate("Screen Width (cm):"),
                                      style=wx.ALIGN_RIGHT)
        self.ctrlScrWidth = wx.TextCtrl(parent, idCtrlScrWidth, "")
        wx.EVT_TEXT(self, idCtrlScrWidth, self.onChangeScrWidth)

        # scr pixels
        _size = _translate("Size (pixels; Horiz,Vert):")
        labelScrPixels = wx.StaticText(parent, -1, _size,
                                       style=wx.ALIGN_RIGHT)
        self.ctrlScrPixHoriz = wx.TextCtrl(parent, -1, "", size=(50, 20))
        wx.EVT_TEXT(self, self.ctrlScrPixHoriz.GetId(),
                    self.onChangeScrPixHoriz)
        self.ctrlScrPixVert = wx.TextCtrl(parent, -1, '', size=(50, 20))
        wx.EVT_TEXT(self, self.ctrlScrPixVert.GetId(),
                    self.onChangeScrPixVert)
        ScrPixelsSizer = wx.BoxSizer(wx.HORIZONTAL)
        ScrPixelsSizer.AddMany([self.ctrlScrPixHoriz, self.ctrlScrPixVert])

        # date
        labelCalibDate = wx.StaticText(parent, -1,
                                       _translate("Calibration Date:"),
                                       style=wx.ALIGN_RIGHT)
        self.ctrlCalibDate = wx.TextCtrl(parent, idCtrlCalibDate, "",
                                         size=(150, 20))
        self.ctrlCalibDate.Disable()
        # notes
        labelCalibNotes = wx.StaticText(parent, -1,
                                        _translate("Notes:"),
                                        style=wx.ALIGN_RIGHT)
        self.ctrlCalibNotes = wx.TextCtrl(parent, idCtrlCalibNotes, "",
                                          size=(150, 150),
                                          style=wx.TE_MULTILINE)
        wx.EVT_TEXT(self, idCtrlCalibNotes, self.onChangeCalibNotes)

        # bits++
        self.ctrlUseBits = wx.CheckBox(parent, -1, _translate('Use Bits++'))
        wx.EVT_CHECKBOX(self, self.ctrlUseBits.GetId(), self.onChangeUseBits)

        infoBoxGrid = wx.FlexGridSizer(cols=2, hgap=6, vgap=6)
        infoBoxGrid.AddMany([
            (1, 10), (1, 10),  # a pair of empty boxes each 1x10pix
            (1, 10), self.ctrlUseBits,
            labelScrDist, self.ctrlScrDist,
            labelScrPixels, ScrPixelsSizer,
            labelScrWidth, self.ctrlScrWidth,
            labelCalibDate, self.ctrlCalibDate
        ])
        infoBoxGrid.Layout()
        infoBoxSizer.Add(infoBoxGrid)
        # put the notes box below the main grid sizer
        infoBoxSizer.Add(labelCalibNotes)
        infoBoxSizer.Add(self.ctrlCalibNotes, 1, wx.EXPAND)
        return infoBoxSizer
Esempio n. 30
0
    def makeCalibBox(self, parent):
        boxLabel = wx.StaticBox(parent, -1, _translate('Calibration'))
        boxLabel.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL))
        calibBox = wx.StaticBoxSizer(boxLabel)

        photometerBox = wx.FlexGridSizer(cols=2, hgap=6, vgap=6)
        # com port entry number
        self.comPortLabel = wx.StaticText(parent, -1, " ", size=(150, 20))
        # photometer button
        # photom type choices should not need localization:
        _choices = list([p.longName for p in hardware.getAllPhotometers()])
        self.ctrlPhotomType = wx.Choice(parent, -1, name="Type:",
                                        choices=_choices)

        _ports = list(hardware.getSerialPorts())
        self._photomChoices = [_translate("Scan all ports")] + _ports
        _size = self.ctrlPhotomType.GetSize() + [0, 5]
        self.ctrlPhotomPort = wx.ComboBox(parent, -1, name="Port:",
                                          value=self._photomChoices[0],
                                          choices=self._photomChoices,
                                          size=_size)

        # wx.EVT_CHOICE(self, self.ctrlPhotomType.GetId(),
        #               self.onChangePhotomType)  # not needed?
        self.btnFindPhotometer = wx.Button(parent, -1,
                                           _translate("Get Photometer"))
        wx.EVT_BUTTON(self, self.btnFindPhotometer.GetId(),
                      self.onBtnFindPhotometer)

        # gamma controls
        self.btnCalibrateGamma = wx.Button(
            parent, -1, _translate("Gamma Calibration..."))
        wx.EVT_BUTTON(self, self.btnCalibrateGamma.GetId(),
                      self.onCalibGammaBtn)
        self.btnTestGamma = wx.Button(
            parent, -1, _translate("Gamma Test..."))
        self.btnTestGamma.Enable(False)

        # color controls
        wx.EVT_BUTTON(self, self.btnTestGamma.GetId(), self.onCalibTestBtn)
        self.btnCalibrateColor = wx.Button(
            parent, -1, _translate("Chromatic Calibration..."))
        self.btnCalibrateColor.Enable(False)
        wx.EVT_BUTTON(self, self.btnCalibrateColor.GetId(),
                      self.onCalibColorBtn)
        self.btnPlotGamma = wx.Button(
            parent, -1, _translate("Plot gamma"))
        wx.EVT_BUTTON(self, self.btnPlotGamma.GetId(), self.plotGamma)
        self.btnPlotSpectra = wx.Button(
            parent, -1, _translate("Plot spectra"))
        wx.EVT_BUTTON(self, self.btnPlotSpectra.GetId(), self.plotSpectra)

        photometerBox.AddMany([self.ctrlPhotomType, self.btnFindPhotometer,
                               self.ctrlPhotomPort, (0, 0),
                               self.comPortLabel, (0, 0),
                               self.btnCalibrateGamma, (0, 0),
                               self.btnTestGamma, self.btnPlotGamma,
                               self.btnCalibrateColor, self.btnPlotSpectra])

        # ----GAMMA------------
        # calibration grid
        gammaBox = wx.StaticBox(parent, -1, _translate('Linearization'))
        gammaBox.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL))
        gammaBoxSizer = wx.StaticBoxSizer(gammaBox, wx.VERTICAL)

        # don't localize the choices
        _choices = ['easy: a+kx^g', 'full: a+(b+kx)^g']
        self.choiceLinearMethod = wx.Choice(parent, -1, name='formula:',
                                            choices=_choices)
        if self.currentMon.getLinearizeMethod() == 4:
            self.choiceLinearMethod.SetSelection(1)
        else:
            self.choiceLinearMethod.SetSelection(0)
        wx.EVT_CHOICE(self, self.choiceLinearMethod.GetId(),
                      self.onChangeLinearMethod)
        gammaBoxSizer.Add(self.choiceLinearMethod, 1, wx.ALL, 2)

        self.gammaGrid = SimpleGrid(parent, id=-1,
                                    cols=['Min', 'Max', 'Gamma',
                                          'a', 'b', 'k'],
                                    rows=['lum', 'R', 'G', 'B'])
        gammaBoxSizer.Add(self.gammaGrid)
        grid.EVT_GRID_CELL_CHANGE(self.gammaGrid, self.onChangeGammaGrid)
        gammaBoxSizer.Layout()

        # LMS grid
        LMSbox = wx.StaticBox(parent, -1, 'LMS->RGB')
        LMSboxSizer = wx.StaticBoxSizer(LMSbox, wx.VERTICAL)
        self.LMSgrid = SimpleGrid(parent, id=-1,
                                  cols=['L', 'M', 'S'],
                                  rows=['R', 'G', 'B'])
        LMSboxSizer.Add(self.LMSgrid)
        LMSboxSizer.Layout()
        grid.EVT_GRID_CELL_CHANGE(self.LMSgrid, self.onChangeLMSgrid)

        # DKL grid
        DKLbox = wx.StaticBox(parent, -1, 'DKL->RGB')
        DKLboxSizer = wx.StaticBoxSizer(DKLbox, wx.VERTICAL)
        self.DKLgrid = SimpleGrid(parent, id=-1,
                                  cols=['Lum', 'L-M', 'L+M-S'],
                                  rows=['R', 'G', 'B'])
        DKLboxSizer.Add(self.DKLgrid)
        DKLboxSizer.Layout()
        grid.EVT_GRID_CELL_CHANGE(self.DKLgrid, self.onChangeDKLgrid)

        calibBoxMainSizer = wx.BoxSizer(wx.VERTICAL)
        calibBoxMainSizer.AddMany([photometerBox,
                                   gammaBoxSizer,
                                   LMSboxSizer,
                                   DKLboxSizer])
        calibBoxMainSizer.Layout()

        if NOTEBOOKSTYLE:
            return calibBoxMainSizer
        else:
            # put the main sizer into a labeled box
            calibBox.Add(calibBoxMainSizer)
            return calibBox