-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathlogic.py
240 lines (227 loc) · 11 KB
/
logic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
"""Handles all the calculations for the calculator."""
from decimal import Decimal as dec
from decimal import getcontext
class Logic:
"""The brain of the calculator, and all functions in this class."""
def __init__(self, display):
"""Initialise the Logic."""
self.display = display # The display of the calculator, to be updated
self.input_num = dec(0) # The number currently being typed
self.decimal = None # nr. of decimals, None if no decimal point
self.stored_num = None # The other number being stored in memory
self.operator = None # The operator to be used
self.button = None # The button that was pressed
self.memory = dec(0)
getcontext().prec = 16
def button_press(self, button):
"""Handle the button press."""
try:
self.button = button.text() # The button pressed
# Subdefining the buttons into different functions
if self.button in ['0', '1', '2', '3', '4', '5', '6', '7',
'8', '9']:
self.number_button()
elif self.button == '.':
self.decimal_button()
elif self.button == '+/-':
self.negative_button()
elif self.button in ['+', '-', '×', '÷']:
self.operator_button()
elif self.button in ['x²', '√x', '1/x']:
self.operator_single_input() # Calculates right away
elif self.button == '%':
self.percent_button() # Similar to single input op
elif self.button in ['⌫', 'CE', 'C']:
self.clear_button()
elif self.button in ['MC', 'MR', 'M+', 'M-']:
self.memory_button()
elif self.button == '=':
if None not in [self.input_num, self.stored_num,
self.operator]:
# If any of the 3 are not defined, can't do the calculation
self.calculate()
except ZeroDivisionError:
self.display.setText('ERROR: divide by 0')
def calculate(self):
"""Calculate with operators using 2 numbers as input."""
# Processing the different operators
if self.operator == '+':
self.stored_num = self.stored_num + self.input_num
elif self.operator == '-':
self.stored_num = self.stored_num - self.input_num
elif self.operator == '×':
self.stored_num = self.stored_num * self.input_num
elif self.operator == '÷':
self.stored_num = self.stored_num / self.input_num
# Result being stored in stored_num and input_num getting cleared
self.stored_num = self.stored_num.normalize()
self.input_num = dec(0)
self.operator = None
# Displaying the newly calculated result
self.display.setText(str(self.stored_num))
def number_button(self):
"""Pressing a number button, appends the input number."""
number = int(self.button) # Number to be appended
input = self.input_num.as_tuple() # input_num as a named tuple
if self.input_num.is_zero() and self.decimal is None:
# When no number is typed yet, sets the number to the typed one
input = input._replace(digits=(number,))
if self.operator is None and self.stored_num is not None:
# When typing a new number, after using equals on another calc
self.stored_num = None
elif len(input.digits) < 16:
# Appends the button pressed to the existing number
# Caps the input to 16 digits
input = input._replace(digits=input.digits + (number,))
if self.decimal is not None:
# Moves the decimal if needed
self.decimal += 1
input = input._replace(exponent=-self.decimal)
# Updates the input number
self.input_num = dec(input)
# Displays the number currently being typed
self.display.setText(str(self.input_num))
def decimal_button(self):
"""Pressing the decimal button, converts input to decimal."""
if self.decimal is None:
self.decimal = 0
self.display.setText(str(str(self.input_num) + '.'))
def negative_button(self):
"""Pressing the negative toggle button, toggles negative/positive."""
input = self.input_num.as_tuple()
input = input._replace(sign=not input.sign)
self.input_num = dec(input)
self.display.setText(str(self.input_num))
def operator_button(self):
"""Pressing an operator button, that uses two numbers."""
if self.stored_num is None:
# Moving the input number to storage, to allow new input
self.stored_num = self.input_num
self.input_num = dec(0)
self.decimal = None
else:
# When you click an operator after putting in a full equation
self.calculate() # Will calculate previous calculation first
# Assigns the new operator, or reassigns it when you change operator
self.operator = self.button
# Updates the display, to show both the number and the operator
self.display.setText(str(self.stored_num) + self.operator)
def operator_single_input(self):
"""Pressing an operator button, that uses one number, giving result."""
def calc(num, operator=self.button):
# Processes the different operations
if operator == 'x²':
# Squares the number
result = num ** 2
elif operator == '√x':
# Squareroots the number
result = num.sqrt() # Decimal module functionality
elif operator == '1/x':
# Inverses the number (1 divided by the number)
result = 1 / num
return result.normalize()
if self.input_num.is_zero():
if self.stored_num is None:
# Only input_num is defined, will put answer in stored
self.stored_num = calc(self.input_num, self.button)
# Displaying result
self.display.setText(str(self.stored_num))
else:
# Both are defined, will calculate first
self.calculate()
self.stored_num = calc(self.stored_num, self.button)
self.display.setText(str(self.stored_num))
elif self.stored_num is not None and self.operator is None:
# Calculates on a previous result
self.stored_num = calc(self.stored_num, self.button)
self.display.setText(str(self.stored_num))
# Any other case, won't work (including no number defined, or mid calc)
def percent_button(self):
"""Pressing the percent button, lots of features, calculates."""
if self.input_num.is_zero():
if self.stored_num is not None and self.operator is None:
# Converts previous result to percent
self.stored_num = self.stored_num / 100
self.display.setText(str(self.stored_num))
# Any other case without input number, won't do anything
else:
# There is an input number
if self.operator is None:
# If no operator shown, will just display percent of input num
self.stored_num = self.input_num / 100
self.input_num = dec(0)
self.display.setText(str(self.stored_num))
else:
# When there is an operator, does the calculation
if self.operator in ['+', '-']:
# Adds or subtracts a percentage (inp) of the num (stored)
self.input_num = self.stored_num * (self.input_num / 100)
self.calculate()
elif self.operator in ['×', '÷']:
# Finds the percentage (inp) of the number (stored)
# Or divides by the percentage, not sure if feature needed
self.input_num = self.input_num / 100
self.calculate()
def clear_button(self):
"""Pressing a clearing button(backspace, clear entry, global clear)."""
if self.button == '⌫':
# Backspace, delete one char
if not self.input_num.is_zero():
# Can't delete nothing *shrugs*
if self.decimal == 0:
# Deletes the decimal point instead
self.decimal = None
self.display.setText(str(self.input_num))
else:
input = self.input_num.as_tuple() # Converting to tuple
# Deleting one char
input = input._replace(digits=input.digits[:-1])
if self.decimal is not None:
# Moves the decimal point, if it exists
self.decimal -= 1
input = input._replace(exponent=-self.decimal)
# Putting the updated number back, and updates display
self.input_num = dec(input)
self.display.setText(str(self.input_num))
elif self.button == 'CE':
# Clear entry, erases the current input number
self.input_num = dec(0)
self.decimal = None
self.display.setText('0') # Displaying 0 (resseting)
elif self.button == 'C':
# Clear global, erasing entire memory
self.input_num = dec(0)
self.decimal = None
self.stored_num = None
self.operator = None
self.display.setText('0') # Displaying 0 (resseting)
def memory_button(self):
"""Trigger any button related to the memory variable."""
if self.button == 'MC':
# Resets the memory variable
self.memory = dec(0)
elif self.button == 'MR':
# Prints out the memory variable
if self.stored_num is not None and self.operator is None:
# Clears stored if overwriting previous result
self.stored_num = None
# Sets input to memory, clears existing
self.input_num = self.memory
self.decimal = -self.memory.as_tuple().exponent # Updates too ofc
if self.decimal == 0: # If 0 there is no decimal, so None
self.decimal = None
self.display.setText(str(self.input_num)) # Sets the display
elif self.button == 'M+':
if self.stored_num is not None and self.operator is None:
# Adds previous result to the memory
self.memory += self.stored_num
else:
# Adds current input to the memory
self.memory += self.input_num
elif self.button == 'M-':
if self.stored_num is not None and self.operator is None:
# Subtracts previous result to the memory
self.memory -= self.stored_num
else:
# Subtracts current input to the memory
self.memory -= self.input_num