Example #1
0
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.timer = QtCore.QTime()            # timer
        self.calc = CalcCore()
        self.setWindowTitle('rpCalc')
        modPath = os.path.abspath(sys.path[0])
        if modPath.endswith('.zip') or modPath.endswith('.exe'):
            modPath = os.path.dirname(modPath)  # for py2exe/cx_freeze
        iconPathList = [iconPath, os.path.join(modPath, 'icons/'),
                         os.path.join(modPath, '../icons')]
        self.icons = icondict.IconDict()
        self.icons.addIconPath(filter(None, iconPathList))
        self.icons.addIconPath([path for path in iconPathList if path])
        try:
            QtWidgets.QApplication.setWindowIcon(self.icons['calc_lg'])
        except KeyError:
            pass
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.helpView = None
        self.extraView = None
        self.regView = None
        self.histView = None
        self.memView = None
        self.altBaseView = None
        self.optDlg = None
        self.popupMenu = QtWidgets.QMenu(self)
        self.popupMenu.addAction('Registers on &LCD', self.toggleReg)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show &Register List', self.viewReg)
        self.popupMenu.addAction('Show &History List', self.viewHist)
        self.popupMenu.addAction('Show &Memory List', self.viewMem)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Other &Bases', self.viewAltBases)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Help &File', self.help)
        self.popupMenu.addAction('&About rpCalc', self.about)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('&Quit', self.close)
        topLay = QtWidgets.QVBoxLayout(self)
        self.setLayout(topLay)
        topLay.setSpacing(4)
        topLay.setContentsMargins(6,6,6,6)
        lcdBox = LcdBox()
        topLay.addWidget(lcdBox)
        lcdLay = QtWidgets.QGridLayout(lcdBox)
        lcdLay.setColumnStretch(1, 1)
        lcdLay.setRowStretch(3, 1)
        self.extraLabels = [QtWidgets.QLabel(' T:',), QtWidgets.QLabel(' Z:',),
                            QtWidgets.QLabel(' Y:',)]
        for i in range(3):
            lcdLay.addWidget(self.extraLabels[i], i, 0, QtCore.Qt.AlignLeft)
        self.extraLcds = [Lcd(1.5, 13), Lcd(1.5, 13), Lcd(1.5, 13)]
        lcdLay.addWidget(self.extraLcds[2], 0, 1, QtCore.Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[1], 1, 1, QtCore.Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[0], 2, 1, QtCore.Qt.AlignRight)
        if not self.calc.option.boolData('ViewRegisters'):
            for w in self.extraLabels + self.extraLcds:
                w.hide()
        self.lcd = Lcd(2.0, 13)
        lcdLay.addWidget(self.lcd, 3, 0, 1, 2, QtCore.Qt.AlignRight)
        self.setLcdHighlight()
        self.updateLcd()
        self.updateColors()

        self.cmdLay = QtWidgets.QGridLayout()
        topLay.addLayout(self.cmdLay)
        self.cmdDict = {}
        self.addCmdButton('x^2', 0, 0)
        self.addCmdButton('sqRT', 0, 1)
        self.addCmdButton('y^X', 0, 2)
        self.addCmdButton('xRT', 0, 3)
        self.addCmdButton('RCIP', 0, 4)
        self.addCmdButton('SIN', 1, 0)
        self.addCmdButton('COS', 1, 1)
        self.addCmdButton('TAN', 1, 2)
        self.addCmdButton('LN', 1, 3)
        self.addCmdButton('e^X', 1, 4)
        self.addCmdButton('ASIN', 2, 0)
        self.addCmdButton('ACOS', 2, 1)
        self.addCmdButton('ATAN', 2, 2)
        self.addCmdButton('LOG', 2, 3)
        self.addCmdButton('tn^X', 2, 4)
        self.addCmdButton('STO', 3, 0)
        self.addCmdButton('RCL', 3, 1)
        self.addCmdButton('R<', 3, 2)
        self.addCmdButton('R>', 3, 3)
        self.addCmdButton('x<>y', 3, 4)
        self.addCmdButton('SHOW', 4, 0)
        self.addCmdButton('CLR', 4, 1)
        self.addCmdButton('PLCS', 4, 2)
        self.addCmdButton('SCI', 4, 3)
        self.addCmdButton('DEG', 4, 4)
        self.addCmdButton('EXIT', 5, 0)
        self.addCmdButton('Pi', 5, 1)
        self.addCmdButton('EXP', 5, 2)
        self.addCmdButton('CHS', 5, 3)
        self.addCmdButton('<-', 5, 4)

        self.mainLay = QtWidgets.QGridLayout()
        topLay.addLayout(self.mainLay)
        self.mainDict = {}
        self.addMainButton(0, 'OPT', 0, 0)
        self.addMainButton(QtCore.Qt.Key_Slash, '/', 0, 1)
        self.addMainButton(QtCore.Qt.Key_Asterisk, '*', 0, 2)
        self.addMainButton(QtCore.Qt.Key_Minus, '-', 0, 3)
        self.addMainButton(QtCore.Qt.Key_7, '7', 1, 0)
        self.addMainButton(QtCore.Qt.Key_8, '8', 1, 1)
        self.addMainButton(QtCore.Qt.Key_9, '9', 1, 2)
        self.addMainButton(QtCore.Qt.Key_Plus, '+', 1, 3, 1, 0)
        self.addMainButton(QtCore.Qt.Key_4, '4', 2, 0)
        self.addMainButton(QtCore.Qt.Key_5, '5', 2, 1)
        self.addMainButton(QtCore.Qt.Key_6, '6', 2, 2)
        self.addMainButton(QtCore.Qt.Key_1, '1', 3, 0)
        self.addMainButton(QtCore.Qt.Key_2, '2', 3, 1)
        self.addMainButton(QtCore.Qt.Key_3, '3', 3, 2)
        self.addMainButton(QtCore.Qt.Key_Enter, 'ENT', 3, 3, 1, 0)
        self.addMainButton(QtCore.Qt.Key_0, '0', 4, 0, 0, 1)
        self.addMainButton(QtCore.Qt.Key_Period, '.', 4, 2)

        self.mainDict[QtCore.Qt.Key_Return] = \
                     self.mainDict[QtCore.Qt.Key_Enter]
        # added for european keyboards:
        self.mainDict[QtCore.Qt.Key_Comma] = \
                     self.mainDict[QtCore.Qt.Key_Period]
        self.cmdDict['ENT'] = self.mainDict[QtCore.Qt.Key_Enter]
        self.cmdDict['OPT'] = self.mainDict[0]

        self.entryStr = ''
        self.showMode = False

        statusBox = QtWidgets.QFrame()
        statusBox.setFrameStyle(QtWidgets.QFrame.Panel | QtWidgets.QFrame.Sunken)
        statusBox.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                                  QtWidgets.QSizePolicy.Preferred))
        topLay.addWidget(statusBox)
        statusLay = QtWidgets.QHBoxLayout(statusBox)
        self.entryLabel = QtWidgets.QLabel(statusBox)
        statusLay.addWidget(self.entryLabel)
        statusLay.setContentsMargins(1,1,1,1)
        self.statusLabel = QtWidgets.QLabel(statusBox)
        self.statusLabel.setAlignment(QtCore.Qt.AlignRight)
        statusLay.addWidget(self.statusLabel)

        if self.calc.option.boolData('ExtraViewStartup'):
            self.viewReg()
        if self.calc.option.boolData('AltBaseStartup'):
            self.viewAltBases()

        xSize = self.calc.option.intData('MainDlgXSize', 0, 10000)
        ySize = self.calc.option.intData('MainDlgYSize', 0, 10000)
        if xSize and ySize:
            self.resize(xSize, ySize)
        self.move(self.calc.option.intData('MainDlgXPos', 0, 10000),
                  self.calc.option.intData('MainDlgYPos', 0, 10000))

        self.updateEntryLabel('rpCalc Version {0}'.format(__version__))
        QtCore.QTimer.singleShot(5000, self.updateEntryLabel)

        # time predecessor
        self.timePredecessor = 0
        self.timeCounterRunning = False
        self.inOperator = "Mouse"
