662 lines
24 KiB
Python
662 lines
24 KiB
Python
#!/usr/bin/env python3
|
|
import math
|
|
import sys
|
|
|
|
from qtpy.QtCore import Qt
|
|
from qtpy.QtWidgets import (QApplication, QGridLayout, QLayout, QLineEdit,
|
|
QSizePolicy, QPushButton, QDialog, QDialogButtonBox, QMenu, QAction,
|
|
QVBoxLayout, QToolButton, QLabel)
|
|
from qtpy.QtGui import QDoubleValidator
|
|
from qtpy.QtGui import QIcon
|
|
from qtpy import QtCore
|
|
from qtvcp.core import Status, Info
|
|
STATUS = Status()
|
|
INFO = Info()
|
|
|
|
# TODO: this needs to handle internationalization since much of the world uses
|
|
# commas instead of periods for decimal points.
|
|
|
|
|
|
class CalculatorLineEdit(QLineEdit):
|
|
operatorKeyPressed = QtCore.Signal(str)
|
|
digitKeyPressed = QtCore.Signal(str)
|
|
fieldKeyPressed = QtCore.Signal(str)
|
|
cancelKeyPressed = QtCore.Signal()
|
|
|
|
def __init__(self, parent=None):
|
|
super(CalculatorLineEdit, self).__init__(parent)
|
|
self.setMaxLength(15)
|
|
self.setAlignment(Qt.AlignRight)
|
|
|
|
# set up a validator so the input text can only be a number
|
|
validator = QDoubleValidator()
|
|
# StandardNotation disables scientific notation like 10e-5, which could be left incompleted
|
|
# before submitting (e.g. "10e" would be invalid and cause an error)
|
|
validator.setNotation(QDoubleValidator.StandardNotation)
|
|
self.setValidator(validator)
|
|
|
|
def keyPressEvent(self, event):
|
|
# The digit and decimal keys emit a digitKeyPressed signal
|
|
|
|
if (event.key() >= Qt.Key_0 and event.key() <= Qt.Key_9) or event.key() == Qt.Key_Period:
|
|
self.digitKeyPressed.emit(str(event.text()))
|
|
|
|
# these keys are absorbed and not sent to QLineEdit but a signal is emitted
|
|
# special keys:
|
|
# ALT+Left - move to previous field
|
|
# ALT+Right - move to next field
|
|
# ALT+Backspace - cancel
|
|
key_map = {
|
|
Qt.Key_Minus: lambda: self.operatorKeyPressed.emit('-'),
|
|
Qt.Key_Plus: lambda: self.operatorKeyPressed.emit('+'),
|
|
Qt.Key_Asterisk: lambda: self.operatorKeyPressed.emit('*'),
|
|
Qt.Key_Slash: lambda: self.operatorKeyPressed.emit('/'),
|
|
Qt.Key_Equal: lambda: self.operatorKeyPressed.emit('='),
|
|
(Qt.Key_Right, Qt.AltModifier): lambda: self.fieldKeyPressed.emit('next'),
|
|
(Qt.Key_Left, Qt.AltModifier): lambda: self.fieldKeyPressed.emit('previous'),
|
|
(Qt.Key_Backspace, Qt.AltModifier): self.cancelKeyPressed.emit
|
|
}
|
|
|
|
key = event.key()
|
|
modifiers = event.modifiers()
|
|
|
|
if (key, modifiers) in key_map:
|
|
key_map[(key, modifiers)]()
|
|
elif key in key_map:
|
|
key_map[key]()
|
|
else:
|
|
# the fallthrough sends everything else to QLineEdit
|
|
return super(CalculatorLineEdit, self).keyPressEvent(event)
|
|
|
|
class Calculator(QDialog):
|
|
NumDigitButtons = 10
|
|
def __init__(self, parent=None):
|
|
super(Calculator, self).__init__(parent)
|
|
|
|
try:
|
|
self.PREFS_ = self.QTVCP_INSTANCE_.PREFS_
|
|
self.PREF_SECTION = 'CALCULATOR'
|
|
except:
|
|
self.PREFS_ = None
|
|
|
|
self.pendingAdditiveOperator = ''
|
|
self.pendingMultiplicativeOperator = ''
|
|
|
|
self.sumInMemory = 0.0
|
|
self.sumSoFar = 0.0
|
|
self.factorSoFar = 0.0
|
|
self.waitingForOperand = True
|
|
|
|
self.display = CalculatorLineEdit('0')
|
|
self.display.setMinimumHeight(30)
|
|
self.display.setAlignment(Qt.AlignRight)
|
|
self.display.setMaxLength(15)
|
|
|
|
self.display.textEdited.connect(self.displayTextEdited)
|
|
self.display.textChanged.connect(self.displayTextChanged)
|
|
|
|
self.pendingLabel = QLabel()
|
|
self.pendingLabel.setAlignment(Qt.AlignRight)
|
|
|
|
self.memoryLabel = QLabel()
|
|
self.memoryLabel.setAlignment(Qt.AlignRight)
|
|
self.updateMemLabel()
|
|
|
|
self.display.digitKeyPressed.connect(self.physDigitPressed)
|
|
self.display.operatorKeyPressed.connect(self.physOperatorPressed)
|
|
self.display.fieldKeyPressed.connect(self.physFieldKeyPressed)
|
|
self.display.cancelKeyPressed.connect(self.physCancelKeyPressed)
|
|
self.digitButtons = []
|
|
for i in range(Calculator.NumDigitButtons):
|
|
self.digitButtons.append(self.createButton(str(i),
|
|
self.digitClicked))
|
|
|
|
self.pointButton = self.createButton(".", self.pointClicked)
|
|
self.changeSignButton = self.createButton(str("\N{PLUS-MINUS SIGN}"), self.changeSignClicked)
|
|
self.axisButton = self.createAxisButton("AXIS X", self.axisClicked)
|
|
self.backspaceButton = self.createButton("BKSP",self.backspaceClicked, 'Backspace')
|
|
self.clearButton = self.createButton("CLR", self.clear)
|
|
self.clearAllButton = self.createButton("CLR ALL", self.clearAll)
|
|
self.clearMemoryButton = self.createButton("MC", self.clearMemory, 'Clear memory')
|
|
self.readMemoryButton = self.createButton("MR", self.readMemory, 'Read memory')
|
|
self.setMemoryButton = self.createButton("MS", self.setMemory, 'Set memory')
|
|
self.addToMemoryButton = self.createButton("M+", self.addToMemory, 'Add to memory')
|
|
|
|
self.divisionButton = self.createButton(str("\N{DIVISION SIGN}"),
|
|
self.multiplicativeOperatorClicked)
|
|
self.timesButton = self.createButton(str("\N{MULTIPLICATION SIGN}"), self.multiplicativeOperatorClicked)
|
|
self.minusButton = self.createButton("-", self.additiveOperatorClicked)
|
|
self.plusButton = self.createButton("+", self.additiveOperatorClicked)
|
|
|
|
self.squareRootButton = self.createButton("SQRT", self.unaryOperatorClicked)
|
|
self.powerButton = self.createButton(str("x\N{SUPERSCRIPT TWO}"), self.unaryOperatorClicked)
|
|
self.reciprocalButton = self.createButton("1/x", self.unaryOperatorClicked)
|
|
self.equalButton = self.createButton("=", self.equalClicked)
|
|
|
|
self.to_mm_btn = self.createButton('-> MM', self.convertClicked, 'Convert inch to mm')
|
|
self.to_mm_btn.setProperty('convert', 'to_mm')
|
|
self.to_inch_btn = self.createButton('-> INCH', self.convertClicked, 'Convert mm to inch')
|
|
self.to_inch_btn.setProperty('convert', 'to_inch')
|
|
self.tpi_btn = self.createButton('25.4/X', self.convertClicked, 'Convert metric pitch to TPI or TPI to metric pitch')
|
|
self.tpi_btn.setProperty('convert', '25.4/X')
|
|
|
|
mainLayout = QGridLayout()
|
|
mainLayout.setSizeConstraint(QLayout.SetFixedSize)
|
|
|
|
mainLayout.addWidget(self.backspaceButton, 2, 0, 1, 1)
|
|
mainLayout.addWidget(self.axisButton, 2, 1, 1, 2)
|
|
mainLayout.addWidget(self.clearButton, 2, 3, 1, 1)
|
|
mainLayout.addWidget(self.clearAllButton, 2, 4, 1, 2)
|
|
mainLayout.addWidget(self.clearMemoryButton, 3, 0)
|
|
mainLayout.addWidget(self.readMemoryButton, 4, 0)
|
|
mainLayout.addWidget(self.setMemoryButton, 5, 0)
|
|
mainLayout.addWidget(self.addToMemoryButton, 6, 0)
|
|
|
|
for i in range(1, Calculator.NumDigitButtons):
|
|
row = ((9 - i) // 3) + 2
|
|
column = ((i - 1) % 3) + 1
|
|
mainLayout.addWidget(self.digitButtons[i], row + 1, column)
|
|
|
|
mainLayout.addWidget(self.digitButtons[0], 6, 1)
|
|
mainLayout.addWidget(self.pointButton, 6, 2)
|
|
mainLayout.addWidget(self.changeSignButton, 6, 3)
|
|
|
|
mainLayout.addWidget(self.divisionButton, 3, 4)
|
|
mainLayout.addWidget(self.timesButton, 4, 4)
|
|
mainLayout.addWidget(self.minusButton, 5, 4)
|
|
mainLayout.addWidget(self.plusButton, 6, 4)
|
|
|
|
mainLayout.addWidget(self.squareRootButton, 3, 5)
|
|
mainLayout.addWidget(self.powerButton, 4, 5)
|
|
mainLayout.addWidget(self.reciprocalButton, 5, 5)
|
|
mainLayout.addWidget(self.equalButton, 6, 5)
|
|
|
|
mainLayout.addWidget(self.to_mm_btn, 7, 0)
|
|
mainLayout.addWidget(self.to_inch_btn, 7, 1)
|
|
mainLayout.addWidget(self.tpi_btn, 7, 2)
|
|
if self.PREFS_:
|
|
constValues = self.PREFS_.getpref('constValuesList', 'None', str, self.PREF_SECTION)
|
|
if constValues != 'None':
|
|
self.constButtons = []
|
|
constValues = ''.join(constValues.split())
|
|
for value in constValues.split(',')[:6]:
|
|
constButton = QPushButton(value)
|
|
constButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
|
constButton.setFocusPolicy(Qt.NoFocus)
|
|
constButton.clicked.connect(self.constClicked)
|
|
mainLayout.addWidget(constButton, len(self.constButtons) + 2, 6)
|
|
self.constButtons.append(constButton)
|
|
|
|
mainLayout.addWidget(self.display, 0, 1, 1, mainLayout.columnCount())
|
|
mainLayout.addWidget(self.pendingLabel, 0, 0)
|
|
mainLayout.addWidget(self.memoryLabel, 1, 1, 1, mainLayout.columnCount()-1)
|
|
|
|
self.backButton = QPushButton('Back')
|
|
self.backButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
|
self.backButton.setFocusPolicy(Qt.NoFocus)
|
|
self.backButton.clicked.connect(self.backActionWrapper)
|
|
|
|
self.nextButton = QPushButton('Next')
|
|
self.nextButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
|
self.nextButton.setFocusPolicy(Qt.NoFocus)
|
|
self.nextButton.clicked.connect(self.nextActionWrapper)
|
|
self.applyNextButton = QPushButton('Apply\nNext')
|
|
self.applyNextButton.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
|
self.applyNextButton.clicked.connect(self.applyActionWrapper)
|
|
self.applyNextButton.setVisible(False)
|
|
|
|
self.bBox = QDialogButtonBox()
|
|
|
|
cancelButton = self.bBox.addButton(QDialogButtonBox.StandardButton.Cancel)
|
|
cancelButton.setFocusPolicy(Qt.NoFocus)
|
|
applyButton = self.bBox.addButton(QDialogButtonBox.StandardButton.Apply)
|
|
applyButton.setFocusPolicy(Qt.NoFocus)
|
|
self.bBox.addButton(self.backButton, QDialogButtonBox.ActionRole)
|
|
self.bBox.addButton(self.nextButton, QDialogButtonBox.ActionRole)
|
|
self.bBox.addButton(self.applyNextButton, QDialogButtonBox.ActionRole)
|
|
self.bBox.rejected.connect(self.reject)
|
|
self.bBox.accepted.connect(self.accept)
|
|
|
|
applyButton.clicked.connect(self.accept)
|
|
|
|
self.display.returnPressed.connect(self.physReturnPressed)
|
|
calc_layout = QVBoxLayout()
|
|
calc_layout.addLayout(mainLayout)
|
|
calc_layout.addWidget(self.bBox)
|
|
self.setLayout(calc_layout)
|
|
|
|
for button in self.bBox.buttons():
|
|
if button.text() == 'Cancel' or button.text() == 'Apply':
|
|
button.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
|
|
|
self.setWindowTitle("Calculator")
|
|
if not INFO.LINUXCNC_IS_RUNNING:
|
|
self.axisButton.setEnabled(False)
|
|
STATUS.connect('all-homed', lambda w: self.axisButton.setEnabled(True))
|
|
STATUS.connect('not-all-homed', lambda w, data: self.axisButton.setEnabled(False))
|
|
|
|
if self.PREFS_:
|
|
self.behaviorOnShow = self.PREFS_.getpref('onShowBehavior', 'None', str, self.PREF_SECTION)
|
|
else:
|
|
self.behaviorOnShow = 'None'
|
|
|
|
def showEvent(self, event):
|
|
if self.behaviorOnShow != 'None':
|
|
if 'CLEAR_ALL' in self.behaviorOnShow.upper():
|
|
self.clearAll()
|
|
if 'FORCE_FOCUS' in self.behaviorOnShow.upper():
|
|
self.display.setFocus()
|
|
|
|
def displayTextEdited(self):
|
|
# this only triggers on user changes
|
|
if self.display.text() == '':
|
|
self.display.setText('0')
|
|
|
|
def displayTextChanged(self):
|
|
# this triggers on both user and programmatic changes
|
|
self.display.setStyleSheet("QLineEdit { }")
|
|
|
|
def physCancelKeyPressed(self):
|
|
self.reject()
|
|
|
|
def physFieldKeyPressed(self, field):
|
|
if field == 'next' and self.nextButton.isVisible():
|
|
self.nextButton.animateClick()
|
|
elif field == 'previous' and self.backButton.isVisible():
|
|
self.backButton.animateClick()
|
|
|
|
def physReturnPressed(self):
|
|
if not self.waitingForOperand:
|
|
self.equalClicked()
|
|
elif self.PREFS_ and self.PREFS_.getpref('acceptOnReturnKey', False, bool, self.PREF_SECTION):
|
|
if self.applyNextButton.isVisible():
|
|
self.applyNextButton.animateClick()
|
|
else:
|
|
self.accept()
|
|
|
|
def physDigitPressed(self, digit):
|
|
if self.display.text() == '0' and digit != '0':
|
|
self.display.clear()
|
|
|
|
if self.waitingForOperand:
|
|
self.display.clear()
|
|
self.waitingForOperand = False
|
|
|
|
|
|
def physOperatorPressed(self, operator):
|
|
if operator == '+':
|
|
self.plusButton.animateClick()
|
|
elif operator == '-':
|
|
if self.pendingAdditiveOperator != '-':
|
|
self.minusButton.animateClick()
|
|
else:
|
|
self.changeSignButton.animateClick()
|
|
self.pendingAdditiveOperator = ''
|
|
self.waitingForOperand = True
|
|
self.pendingLabel.clear()
|
|
elif operator == '*':
|
|
self.timesButton.animateClick()
|
|
elif operator == '/':
|
|
self.divisionButton.animateClick()
|
|
elif operator == '=':
|
|
self.equalButton.animateClick()
|
|
|
|
|
|
def digitClicked(self):
|
|
clickedButton = self.sender()
|
|
digitValue = int(clickedButton.text())
|
|
|
|
if self.display.text() == '0' and digitValue == 0.0:
|
|
return
|
|
|
|
if self.waitingForOperand:
|
|
self.display.clear()
|
|
self.waitingForOperand = False
|
|
|
|
self.display.setText(self.display.text() + str(digitValue))
|
|
self.display.setFocus()
|
|
|
|
def unaryOperatorClicked(self):
|
|
clickedButton = self.sender()
|
|
clickedOperator = clickedButton.text()
|
|
operand = float(self.display.text())
|
|
if clickedOperator == "SQRT":
|
|
if operand < 0.0:
|
|
self.abortOperation()
|
|
return
|
|
result = math.sqrt(operand)
|
|
elif clickedOperator == str("x\N{SUPERSCRIPT TWO}"):
|
|
result = math.pow(operand, 2.0)
|
|
elif clickedOperator == "1/x":
|
|
if operand == 0.0:
|
|
self.abortOperation()
|
|
return
|
|
|
|
result = 1.0 / operand
|
|
|
|
self.display.setText(str(result))
|
|
self.display.setFocus()
|
|
self.waitingForOperand = True
|
|
|
|
def additiveOperatorClicked(self):
|
|
clickedButton = self.sender()
|
|
clickedOperator = clickedButton.text()
|
|
operand = float(self.display.text())
|
|
|
|
if self.pendingMultiplicativeOperator:
|
|
if not self.calculate(operand, self.pendingMultiplicativeOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.display.setText(str(self.factorSoFar))
|
|
operand = self.factorSoFar
|
|
self.factorSoFar = 0.0
|
|
self.pendingMultiplicativeOperator = ''
|
|
|
|
if self.pendingAdditiveOperator and not self.waitingForOperand:
|
|
if not self.calculate(operand, self.pendingAdditiveOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.display.setText(str(self.sumSoFar))
|
|
else:
|
|
self.sumSoFar = operand
|
|
|
|
self.pendingAdditiveOperator = clickedOperator
|
|
self.waitingForOperand = True
|
|
self.pendingLabel.setText(clickedOperator)
|
|
self.display.setFocus()
|
|
|
|
def multiplicativeOperatorClicked(self):
|
|
clickedButton = self.sender()
|
|
clickedOperator = clickedButton.text()
|
|
operand = float(self.display.text())
|
|
|
|
if self.pendingMultiplicativeOperator and not self.waitingForOperand:
|
|
if not self.calculate(operand, self.pendingMultiplicativeOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.display.setText(str(self.factorSoFar))
|
|
else:
|
|
self.factorSoFar = operand
|
|
|
|
self.pendingMultiplicativeOperator = clickedOperator
|
|
self.waitingForOperand = True
|
|
self.pendingLabel.setText(clickedOperator)
|
|
self.display.setFocus()
|
|
|
|
def equalClicked(self):
|
|
operand = float(self.display.text())
|
|
|
|
if self.pendingMultiplicativeOperator:
|
|
if not self.calculate(operand, self.pendingMultiplicativeOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
operand = self.factorSoFar
|
|
self.factorSoFar = 0.0
|
|
self.pendingMultiplicativeOperator = ''
|
|
|
|
if self.pendingAdditiveOperator:
|
|
if not self.calculate(operand, self.pendingAdditiveOperator):
|
|
self.abortOperation()
|
|
return
|
|
|
|
self.pendingAdditiveOperator = ''
|
|
else:
|
|
self.sumSoFar = operand
|
|
|
|
self.display.setText(str(self.sumSoFar))
|
|
self.sumSoFar = 0.0
|
|
self.waitingForOperand = True
|
|
self.pendingLabel.clear()
|
|
self.display.setFocus()
|
|
|
|
def pointClicked(self):
|
|
if self.waitingForOperand:
|
|
self.display.setText('0')
|
|
|
|
if "." not in self.display.text():
|
|
self.display.setText(self.display.text() + ".")
|
|
|
|
self.waitingForOperand = False
|
|
self.display.setFocus()
|
|
|
|
def changeSignClicked(self):
|
|
text = self.display.text()
|
|
value = float(text)
|
|
|
|
if value > 0.0:
|
|
text = "-" + text
|
|
elif value < 0.0:
|
|
text = text[1:]
|
|
|
|
self.display.setText(text)
|
|
self.display.setFocus()
|
|
|
|
def axisClicked(self):
|
|
conversion = {'X':0, 'Y':1, "Z":2, 'A':3, "B":4, "C":5, 'U':6, 'V':7, 'W':8}
|
|
digitValue = 0.0
|
|
try:
|
|
p,relp,dtg = STATUS.get_position()
|
|
text = self.axisButton.text()
|
|
for let in INFO.AVAILABLE_AXES:
|
|
if let == text[-1]:
|
|
digitValue = round(relp[conversion[let]],5)
|
|
text = text.replace('%s'%let,'%s'%digitValue)
|
|
break
|
|
except Exception as e:
|
|
print(e)
|
|
return
|
|
|
|
if self.display.text() == '0' and digitValue == 0.0:
|
|
return
|
|
|
|
if self.waitingForOperand:
|
|
self.display.clear()
|
|
self.waitingForOperand = False
|
|
self.display.setText(str(digitValue))
|
|
self.display.setFocus()
|
|
|
|
def axisTriggered(self, data):
|
|
self.axisButton.setText('Axis {}'.format(data))
|
|
self.display.setFocus()
|
|
|
|
def backspaceClicked(self):
|
|
if self.waitingForOperand:
|
|
return
|
|
|
|
text = self.display.text()[:-1]
|
|
if not text:
|
|
text = '0'
|
|
self.waitingForOperand = True
|
|
|
|
self.display.setFocus()
|
|
self.display.setText(text)
|
|
|
|
def convertClicked(self):
|
|
clickedOperator = self.sender().property('convert')
|
|
operand = float(self.display.text())
|
|
|
|
if clickedOperator == "to_mm":
|
|
result = operand * 25.4
|
|
elif clickedOperator == "to_inch":
|
|
if operand == 0:
|
|
result = 0
|
|
else:
|
|
result = operand / 25.4
|
|
elif clickedOperator == "25.4/X":
|
|
if operand == 0:
|
|
result = 0
|
|
else:
|
|
result = 25.4 / operand
|
|
else:
|
|
return
|
|
self.display.setText(str(result))
|
|
self.waitingForOperand = True
|
|
self.display.setFocus()
|
|
|
|
def constClicked(self):
|
|
clickedButton = self.sender()
|
|
constValue = float(clickedButton.text())
|
|
|
|
if self.waitingForOperand:
|
|
self.display.clear()
|
|
self.waitingForOperand = False
|
|
|
|
self.display.setText(str(constValue))
|
|
self.display.setFocus()
|
|
|
|
|
|
def clear(self):
|
|
if self.waitingForOperand:
|
|
return
|
|
|
|
self.display.setText('0')
|
|
self.waitingForOperand = True
|
|
self.pendingLabel.clear()
|
|
self.display.setFocus()
|
|
|
|
def clearAll(self):
|
|
self.sumSoFar = 0.0
|
|
self.factorSoFar = 0.0
|
|
self.pendingAdditiveOperator = ''
|
|
self.pendingMultiplicativeOperator = ''
|
|
self.display.setText('0')
|
|
self.display.setFocus()
|
|
self.pendingLabel.clear()
|
|
self.waitingForOperand = True
|
|
|
|
def updateMemLabel(self):
|
|
self.memoryLabel.setText(f"MEM {self.sumInMemory}")
|
|
def clearMemory(self):
|
|
self.sumInMemory = 0.0
|
|
self.updateMemLabel()
|
|
self.display.setFocus()
|
|
|
|
def readMemory(self):
|
|
self.display.setText(str(self.sumInMemory))
|
|
self.waitingForOperand = True
|
|
self.display.setFocus()
|
|
|
|
def setMemory(self):
|
|
self.equalClicked()
|
|
self.sumInMemory = float(self.display.text())
|
|
self.updateMemLabel()
|
|
self.display.setFocus()
|
|
|
|
def addToMemory(self):
|
|
self.equalClicked()
|
|
self.sumInMemory += float(self.display.text())
|
|
self.updateMemLabel()
|
|
self.display.setFocus()
|
|
|
|
def createButton(self, text, member, tip=None):
|
|
button = QPushButton(text)
|
|
button.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
|
button.setFocusPolicy(Qt.NoFocus)
|
|
button.setMinimumSize(70, 40)
|
|
button.clicked.connect(member)
|
|
if tip is not None:
|
|
button.setToolTip(tip)
|
|
return button
|
|
|
|
def createAxisButton(self, text, member):
|
|
button = QToolButton()
|
|
button.setText(text)
|
|
button.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
|
button.setMinimumSize(70, 40)
|
|
button.clicked.connect(member)
|
|
SettingMenu = QMenu()
|
|
button.settingMenu = SettingMenu
|
|
for i in INFO.AVAILABLE_AXES:
|
|
axisButton = QAction(QIcon('exit24.png'), i, self)
|
|
# weird lambda i=i to work around 'function closure'
|
|
axisButton.triggered.connect(lambda state, i=i: self.axisTriggered(i))
|
|
SettingMenu.addAction(axisButton)
|
|
button.setMenu(SettingMenu)
|
|
return button
|
|
|
|
def abortOperation(self):
|
|
self.clearAll()
|
|
# this should really be dictated by the stylesheet in use
|
|
self.display.setStyleSheet("QLineEdit { background-color: #ff7777; }")
|
|
self.display.setFocus()
|
|
|
|
def getDisplay(self):
|
|
try:
|
|
print(self.display.text())
|
|
a = int(self.display.text())
|
|
except Exception as e:
|
|
self.display.setText('0')
|
|
print(e)
|
|
print(self.display.text())
|
|
return self.display.text()
|
|
|
|
def calculate(self, rightOperand, pendingOperator):
|
|
if pendingOperator == "+":
|
|
self.sumSoFar += rightOperand
|
|
elif pendingOperator == "-":
|
|
self.sumSoFar -= rightOperand
|
|
if pendingOperator == str("\N{MULTIPLICATION SIGN}"):
|
|
self.factorSoFar *= rightOperand
|
|
elif pendingOperator == str("\N{DIVISION SIGN}"):
|
|
if rightOperand == 0.0:
|
|
return False
|
|
self.factorSoFar /= rightOperand
|
|
return True
|
|
|
|
# these wrappers ensure focus is properly managed
|
|
def backActionWrapper(self):
|
|
self.backAction()
|
|
self.display.setFocus()
|
|
|
|
def nextActionWrapper(self):
|
|
self.nextAction()
|
|
self.display.setFocus()
|
|
|
|
def applyActionWrapper(self):
|
|
self.applyAction()
|
|
self.display.setFocus()
|
|
|
|
# Subclass can redefine
|
|
def backAction(self):
|
|
pass
|
|
def nextAction(self):
|
|
pass
|
|
def applyAction(self):
|
|
pass
|
|
|
|
# wait but don't block
|
|
# return a display value and ok/cancel
|
|
def getValue(self, title=None):
|
|
self.setWindowTitle(title)
|
|
self.show()
|
|
self.applyNextButton.setVisible(False)
|
|
self.nextButton.setVisible(False)
|
|
self.backButton.setVisible(False)
|
|
self._flag = True
|
|
while self._flag:
|
|
QApplication.processEvents()
|
|
return (self.display.text(), self._result)
|
|
|
|
def accept(self):
|
|
super(Calculator, self).accept()
|
|
self._result = True
|
|
self._flag = False
|
|
|
|
def reject(self):
|
|
super(Calculator, self).reject()
|
|
self._result = False
|
|
self._flag = False
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
app = QApplication(sys.argv)
|
|
calc = Calculator()
|
|
calc.show()
|
|
sys.exit(app.exec())
|