Example #2
0
class CalcDlg(QtWidgets.QWidget):
    """Main dialog for calculator program.
    """
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.timer = QtCore.QTime()            # timer
        self.calc = CalcCore()
        self.setWindowTitle('rpCalc')
        modPath = os.path.abspath(sys.path[0])
        if modPath.endswith('.zip') or modPath.endswith('.exe'):
            modPath = os.path.dirname(modPath)  # for py2exe/cx_freeze
        iconPathList = [iconPath, os.path.join(modPath, 'icons/'),
                         os.path.join(modPath, '../icons')]
        self.icons = icondict.IconDict()
        self.icons.addIconPath(filter(None, iconPathList))
        self.icons.addIconPath([path for path in iconPathList if path])
        try:
            QtWidgets.QApplication.setWindowIcon(self.icons['calc_lg'])
        except KeyError:
            pass
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.helpView = None
        self.extraView = None
        self.regView = None
        self.histView = None
        self.memView = None
        self.altBaseView = None
        self.optDlg = None
        self.popupMenu = QtWidgets.QMenu(self)
        self.popupMenu.addAction('Registers on &LCD', self.toggleReg)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show &Register List', self.viewReg)
        self.popupMenu.addAction('Show &History List', self.viewHist)
        self.popupMenu.addAction('Show &Memory List', self.viewMem)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Other &Bases', self.viewAltBases)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Help &File', self.help)
        self.popupMenu.addAction('&About rpCalc', self.about)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('&Quit', self.close)
        topLay = QtWidgets.QVBoxLayout(self)
        self.setLayout(topLay)
        topLay.setSpacing(4)
        topLay.setContentsMargins(6,6,6,6)
        lcdBox = LcdBox()
        topLay.addWidget(lcdBox)
        lcdLay = QtWidgets.QGridLayout(lcdBox)
        lcdLay.setColumnStretch(1, 1)
        lcdLay.setRowStretch(3, 1)
        self.extraLabels = [QtWidgets.QLabel(' T:',), QtWidgets.QLabel(' Z:',),
                            QtWidgets.QLabel(' Y:',)]
        for i in range(3):
            lcdLay.addWidget(self.extraLabels[i], i, 0, QtCore.Qt.AlignLeft)
        self.extraLcds = [Lcd(1.5, 13), Lcd(1.5, 13), Lcd(1.5, 13)]
        lcdLay.addWidget(self.extraLcds[2], 0, 1, QtCore.Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[1], 1, 1, QtCore.Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[0], 2, 1, QtCore.Qt.AlignRight)
        if not self.calc.option.boolData('ViewRegisters'):
            for w in self.extraLabels + self.extraLcds:
                w.hide()
        self.lcd = Lcd(2.0, 13)
        lcdLay.addWidget(self.lcd, 3, 0, 1, 2, QtCore.Qt.AlignRight)
        self.setLcdHighlight()
        self.updateLcd()
        self.updateColors()

        self.cmdLay = QtWidgets.QGridLayout()
        topLay.addLayout(self.cmdLay)
        self.cmdDict = {}
        self.addCmdButton('x^2', 0, 0)
        self.addCmdButton('sqRT', 0, 1)
        self.addCmdButton('y^X', 0, 2)
        self.addCmdButton('xRT', 0, 3)
        self.addCmdButton('RCIP', 0, 4)
        self.addCmdButton('SIN', 1, 0)
        self.addCmdButton('COS', 1, 1)
        self.addCmdButton('TAN', 1, 2)
        self.addCmdButton('LN', 1, 3)
        self.addCmdButton('e^X', 1, 4)
        self.addCmdButton('ASIN', 2, 0)
        self.addCmdButton('ACOS', 2, 1)
        self.addCmdButton('ATAN', 2, 2)
        self.addCmdButton('LOG', 2, 3)
        self.addCmdButton('tn^X', 2, 4)
        self.addCmdButton('STO', 3, 0)
        self.addCmdButton('RCL', 3, 1)
        self.addCmdButton('R<', 3, 2)
        self.addCmdButton('R>', 3, 3)
        self.addCmdButton('x<>y', 3, 4)
        self.addCmdButton('SHOW', 4, 0)
        self.addCmdButton('CLR', 4, 1)
        self.addCmdButton('PLCS', 4, 2)
        self.addCmdButton('SCI', 4, 3)
        self.addCmdButton('DEG', 4, 4)
        self.addCmdButton('EXIT', 5, 0)
        self.addCmdButton('Pi', 5, 1)
        self.addCmdButton('EXP', 5, 2)
        self.addCmdButton('CHS', 5, 3)
        self.addCmdButton('<-', 5, 4)

        self.mainLay = QtWidgets.QGridLayout()
        topLay.addLayout(self.mainLay)
        self.mainDict = {}
        self.addMainButton(0, 'OPT', 0, 0)
        self.addMainButton(QtCore.Qt.Key_Slash, '/', 0, 1)
        self.addMainButton(QtCore.Qt.Key_Asterisk, '*', 0, 2)
        self.addMainButton(QtCore.Qt.Key_Minus, '-', 0, 3)
        self.addMainButton(QtCore.Qt.Key_7, '7', 1, 0)
        self.addMainButton(QtCore.Qt.Key_8, '8', 1, 1)
        self.addMainButton(QtCore.Qt.Key_9, '9', 1, 2)
        self.addMainButton(QtCore.Qt.Key_Plus, '+', 1, 3, 1, 0)
        self.addMainButton(QtCore.Qt.Key_4, '4', 2, 0)
        self.addMainButton(QtCore.Qt.Key_5, '5', 2, 1)
        self.addMainButton(QtCore.Qt.Key_6, '6', 2, 2)
        self.addMainButton(QtCore.Qt.Key_1, '1', 3, 0)
        self.addMainButton(QtCore.Qt.Key_2, '2', 3, 1)
        self.addMainButton(QtCore.Qt.Key_3, '3', 3, 2)
        self.addMainButton(QtCore.Qt.Key_Enter, 'ENT', 3, 3, 1, 0)
        self.addMainButton(QtCore.Qt.Key_0, '0', 4, 0, 0, 1)
        self.addMainButton(QtCore.Qt.Key_Period, '.', 4, 2)

        self.mainDict[QtCore.Qt.Key_Return] = \
                     self.mainDict[QtCore.Qt.Key_Enter]
        # added for european keyboards:
        self.mainDict[QtCore.Qt.Key_Comma] = \
                     self.mainDict[QtCore.Qt.Key_Period]
        self.cmdDict['ENT'] = self.mainDict[QtCore.Qt.Key_Enter]
        self.cmdDict['OPT'] = self.mainDict[0]

        self.entryStr = ''
        self.showMode = False

        statusBox = QtWidgets.QFrame()
        statusBox.setFrameStyle(QtWidgets.QFrame.Panel | QtWidgets.QFrame.Sunken)
        statusBox.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                                  QtWidgets.QSizePolicy.Preferred))
        topLay.addWidget(statusBox)
        statusLay = QtWidgets.QHBoxLayout(statusBox)
        self.entryLabel = QtWidgets.QLabel(statusBox)
        statusLay.addWidget(self.entryLabel)
        statusLay.setContentsMargins(1,1,1,1)
        self.statusLabel = QtWidgets.QLabel(statusBox)
        self.statusLabel.setAlignment(QtCore.Qt.AlignRight)
        statusLay.addWidget(self.statusLabel)

        if self.calc.option.boolData('ExtraViewStartup'):
            self.viewReg()
        if self.calc.option.boolData('AltBaseStartup'):
            self.viewAltBases()

        xSize = self.calc.option.intData('MainDlgXSize', 0, 10000)
        ySize = self.calc.option.intData('MainDlgYSize', 0, 10000)
        if xSize and ySize:
            self.resize(xSize, ySize)
        self.move(self.calc.option.intData('MainDlgXPos', 0, 10000),
                  self.calc.option.intData('MainDlgYPos', 0, 10000))

        self.updateEntryLabel('rpCalc Version {0}'.format(__version__))
        QtCore.QTimer.singleShot(5000, self.updateEntryLabel)

        # time predecessor
        self.timePredecessor = 0
        self.timeCounterRunning = False
        self.inOperator = "Mouse"

    def updateEntryLabel(self, subsText=''):
        """Set entry & status label text, use entryStr or subsText, options.
        """
        numFormat = self.calc.option.boolData('ForceSciNotation') and 'sci' \
                    or 'fix'
        decPlcs = self.calc.option.intData('NumDecimalPlaces', 0, 9)
        angle = self.calc.option.strData('AngleUnit')
        self.statusLabel.setText('{0} {1}  {2}'.format(numFormat, decPlcs,
                                                       angle))
        self.entryLabel.setText(subsText or '> {0}'.format(self.entryStr))

    def setOptions(self):
        """Starts option dialog, called by option key.
        """
        oldViewReg = self.calc.option.boolData('ViewRegisters')
        self.optDlg = optiondlg.OptionDlg(self.calc.option, self)
        self.optDlg.startGroupBox('Startup', 8)
        optiondlg.OptionDlgBool(self.optDlg, 'SaveStacks',
                                'Save previous entries')
        optiondlg.OptionDlgBool(self.optDlg, 'ExtraViewStartup',
                                'Auto open extra data view')
        optiondlg.OptionDlgBool(self.optDlg, 'AltBaseStartup',
                                'Auto open alternate base view')
        self.optDlg.startGroupBox('Display', 8)
        optiondlg.OptionDlgInt(self.optDlg, 'NumDecimalPlaces',
                               'Number of decimal places', 0, 9)
        optiondlg.OptionDlgBool(self.optDlg, 'ThousandsSeparator',
                                'Separate thousands with spaces')
        optiondlg.OptionDlgBool(self.optDlg, 'ForceSciNotation',
                                'Always show exponent')
        optiondlg.OptionDlgBool(self.optDlg, 'UseEngNotation',
                                'Use engineering notation')
        optiondlg.OptionDlgBool(self.optDlg, 'TrimExponents',
                                'Hide exponent leading zeros')
        optiondlg.OptionDlgBool(self.optDlg, 'ViewRegisters',
                                'View Registers on LCD')
        optiondlg.OptionDlgBool(self.optDlg, 'HideLcdHighlight',
                                'Hide LCD highlight')
        self.optDlg.startNewColumn()
        optiondlg.OptionDlgRadio(self.optDlg, 'AngleUnit', 'Angular Units',
                                 [('deg', 'Degrees'), ('rad', 'Radians')])
        self.optDlg.startGroupBox('Alternate Bases')
        optiondlg.OptionDlgInt(self.optDlg, 'AltBaseBits', 'Size limit',
                               CalcCore.minNumBits, CalcCore.maxNumBits,
                               True, 4, False, ' bits')
        optiondlg.OptionDlgBool(self.optDlg, 'UseTwosComplement',
                                'Use two\'s complement\nnegative numbers')
        self.optDlg.startGroupBox('Extra Views',)
        optiondlg.OptionDlgPush(self.optDlg, 'View Extra Data', self.viewExtra)
        optiondlg.OptionDlgPush(self.optDlg, 'View Other Bases',
                                self.viewAltBases)
        optiondlg.OptionDlgPush(self.optDlg, 'View Help file', self.help)
        optiondlg.OptionDlgInt(self.optDlg, 'MaxHistLength',
                               'Saved history steps', CalcCore.minMaxHist,
                               CalcCore.maxMaxHist, True, 10)
        if self.optDlg.exec_() == QtWidgets.QDialog.Accepted:
            self.calc.option.writeChanges()
            newViewReg = self.calc.option.boolData('ViewRegisters')
            if newViewReg != oldViewReg:
                if newViewReg:
                    for w in self.extraLabels + self.extraLcds:
                        w.show()
                else:
                    for w in self.extraLabels + self.extraLcds:
                        w.hide()
                QtGui.qApp.processEvents()
                self.adjustSize()
            if self.altBaseView:
                self.altBaseView.updateOptions()
            self.setLcdHighlight()
            self.calc.updateXStr()
        self.optDlg = None

    def setLcdHighlight(self):
        """Set lcd highlight based on option.
        """
        opt = self.calc.option.boolData('HideLcdHighlight') and \
              QtWidgets.QLCDNumber.Flat or QtWidgets.QLCDNumber.Filled
        self.lcd.setSegmentStyle(opt)
        for lcd in self.extraLcds:
            lcd.setSegmentStyle(opt)

    def updateColors(self):
        """Adjust the colors to the current option settings.
        """
        if self.calc.option.boolData('UseDefaultColors'):
            return
        pal = QtWidgets.QApplication.palette()
        background = QtGui.QColor(self.calc.option.intData('BackgroundR',
                                                           0, 255),
                                  self.calc.option.intData('BackgroundG',
                                                           0, 255),
                                  self.calc.option.intData('BackgroundB',
                                                           0, 255))
        foreground = QtGui.QColor(self.calc.option.intData('ForegroundR',
                                                           0, 255),
                                  self.calc.option.intData('ForegroundG',
                                                           0, 255),
                                  self.calc.option.intData('ForegroundB',
                                                           0, 255))
        pal.setColor(QtGui.QPalette.Base, background)
        pal.setColor(QtGui.QPalette.Text, foreground)
        QtWidgets.QApplication.setPalette(pal)

    def viewExtra(self, defaultTab=0):
        """Show extra data view.
        """
        if self.optDlg:
            self.optDlg.reject()   # unfortunately necessary?
        if not self.extraView:
            self.extraView = extradisplay.ExtraDisplay(self)
        self.extraView.tabUpdate(defaultTab)
        self.extraView.tab.setCurrentIndex(defaultTab)
        self.extraView.show()

    def viewReg(self):
        """Show extra data view with register tab open.
        """
        self.viewExtra(0)

    def viewHist(self):
        """Show extra data view with history tab open.
        """
        self.viewExtra(1)

    def viewMem(self):
        """Show extra data view with memory tab open.
        """
        self.viewExtra(2)

    def updateExtra(self):
        """Update current extra and alt base views.
        """
        if self.extraView and self.extraView.isVisible():
            self.extraView.updateData()
        if self.altBaseView:
            self.altBaseView.updateData()

    def toggleReg(self):
        """Toggle register display on LCD.
        """
        viewReg = not self.calc.option.boolData('ViewRegisters')
        self.calc.option.changeData('ViewRegisters',
                                    viewReg and 'yes' or 'no', 1)
        if viewReg:
            for w in self.extraLabels + self.extraLcds:
                w.show()
        else:
            for w in self.extraLabels + self.extraLcds:
                w.hide()
        self.adjustSize()
        self.calc.updateXStr()

    def viewAltBases(self):
        """Show alternate base view.
        """
        if self.optDlg:
            self.optDlg.reject()   # unfortunately necessary?
        if not self.altBaseView:
            self.altBaseView = altbasedialog.AltBaseDialog(self)
        self.altBaseView.updateData()
        self.altBaseView.show()

    def findHelpFile(self):
        """Return the path to the help file.
        """
        modPath = os.path.abspath(sys.path[0])
        if modPath.endswith('.zip') or modPath.endswith('.exe'):
            modPath = os.path.dirname(modPath)  # for py2exe/cx_freeze
        pathList = [helpFilePath, os.path.join(modPath, '../doc/'),
                    modPath, 'doc/']
        for path in pathList:
            if path:
                try:
                    fullPath = os.path.join(path, 'README.html')
                    with open(fullPath, 'r', encoding='utf-8') as f:
                        pass
                    return fullPath
                except IOError:
                    pass
        return ''

    def help(self):
        """View the ReadMe file.
        """
        if self.optDlg:
            self.optDlg.reject()   # unfortunately necessary?
        if not self.helpView:
            path = self.findHelpFile()
            if not path:
                QtWidgets.QMessageBox.warning(self, 'rpCalc',
                                          'Read Me file not found')
                return
            self.helpView = helpview.HelpView(path, 'rpCalc README File',
                                              self.icons, self)
        self.helpView.show()

    def about(self):
        """About this program.
        """
        QtWidgets.QMessageBox.about(self, 'rpCalc',
                                'rpCalc, Version {0}\n by {1}'.
                                format(__version__, __author__))

    def addCmdButton(self, text, row, col):
        """Adds a CalcButton for command functions.
        """
        button = CalcButton(text)
        self.cmdDict[text.upper()] = button
        self.cmdLay.addWidget(button, row, col)
        button.activated.connect(self.issueCmd)

    def addMainButton(self, key, text, row, col, extraRow=0, extraCol=0):
        """Adds a CalcButton for number and 4-function keys.
        """
        button = CalcButton(text)
        self.mainDict[key] = button
        self.mainLay.addWidget(button, row, col, 1+extraRow, 1+extraCol)
        button.activated.connect(self.issueCmd)

    def updateLcd(self):
        """Sets display back to CalcCore string.
        """
        numDigits = int(self.calc.option.numData('NumDecimalPlaces', 0, 9)) + 9
        if self.calc.option.boolData('ThousandsSeparator') or \
                self.calc.option.boolData('UseEngNotation'):
            numDigits += 2
        self.lcd.setDisplay(self.calc.xStr, numDigits)
        if self.calc.option.boolData('ViewRegisters'):
            nums = [self.calc.formatNum(num) for num in self.calc.stack[1:]]
            for num, lcd in zip(nums, self.extraLcds):
                lcd.setDisplay(num, numDigits)
        self.updateExtra()

    def issueCmd(self, text):
        """Sends command text to CalcCore - connected to button signals.
        """
        # starts timer with the first button press or Keystroke
        if self.timeCounterRunning is False:
            self.timer.start()
            self.timeCounterRunning = True
        if self.inOperator is "Mouse":
            # P (Pointing) here
            self.timeCounter(self.inOperator)
        else:
            # K (Keystroke) here
            self.timeCounter(self.inOperator)
            self.inOperator = "Mouse"
        mode = self.calc.flag
        text = str(text).upper()
        if text == 'OPT':
            self.setOptions()
        elif text == 'SHOW':
            if not self.showMode:
                valueStr = self.calc.sciFormatX(11).replace('e', ' E', 1)
                self.lcd.setNumDigits(19)
                self.lcd.display(valueStr)
                self.showMode = True
                return
        elif text == 'EXIT':
            self.close()
            return
        else:
            self.calc.cmd(text)
        if text in ('SCI', 'DEG', 'OPT') or mode == Mode.decPlcMode:
            self.updateEntryLabel()
        self.showMode = False
        self.updateLcd()

    def textEntry(self, ch):
        """Searches for button match from text entry.
        """
        if not ch:
            return False
        if ord(ch) == 8:   # backspace key
            self.entryStr = self.entryStr[:-1]
        elif ord(ch) == 27:  # escape key
            self.entryStr = ''
        elif ch == '\t':     # tab key
            cmds = [key for key in self.cmdDict.keys() if
                    key.startswith(self.entryStr.upper())]
            if len(cmds) == 1:
                button = self.cmdDict[cmds[0]]
                button.clickEvent()
                button.tmpDown(300)
                self.entryStr = ''
            else:
                QtWidgets.QApplication.beep()
        elif ch == ':' and not self.entryStr:
            self.entryStr = ':'   # optional command prefix
        else:
            newStr = (self.entryStr + ch).upper()
            if newStr == ':Q':    # vim-like shortcut
                newStr = 'EXIT'
            button = self.cmdDict.get(newStr.lstrip(':'))
            if button:
                button.clickEvent()
                button.tmpDown(300)
                self.entryStr = ''
            else:
                if [key for key in self.cmdDict.keys() if
                    key.startswith(newStr.lstrip(':'))]:
                    self.entryStr += ch
                else:
                    QtWidgets.QApplication.beep()
                    return False
        self.updateEntryLabel()
        return True

    def timeCounter(self, inputOperator):
        # calculates the time between two inputs (Mouse or Keyboard) in ms
        elapsedTime = self.timer.elapsed()  # to ashure that always same elapsed time gets used
        keystrokeTime = elapsedTime - self.timePredecessor
        self.timePredecessor = elapsedTime
        print(inputOperator, keystrokeTime)

    def keyPressEvent(self, keyEvent):
        """Event handler for keys - checks for numbers and typed commands.
        """
        # Input is Keyboard
        self.inOperator = "Keyboard"
        button = self.mainDict.get(keyEvent.key())
        if not self.entryStr and button:
            button.clickEvent()
            button.setDown(True)
            return
        letter = str(keyEvent.text()).upper()
        if keyEvent.modifiers() == QtCore.Qt.AltModifier:
            if self.altBaseView and self.altBaseView.isVisible():
                if letter in ('X', 'O', 'B', 'D'):
                    self.altBaseView.setCodedBase(letter, False)
                elif letter == 'V':
                    self.altBaseView.copyValue()
                elif letter == 'C':
                    self.altBaseView.close()
        elif not self.entryStr and self.calc.base == 16 and \
                 'A' <= letter <= 'F':
            self.issueCmd(keyEvent.text())
        elif self.altBaseView and self.altBaseView.isVisible() and \
                (self.calc.xStr == ' 0' or \
                 (self.calc.stack[0] == 0.0 and self.calc.base != 10)) and \
                self.calc.flag == Mode.entryMode and \
                letter in ('X', 'O', 'B', 'D'):
            self.altBaseView.setCodedBase(letter, True)
        elif not self.entryStr and keyEvent.key() == QtCore.Qt.Key_Backspace:
            button = self.cmdDict['<-']
            button.clickEvent()
            button.tmpDown(300)
        elif not self.entryStr and keyEvent.key() == QtCore.Qt.Key_Escape:
            self.popupMenu.popup(self.mapToGlobal(QtCore.QPoint(0, 0)))
        elif not self.textEntry(str(keyEvent.text())):
            QtWidgets.QWidget.keyPressEvent(self, keyEvent)

    def keyReleaseEvent(self, keyEvent):
        """Event handler for keys - sets button back to raised position.
        """
        button = self.mainDict.get(keyEvent.key())
        if not self.entryStr and button:
            button.setDown(False)

    def closeEvent(self, event):
        """Saves the stack prior to closing.
        """
        self.calc.saveStack()
        self.calc.option.changeData('MainDlgXSize', self.width(), True)
        self.calc.option.changeData('MainDlgYSize', self.height(), True)
        self.calc.option.changeData('MainDlgXPos', self.x(), True)
        self.calc.option.changeData('MainDlgYPos', self.y(), True)
        if self.extraView:
            self.calc.option.cself.timeCounterRunninghangeData('ExtraViewXSize',
                                        self.extraView.width(), True)
            self.calc.option.changeData('ExtraViewYSize',
                                        self.extraView.height(), True)
            self.calc.option.changeData('ExtraViewXPos',
                                        self.extraView.x(), True)
            self.calc.option.changeData('ExtraViewYPos',
                                        self.extraView.y(), True)
        if self.altBaseView:
            self.calc.option.changeData('AltBaseXPos',
                                        self.altBaseView.x(), True)
            self.calc.option.changeData('AltBaseYPos',
                                        self.altBaseView.y(), True)
        self.calc.option.writeChanges()
        QtWidgets.QWidget.closeEvent(self, event)
Example #3
0
class CalcDlg(QWidget):
    """Main dialog for calculator program.
    """
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.calc = CalcCore()
        self.setWindowTitle('rpCalc')
        modPath = os.path.abspath(sys.path[0])
        if modPath.endswith('.zip') or modPath.endswith('.exe'):
            modPath = os.path.dirname(modPath)  # for py2exe/cx_freeze
        iconPathList = [iconPath, os.path.join(modPath, 'icons/'),
                         os.path.join(modPath, '../icons')]
        self.icons = icondict.IconDict()
        self.icons.addIconPath(filter(None, iconPathList))
        self.icons.addIconPath([path for path in iconPathList if path])
        try:
            QApplication.setWindowIcon(self.icons['calc_lg'])
        except KeyError:
            pass
        self.setFocusPolicy(Qt.StrongFocus)
        self.helpView = None
        self.extraView = None
        self.regView = None
        self.histView = None
        self.memView = None
        self.altBaseView = None
        self.optDlg = None
        self.popupMenu = QMenu(self)
        self.popupMenu.addAction('Registers on &LCD', self.toggleReg)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show &Register List', self.viewReg)
        self.popupMenu.addAction('Show &History List', self.viewHist)
        self.popupMenu.addAction('Show &Memory List', self.viewMem)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Other &Bases', self.viewAltBases)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Help &File', self.help)
        self.popupMenu.addAction('&About rpCalc', self.about)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('&Quit', self.close)
        topLay = QVBoxLayout(self)
        self.setLayout(topLay)
        topLay.setSpacing(4)
        topLay.setContentsMargins(6, 6, 6, 6)
        lcdBox = LcdBox()
        topLay.addWidget(lcdBox)
        lcdLay = QGridLayout(lcdBox)
        lcdLay.setColumnStretch(1, 1)
        lcdLay.setRowStretch(3, 1)
        self.extraLabels = [QLabel(' T:',), QLabel(' Z:',),
                            QLabel(' Y:',)]
        for i in range(3):
            lcdLay.addWidget(self.extraLabels[i], i, 0, Qt.AlignLeft)
        self.extraLcds = [Lcd(1.5, 13), Lcd(1.5, 13), Lcd(1.5, 13)]
        lcdLay.addWidget(self.extraLcds[2], 0, 1, Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[1], 1, 1, Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[0], 2, 1, Qt.AlignRight)
        if not self.calc.option.boolData('ViewRegisters'):
            for w in self.extraLabels + self.extraLcds:
                w.hide()
        self.lcd = Lcd(2.0, 13)
        lcdLay.addWidget(self.lcd, 3, 0, 1, 2, Qt.AlignRight)
        self.setLcdHighlight()
        self.updateLcd()
        self.updateColors()

        self.cmdLay = QGridLayout()
        topLay.addLayout(self.cmdLay)
        self.cmdDict = {}
        self.addCmdButton('x^2', 0, 0)
        self.addCmdButton('sqRT', 0, 1)
        self.addCmdButton('y^X', 0, 2)
        self.addCmdButton('xRT', 0, 3)
        self.addCmdButton('RCIP', 0, 4)
        self.addCmdButton('SIN', 1, 0)
        self.addCmdButton('COS', 1, 1)
        self.addCmdButton('TAN', 1, 2)
        self.addCmdButton('LN', 1, 3)
        self.addCmdButton('e^X', 1, 4)
        self.addCmdButton('ASIN', 2, 0)
        self.addCmdButton('ACOS', 2, 1)
        self.addCmdButton('ATAN', 2, 2)
        self.addCmdButton('LOG', 2, 3)
        self.addCmdButton('tn^X', 2, 4)
        self.addCmdButton('STO', 3, 0)
        self.addCmdButton('RCL', 3, 1)
        self.addCmdButton('R<', 3, 2)
        self.addCmdButton('R>', 3, 3)
        self.addCmdButton('x<>y', 3, 4)
        self.addCmdButton('SHOW', 4, 0)
        self.addCmdButton('CLR', 4, 1)
        self.addCmdButton('PLCS', 4, 2)
        self.addCmdButton('SCI', 4, 3)
        self.addCmdButton('DEG', 4, 4)
        self.addCmdButton('EXIT', 5, 0)
        self.addCmdButton('Pi', 5, 1)
        self.addCmdButton('EXP', 5, 2)
        self.addCmdButton('CHS', 5, 3)
        self.addCmdButton('<-', 5, 4)

        self.mainLay = QGridLayout()
        topLay.addLayout(self.mainLay)
        self.mainDict = {}
        self.addMainButton(0, 'OPT', 0, 0)
        self.addMainButton(Qt.Key_Slash, '/', 0, 1)
        self.addMainButton(Qt.Key_Asterisk, '*', 0, 2)
        self.addMainButton(Qt.Key_Minus, '-', 0, 3)
        self.addMainButton(Qt.Key_7, '7', 1, 0)
        self.addMainButton(Qt.Key_8, '8', 1, 1)
        self.addMainButton(Qt.Key_9, '9', 1, 2)
        self.addMainButton(Qt.Key_Plus, '+', 1, 3, 1, 0)
        self.addMainButton(Qt.Key_4, '4', 2, 0)
        self.addMainButton(Qt.Key_5, '5', 2, 1)
        self.addMainButton(Qt.Key_6, '6', 2, 2)
        self.addMainButton(Qt.Key_1, '1', 3, 0)
        self.addMainButton(Qt.Key_2, '2', 3, 1)
        self.addMainButton(Qt.Key_3, '3', 3, 2)
        self.addMainButton(Qt.Key_Enter, 'ENT', 3, 3, 1, 0)
        self.addMainButton(Qt.Key_0, '0', 4, 0, 0, 1)
        self.addMainButton(Qt.Key_Period, '.', 4, 2)

        self.mainDict[Qt.Key_Return] = \
                     self.mainDict[Qt.Key_Enter]
        # added for european keyboards:
        self.mainDict[Qt.Key_Comma] = \
                     self.mainDict[Qt.Key_Period]
        self.cmdDict['ENT'] = self.mainDict[Qt.Key_Enter]
        self.cmdDict['OPT'] = self.mainDict[0]

        self.entryStr = ''
        self.showMode = False

        statusBox = QFrame()
        statusBox.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        statusBox.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,
                                                  QSizePolicy.Preferred))
        topLay.addWidget(statusBox)
        statusLay = QHBoxLayout(statusBox)
        self.entryLabel = QLabel(statusBox)
        statusLay.addWidget(self.entryLabel)
        statusLay.setContentsMargins(1, 1, 1, 1)
        self.statusLabel = QLabel(statusBox)
        self.statusLabel.setAlignment(Qt.AlignRight)
        statusLay.addWidget(self.statusLabel)

        if self.calc.option.boolData('ExtraViewStartup'):
            self.viewReg()
        if self.calc.option.boolData('AltBaseStartup'):
            self.viewAltBases()

        xSize = self.calc.option.intData('MainDlgXSize', 0, 10000)
        ySize = self.calc.option.intData('MainDlgYSize', 0, 10000)
        if xSize and ySize:
            self.resize(xSize, ySize)
        self.move(self.calc.option.intData('MainDlgXPos', 0, 10000),
                  self.calc.option.intData('MainDlgYPos', 0, 10000))

        self.updateEntryLabel('rpCalc Version {0}'.format(__version__))
        QTimer.singleShot(5000, self.updateEntryLabel)

    def updateEntryLabel(self, subsText=''):
        """Set entry & status label text, use entryStr or subsText, options.
        """
        numFormat = self.calc.option.boolData('ForceSciNotation') and 'sci' \
                    or 'fix'
        decPlcs = self.calc.option.intData('NumDecimalPlaces', 0, 9)
        angle = self.calc.option.strData('AngleUnit')
        self.statusLabel.setText('{0} {1}  {2}'.format(numFormat, decPlcs,
                                                       angle))
        self.entryLabel.setText(subsText or '> {0}'.format(self.entryStr))

    def setOptions(self):
        """Starts option dialog, called by option key.
        """
        oldViewReg = self.calc.option.boolData('ViewRegisters')
        self.optDlg = optiondlg.OptionDlg(self.calc.option, self)
        self.optDlg.startGroupBox('Startup', 8)
        optiondlg.OptionDlgBool(self.optDlg, 'SaveStacks',
                                'Save previous entries')
        optiondlg.OptionDlgBool(self.optDlg, 'ExtraViewStartup',
                                'Auto open extra data view')
        optiondlg.OptionDlgBool(self.optDlg, 'AltBaseStartup',
                                'Auto open alternate base view')
        self.optDlg.startGroupBox('Display', 8)
        optiondlg.OptionDlgInt(self.optDlg, 'NumDecimalPlaces',
                               'Number of decimal places', 0, 9)
        optiondlg.OptionDlgBool(self.optDlg, 'ThousandsSeparator',
                                'Separate thousands with spaces')
        optiondlg.OptionDlgBool(self.optDlg, 'ForceSciNotation',
                                'Always show exponent')
        optiondlg.OptionDlgBool(self.optDlg, 'UseEngNotation',
                                'Use engineering notation')
        optiondlg.OptionDlgBool(self.optDlg, 'TrimExponents',
                                'Hide exponent leading zeros')
        optiondlg.OptionDlgBool(self.optDlg, 'ViewRegisters',
                                'View Registers on LCD')
        optiondlg.OptionDlgBool(self.optDlg, 'HideLcdHighlight',
                                'Hide LCD highlight')
        self.optDlg.startNewColumn()
        optiondlg.OptionDlgRadio(self.optDlg, 'AngleUnit', 'Angular Units',
                                 [('deg', 'Degrees'), ('rad', 'Radians')])
        self.optDlg.startGroupBox('Alternate Bases')
        optiondlg.OptionDlgInt(self.optDlg, 'AltBaseBits', 'Size limit',
                               CalcCore.minNumBits, CalcCore.maxNumBits,
                               True, 4, False, ' bits')
        optiondlg.OptionDlgBool(self.optDlg, 'UseTwosComplement',
                                'Use two\'s complement\nnegative numbers')
        self.optDlg.startGroupBox('Extra Views',)
        optiondlg.OptionDlgPush(self.optDlg, 'View Extra Data', self.viewExtra)
        optiondlg.OptionDlgPush(self.optDlg, 'View Other Bases',
                                self.viewAltBases)
        optiondlg.OptionDlgPush(self.optDlg, 'View Help file', self.help)
        optiondlg.OptionDlgInt(self.optDlg, 'MaxHistLength',
                               'Saved history steps', CalcCore.minMaxHist,
                               CalcCore.maxMaxHist, True, 10)
        if self.optDlg.exec_() == QDialog.Accepted:
            self.calc.option.writeChanges()
            newViewReg = self.calc.option.boolData('ViewRegisters')
            if newViewReg != oldViewReg:
                if newViewReg:
                    for w in self.extraLabels + self.extraLcds:
                        w.show()
                else:
                    for w in self.extraLabels + self.extraLcds:
                        w.hide()
                qApp.processEvents()
                self.adjustSize()
            if self.altBaseView:
                self.altBaseView.updateOptions()
            self.setLcdHighlight()
            self.calc.updateXStr()
        self.optDlg = None

    def setLcdHighlight(self):
        """Set lcd highlight based on option.
        """
        opt = self.calc.option.boolData('HideLcdHighlight') and \
              QLCDNumber.Flat or QLCDNumber.Filled
        self.lcd.setSegmentStyle(opt)
        for lcd in self.extraLcds:
            lcd.setSegmentStyle(opt)

    def updateColors(self):
        """Adjust the colors to the current option settings.
        """
        if self.calc.option.boolData('UseDefaultColors'):
            return
        pal = QApplication.palette()
        background = QColor(self.calc.option.intData('BackgroundR',
                                                           0, 255),
                                  self.calc.option.intData('BackgroundG',
                                                           0, 255),
                                  self.calc.option.intData('BackgroundB',
                                                           0, 255))
        foreground = QColor(self.calc.option.intData('ForegroundR',
                                                           0, 255),
                                  self.calc.option.intData('ForegroundG',
                                                           0, 255),
                                  self.calc.option.intData('ForegroundB',
                                                           0, 255))
        pal.setColor(QPalette.Base, background)
        pal.setColor(QPalette.Text, foreground)
        QApplication.setPalette(pal)

    def viewExtra(self, defaultTab=0):
        """Show extra data view.
        """
        if self.optDlg:
            self.optDlg.reject()   # unfortunately necessary?
        if not self.extraView:
            self.extraView = extradisplay.ExtraDisplay(self)
        self.extraView.tabUpdate(defaultTab)
        self.extraView.tab.setCurrentIndex(defaultTab)
        self.extraView.show()

    def viewReg(self):
        """Show extra data view with register tab open.
        """
        self.viewExtra(0)

    def viewHist(self):
        """Show extra data view with history tab open.
        """
        self.viewExtra(1)

    def viewMem(self):
        """Show extra data view with memory tab open.
        """
        self.viewExtra(2)

    def updateExtra(self):
        """Update current extra and alt base views.
        """
        if self.extraView and self.extraView.isVisible():
            self.extraView.updateData()
        if self.altBaseView:
            self.altBaseView.updateData()

    def toggleReg(self):
        """Toggle register display on LCD.
        """
        viewReg = not self.calc.option.boolData('ViewRegisters')
        self.calc.option.changeData('ViewRegisters',
                                    viewReg and 'yes' or 'no', 1)
        if viewReg:
            for w in self.extraLabels + self.extraLcds:
                w.show()
        else:
            for w in self.extraLabels + self.extraLcds:
                w.hide()
        self.adjustSize()
        self.calc.updateXStr()

    def viewAltBases(self):
        """Show alternate base view.
        """
        if self.optDlg:
            self.optDlg.reject()   # unfortunately necessary?
        if not self.altBaseView:
            self.altBaseView = altbasedialog.AltBaseDialog(self)
        self.altBaseView.updateData()
        self.altBaseView.show()

    def findHelpFile(self):
        """Return the path to the help file.
        """
        modPath = os.path.abspath(sys.path[0])
        if modPath.endswith('.zip') or modPath.endswith('.exe'):
            modPath = os.path.dirname(modPath)  # for py2exe/cx_freeze
        pathList = [helpFilePath, os.path.join(modPath, '../doc/'),
                    modPath, 'doc/']
        for path in pathList:
            if path:
                try:
                    fullPath = os.path.join(path, 'README.html')
                    with open(fullPath, 'r', encoding='utf-8') as f:
                        pass
                    return fullPath
                except IOError:
                    pass
        return ''

    def help(self):
        """View the ReadMe file.
        """
        if self.optDlg:
            self.optDlg.reject()   # unfortunately necessary?
        if not self.helpView:
            path = self.findHelpFile()
            if not path:
                QMessageBox.warning(self, 'rpCalc',
                                          'Read Me file not found')
                return
            self.helpView = helpview.HelpView(path, 'rpCalc README File',
                                              self.icons, self)
        self.helpView.show()

    def about(self):
        """About this program.
        """
        QMessageBox.about(self, 'rpCalc',
                                'rpCalc, Version {0}\n by {1}'.
                                format(__version__, __author__))

    def addCmdButton(self, text, row, col):
        """Adds a CalcButton for command functions.
        """
        button = CalcButton(text)
        self.cmdDict[text.upper()] = button
        self.cmdLay.addWidget(button, row, col)
        button.activated.connect(self.issueCmd)

    def addMainButton(self, key, text, row, col, extraRow=0, extraCol=0):
        """Adds a CalcButton for number and 4-function keys.
        """
        button = CalcButton(text)
        self.mainDict[key] = button
        self.mainLay.addWidget(button, row, col, 1+extraRow, 1+extraCol)
        button.activated.connect(self.issueCmd)

    def updateLcd(self):
        """Sets display back to CalcCore string.
        """
        numDigits = int(self.calc.option.numData('NumDecimalPlaces', 0, 9)) + 9
        if self.calc.option.boolData('ThousandsSeparator') or \
                self.calc.option.boolData('UseEngNotation'):
            numDigits += 2
        self.lcd.setDisplay(self.calc.xStr, numDigits)
        if self.calc.option.boolData('ViewRegisters'):
            nums = [self.calc.formatNum(num) for num in self.calc.stack[1:]]
            for num, lcd in zip(nums, self.extraLcds):
                lcd.setDisplay(num, numDigits)
        self.updateExtra()

    def issueCmd(self, text):
        """Sends command text to CalcCore - connected to button signals.
        """
        mode = self.calc.flag
        text = str(text).upper()
        if text == 'OPT':
            self.setOptions()
        elif text == 'SHOW':
            if not self.showMode:
                valueStr = self.calc.sciFormatX(11).replace('e', ' E', 1)
                self.lcd.setNumDigits(19)
                self.lcd.display(valueStr)
                self.showMode = True
                return
        elif text == 'EXIT':
            self.close()
            return
        else:
            self.calc.cmd(text)
        if text in ('SCI', 'DEG', 'OPT') or mode == Mode.decPlcMode:
            self.updateEntryLabel()
        self.showMode = False
        self.updateLcd()

    def textEntry(self, ch):
        """Searches for button match from text entry.
        """
        if not ch:
            return False
        if ord(ch) == 8:   # backspace key
            self.entryStr = self.entryStr[:-1]
        elif ord(ch) == 27:  # escape key
            self.entryStr = ''
        elif ch == '\t':     # tab key
            cmds = [key for key in self.cmdDict.keys() if
                    key.startswith(self.entryStr.upper())]
            if len(cmds) == 1:
                button = self.cmdDict[cmds[0]]
                button.clickEvent()
                button.tmpDown(300)
                self.entryStr = ''
            else:
                QApplication.beep()
        elif ch == ':' and not self.entryStr:
            self.entryStr = ':'   # optional command prefix
        else:
            newStr = (self.entryStr + ch).upper()
            if newStr == ':Q':    # vim-like shortcut
                newStr = 'EXIT'
            button = self.cmdDict.get(newStr.lstrip(':'))
            if button:
                button.clickEvent()
                button.tmpDown(300)
                self.entryStr = ''
            else:
                if [key for key in self.cmdDict.keys() if
                    key.startswith(newStr.lstrip(':'))]:
                    self.entryStr += ch
                else:
                    QApplication.beep()
                    return False
        self.updateEntryLabel()
        return True

    def keyPressEvent(self, keyEvent):
        """Event handler for keys - checks for numbers and typed commands.
        """
        button = self.mainDict.get(keyEvent.key())
        if not self.entryStr and button:
            button.clickEvent()
            button.setDown(True)
            return
        letter = str(keyEvent.text()).upper()
        if keyEvent.modifiers() == Qt.AltModifier:
            if self.altBaseView and self.altBaseView.isVisible():
                if letter in ('X', 'O', 'B', 'D'):
                    self.altBaseView.setCodedBase(letter, False)
                elif letter == 'V':
                    self.altBaseView.copyValue()
                elif letter == 'C':
                    self.altBaseView.close()
        elif not self.entryStr and self.calc.base == 16 and \
                 'A' <= letter <= 'F':
            self.issueCmd(keyEvent.text())
        elif self.altBaseView and self.altBaseView.isVisible() and \
                (self.calc.xStr == ' 0' or \
                 (self.calc.stack[0] == 0.0 and self.calc.base != 10)) and \
                self.calc.flag == Mode.entryMode and \
                letter in ('X', 'O', 'B', 'D'):
            self.altBaseView.setCodedBase(letter, True)
        elif not self.entryStr and keyEvent.key() == Qt.Key_Backspace:
            button = self.cmdDict['<-']
            button.clickEvent()
            button.tmpDown(300)
        elif not self.entryStr and keyEvent.key() == Qt.Key_Escape:
            self.popupMenu.popup(self.mapToGlobal(QPoint(0, 0)))
        elif not self.textEntry(str(keyEvent.text())):
            QWidget.keyPressEvent(self, keyEvent)

    def keyReleaseEvent(self, keyEvent):
        """Event handler for keys - sets button back to raised position.
        """
        button = self.mainDict.get(keyEvent.key())
        if not self.entryStr and button:
            button.setDown(False)

    def closeEvent(self, event):
        """Saves the stack prior to closing.
        """
        self.calc.saveStack()
        self.calc.option.changeData('MainDlgXSize', self.width(), True)
        self.calc.option.changeData('MainDlgYSize', self.height(), True)
        self.calc.option.changeData('MainDlgXPos', self.x(), True)
        self.calc.option.changeData('MainDlgYPos', self.y(), True)
        if self.extraView:
            self.calc.option.changeData('ExtraViewXSize',
                                        self.extraView.width(), True)
            self.calc.option.changeData('ExtraViewYSize',
                                        self.extraView.height(), True)
            self.calc.option.changeData('ExtraViewXPos',
                                        self.extraView.x(), True)
            self.calc.option.changeData('ExtraViewYPos',
                                        self.extraView.y(), True)
        if self.altBaseView:
            self.calc.option.changeData('AltBaseXPos',
                                        self.altBaseView.x(), True)
            self.calc.option.changeData('AltBaseYPos',
                                        self.altBaseView.y(), True)
        self.calc.option.writeChanges()
        QWidget.closeEvent(self, event)
Example #4
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.calc = CalcCore()
        self.setWindowTitle('rpCalc')
        modPath = os.path.abspath(sys.path[0])
        if modPath.endswith('.zip') or modPath.endswith('.exe'):
            modPath = os.path.dirname(modPath)  # for py2exe/cx_freeze
        iconPathList = [iconPath, os.path.join(modPath, 'icons/'),
                         os.path.join(modPath, '../icons')]
        self.icons = icondict.IconDict()
        self.icons.addIconPath(filter(None, iconPathList))
        self.icons.addIconPath([path for path in iconPathList if path])
        try:
            QApplication.setWindowIcon(self.icons['calc_lg'])
        except KeyError:
            pass
        self.setFocusPolicy(Qt.StrongFocus)
        self.helpView = None
        self.extraView = None
        self.regView = None
        self.histView = None
        self.memView = None
        self.altBaseView = None
        self.optDlg = None
        self.popupMenu = QMenu(self)
        self.popupMenu.addAction('Registers on &LCD', self.toggleReg)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show &Register List', self.viewReg)
        self.popupMenu.addAction('Show &History List', self.viewHist)
        self.popupMenu.addAction('Show &Memory List', self.viewMem)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Other &Bases', self.viewAltBases)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Help &File', self.help)
        self.popupMenu.addAction('&About rpCalc', self.about)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('&Quit', self.close)
        topLay = QVBoxLayout(self)
        self.setLayout(topLay)
        topLay.setSpacing(4)
        topLay.setContentsMargins(6, 6, 6, 6)
        lcdBox = LcdBox()
        topLay.addWidget(lcdBox)
        lcdLay = QGridLayout(lcdBox)
        lcdLay.setColumnStretch(1, 1)
        lcdLay.setRowStretch(3, 1)
        self.extraLabels = [QLabel(' T:',), QLabel(' Z:',),
                            QLabel(' Y:',)]
        for i in range(3):
            lcdLay.addWidget(self.extraLabels[i], i, 0, Qt.AlignLeft)
        self.extraLcds = [Lcd(1.5, 13), Lcd(1.5, 13), Lcd(1.5, 13)]
        lcdLay.addWidget(self.extraLcds[2], 0, 1, Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[1], 1, 1, Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[0], 2, 1, Qt.AlignRight)
        if not self.calc.option.boolData('ViewRegisters'):
            for w in self.extraLabels + self.extraLcds:
                w.hide()
        self.lcd = Lcd(2.0, 13)
        lcdLay.addWidget(self.lcd, 3, 0, 1, 2, Qt.AlignRight)
        self.setLcdHighlight()
        self.updateLcd()
        self.updateColors()

        self.cmdLay = QGridLayout()
        topLay.addLayout(self.cmdLay)
        self.cmdDict = {}
        self.addCmdButton('x^2', 0, 0)
        self.addCmdButton('sqRT', 0, 1)
        self.addCmdButton('y^X', 0, 2)
        self.addCmdButton('xRT', 0, 3)
        self.addCmdButton('RCIP', 0, 4)
        self.addCmdButton('SIN', 1, 0)
        self.addCmdButton('COS', 1, 1)
        self.addCmdButton('TAN', 1, 2)
        self.addCmdButton('LN', 1, 3)
        self.addCmdButton('e^X', 1, 4)
        self.addCmdButton('ASIN', 2, 0)
        self.addCmdButton('ACOS', 2, 1)
        self.addCmdButton('ATAN', 2, 2)
        self.addCmdButton('LOG', 2, 3)
        self.addCmdButton('tn^X', 2, 4)
        self.addCmdButton('STO', 3, 0)
        self.addCmdButton('RCL', 3, 1)
        self.addCmdButton('R<', 3, 2)
        self.addCmdButton('R>', 3, 3)
        self.addCmdButton('x<>y', 3, 4)
        self.addCmdButton('SHOW', 4, 0)
        self.addCmdButton('CLR', 4, 1)
        self.addCmdButton('PLCS', 4, 2)
        self.addCmdButton('SCI', 4, 3)
        self.addCmdButton('DEG', 4, 4)
        self.addCmdButton('EXIT', 5, 0)
        self.addCmdButton('Pi', 5, 1)
        self.addCmdButton('EXP', 5, 2)
        self.addCmdButton('CHS', 5, 3)
        self.addCmdButton('<-', 5, 4)

        self.mainLay = QGridLayout()
        topLay.addLayout(self.mainLay)
        self.mainDict = {}
        self.addMainButton(0, 'OPT', 0, 0)
        self.addMainButton(Qt.Key_Slash, '/', 0, 1)
        self.addMainButton(Qt.Key_Asterisk, '*', 0, 2)
        self.addMainButton(Qt.Key_Minus, '-', 0, 3)
        self.addMainButton(Qt.Key_7, '7', 1, 0)
        self.addMainButton(Qt.Key_8, '8', 1, 1)
        self.addMainButton(Qt.Key_9, '9', 1, 2)
        self.addMainButton(Qt.Key_Plus, '+', 1, 3, 1, 0)
        self.addMainButton(Qt.Key_4, '4', 2, 0)
        self.addMainButton(Qt.Key_5, '5', 2, 1)
        self.addMainButton(Qt.Key_6, '6', 2, 2)
        self.addMainButton(Qt.Key_1, '1', 3, 0)
        self.addMainButton(Qt.Key_2, '2', 3, 1)
        self.addMainButton(Qt.Key_3, '3', 3, 2)
        self.addMainButton(Qt.Key_Enter, 'ENT', 3, 3, 1, 0)
        self.addMainButton(Qt.Key_0, '0', 4, 0, 0, 1)
        self.addMainButton(Qt.Key_Period, '.', 4, 2)

        self.mainDict[Qt.Key_Return] = \
                     self.mainDict[Qt.Key_Enter]
        # added for european keyboards:
        self.mainDict[Qt.Key_Comma] = \
                     self.mainDict[Qt.Key_Period]
        self.cmdDict['ENT'] = self.mainDict[Qt.Key_Enter]
        self.cmdDict['OPT'] = self.mainDict[0]

        self.entryStr = ''
        self.showMode = False

        statusBox = QFrame()
        statusBox.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        statusBox.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,
                                                  QSizePolicy.Preferred))
        topLay.addWidget(statusBox)
        statusLay = QHBoxLayout(statusBox)
        self.entryLabel = QLabel(statusBox)
        statusLay.addWidget(self.entryLabel)
        statusLay.setContentsMargins(1, 1, 1, 1)
        self.statusLabel = QLabel(statusBox)
        self.statusLabel.setAlignment(Qt.AlignRight)
        statusLay.addWidget(self.statusLabel)

        if self.calc.option.boolData('ExtraViewStartup'):
            self.viewReg()
        if self.calc.option.boolData('AltBaseStartup'):
            self.viewAltBases()

        xSize = self.calc.option.intData('MainDlgXSize', 0, 10000)
        ySize = self.calc.option.intData('MainDlgYSize', 0, 10000)
        if xSize and ySize:
            self.resize(xSize, ySize)
        self.move(self.calc.option.intData('MainDlgXPos', 0, 10000),
                  self.calc.option.intData('MainDlgYPos', 0, 10000))

        self.updateEntryLabel('rpCalc Version {0}'.format(__version__))
        QTimer.singleShot(5000, self.updateEntryLabel)
Example #5
0
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.calc = CalcCore()
        self.setWindowTitle('rpCalc')
        icons.setupIcons()
        self.setWindowIcon(icons.iconDict['calc'])
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.helpView = None
        self.extraView = None
        self.regView = None
        self.histView = None
        self.memView = None
        self.altBaseView = None
        self.optDlg = None
        self.popupMenu = QtGui.QMenu(self)
        self.popupMenu.addAction('Registers on &LCD', self.toggleReg)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show &Register List', self.viewReg)
        self.popupMenu.addAction('Show &History List', self.viewHist)
        self.popupMenu.addAction('Show &Memory List', self.viewMem)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show Other &Bases', self.viewAltBases)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('Show ReadMe &File', self.help)
        self.popupMenu.addAction('&About rpCalc', self.about)
        self.popupMenu.addSeparator()
        self.popupMenu.addAction('&Quit', self.close)
        topLay = QtGui.QVBoxLayout(self)
        self.setLayout(topLay)
        topLay.setSpacing(4)
        topLay.setMargin(6)
        lcdBox = LcdBox()
        topLay.addWidget(lcdBox)
        lcdLay = QtGui.QGridLayout(lcdBox)
        lcdLay.setColumnStretch(1, 1)
        lcdLay.setRowStretch(3, 1)
        self.extraLabels = [QtGui.QLabel(' T:',), QtGui.QLabel(' Z:',),
                            QtGui.QLabel(' Y:',)]
        for i in range(3):
            lcdLay.addWidget(self.extraLabels[i], i, 0, QtCore.Qt.AlignLeft)
        self.extraLcds = [Lcd(1.5, 13), Lcd(1.5, 13), Lcd(1.5, 13)]
        lcdLay.addWidget(self.extraLcds[2], 0, 1, QtCore.Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[1], 1, 1, QtCore.Qt.AlignRight)
        lcdLay.addWidget(self.extraLcds[0], 2, 1, QtCore.Qt.AlignRight)
        if not self.calc.option.boolData('ViewRegisters'):
            for w in self.extraLabels + self.extraLcds:
                w.hide()
        self.lcd = Lcd(2.0, 13)
        lcdLay.addWidget(self.lcd, 3, 0, 1, 2, QtCore.Qt.AlignRight)
        self.setLcdHighlight()
        self.updateLcd()
        self.updateColors()

        self.cmdLay = QtGui.QGridLayout()
        topLay.addLayout(self.cmdLay)
        self.cmdDict = {}
        self.addCmdButton('x^2', 0, 0)
        self.addCmdButton('sqRT', 0, 1)
        self.addCmdButton('y^X', 0, 2)
        self.addCmdButton('xRT', 0, 3)
        self.addCmdButton('RCIP', 0, 4)
        self.addCmdButton('SIN', 1, 0)
        self.addCmdButton('COS', 1, 1)
        self.addCmdButton('TAN', 1, 2)
        self.addCmdButton('LN', 1, 3)
        self.addCmdButton('e^X', 1, 4)
        self.addCmdButton('ASIN', 2, 0)
        self.addCmdButton('ACOS', 2, 1)
        self.addCmdButton('ATAN', 2, 2)
        self.addCmdButton('LOG', 2, 3)
        self.addCmdButton('tn^X', 2, 4)
        self.addCmdButton('STO', 3, 0)
        self.addCmdButton('RCL', 3, 1)
        self.addCmdButton('R<', 3, 2)
        self.addCmdButton('R>', 3, 3)
        self.addCmdButton('x<>y', 3, 4)
        self.addCmdButton('SHOW', 4, 0)
        self.addCmdButton('CLR', 4, 1)
        self.addCmdButton('PLCS', 4, 2)
        self.addCmdButton('SCI', 4, 3)
        self.addCmdButton('DEG', 4, 4)
        self.addCmdButton('EXIT', 5, 0)
        self.addCmdButton('Pi', 5, 1)
        self.addCmdButton('EXP', 5, 2)
        self.addCmdButton('CHS', 5, 3)
        self.addCmdButton('<-', 5, 4)

        self.mainLay = QtGui.QGridLayout()
        topLay.addLayout(self.mainLay)
        self.mainDict = {}
        self.addMainButton(0, 'OPT', 0, 0)
        self.addMainButton(QtCore.Qt.Key_Slash, '/', 0, 1)
        self.addMainButton(QtCore.Qt.Key_Asterisk, '*', 0, 2)
        self.addMainButton(QtCore.Qt.Key_Minus, '-', 0, 3)
        self.addMainButton(QtCore.Qt.Key_7, '7', 1, 0)
        self.addMainButton(QtCore.Qt.Key_8, '8', 1, 1)
        self.addMainButton(QtCore.Qt.Key_9, '9', 1, 2)
        self.addMainButton(QtCore.Qt.Key_Plus, '+', 1, 3, 1, 0)
        self.addMainButton(QtCore.Qt.Key_4, '4', 2, 0)
        self.addMainButton(QtCore.Qt.Key_5, '5', 2, 1)
        self.addMainButton(QtCore.Qt.Key_6, '6', 2, 2)
        self.addMainButton(QtCore.Qt.Key_1, '1', 3, 0)
        self.addMainButton(QtCore.Qt.Key_2, '2', 3, 1)
        self.addMainButton(QtCore.Qt.Key_3, '3', 3, 2)
        self.addMainButton(QtCore.Qt.Key_Enter, 'ENT', 3, 3, 1, 0)
        self.addMainButton(QtCore.Qt.Key_0, '0', 4, 0, 0, 1)
        self.addMainButton(QtCore.Qt.Key_Period, '.', 4, 2)

        self.mainDict[QtCore.Qt.Key_Return] = \
                     self.mainDict[QtCore.Qt.Key_Enter]
        # added for european keyboards:
        self.mainDict[QtCore.Qt.Key_Comma] = \
                     self.mainDict[QtCore.Qt.Key_Period]
        self.cmdDict['ENT'] = self.mainDict[QtCore.Qt.Key_Enter]
        self.cmdDict['OPT'] = self.mainDict[0]

        self.entryStr = ''
        self.showMode = False

        statusBox = QtGui.QFrame()
        statusBox.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken)
        statusBox.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred,
                                                  QtGui.QSizePolicy.Preferred))
        topLay.addWidget(statusBox)
        statusLay = QtGui.QHBoxLayout(statusBox)
        self.entryLabel = QtGui.QLabel(statusBox)
        statusLay.addWidget(self.entryLabel)
        statusLay.setMargin(1)
        self.statusLabel = QtGui.QLabel(statusBox)
        self.statusLabel.setAlignment(QtCore.Qt.AlignRight)
        statusLay.addWidget(self.statusLabel)

        if self.calc.option.boolData('ExtraViewStartup'):
            self.viewReg()
        if self.calc.option.boolData('AltBaseStartup'):
            self.viewAltBases()

        xSize = self.calc.option.intData('MainDlgXSize', 0, 10000)
        ySize = self.calc.option.intData('MainDlgYSize', 0, 10000)
        if xSize and ySize:
            self.resize(xSize, ySize)
        self.move(self.calc.option.intData('MainDlgXPos', 0, 10000),
                  self.calc.option.intData('MainDlgYPos', 0, 10000))

        self.updateEntryLabel('rpCalc Version %s' % __version__)
        QtCore.QTimer.singleShot(5000, self.updateEntryLabel)