Skip to content

Commit 64dd3bd

Browse files
committed
Added PyPortal Calculator
1 parent 8c27d6a commit 64dd3bd

4 files changed

Lines changed: 6289 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
*~
22
Hue_Controller/secrets.h
33
.idea
4-
4+
*.DS_Store
55
CircuitPython_Logger/secrets\.py

PyPortal_Calculator/calculator.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
Class that handles the input and calculations
3+
"""
4+
5+
# Calculator Class
6+
class Calculator:
7+
def __init__(self, calc_display, clear_button, label_offset):
8+
self._calc_display = calc_display
9+
self._clear_button = clear_button
10+
self._label_offset = label_offset
11+
self._all_clear()
12+
13+
def _calculate(self, number_one, operator, number_two):
14+
result = eval(number_one + operator + number_two)
15+
if int(result) == result:
16+
result = int(result)
17+
return str(result)
18+
19+
def _all_clear(self):
20+
self._accumulator = "0"
21+
self._operator = None
22+
self._equal_pressed = False
23+
self._clear_entry()
24+
25+
def _clear_entry(self):
26+
self._operand = None
27+
self._set_button_ce(False)
28+
self._set_text("0")
29+
30+
def _set_button_ce(self, entry_only):
31+
if entry_only:
32+
self._clear_button.label = "CE"
33+
else:
34+
self._clear_button.label = "AC"
35+
36+
def _set_text(self, text):
37+
self._calc_display.text = text
38+
_, _, screen_w, _ = self._calc_display.bounding_box
39+
self._calc_display.x = self._label_offset - screen_w
40+
41+
def _get_text(self):
42+
return self._calc_display.text
43+
44+
def add_input(self, input):
45+
try:
46+
if input == "AC":
47+
self._all_clear()
48+
elif input == "CE":
49+
self._clear_entry()
50+
elif self._operator is None and input == "0":
51+
pass
52+
elif len(input) == 1 and 48 <= ord(input) <= 57:
53+
display_text = self._get_text()
54+
if self._operand is None and self._operator is not None:
55+
display_text = ""
56+
elif self._operand is not None and self._operator is not None and self._equal_pressed:
57+
self._accumulator = self._operand
58+
self._operator = None
59+
self._operand = None
60+
display_text = ""
61+
elif display_text == "0":
62+
display_text = ""
63+
display_text += input
64+
self._set_text(display_text)
65+
if self._operator is not None:
66+
self._operand = display_text
67+
self._set_button_ce(True)
68+
self._equal_pressed = False
69+
elif input == "+" or input == "-" or input == "/" or input == "x":
70+
if input == "x":
71+
input = "*"
72+
if self._equal_pressed:
73+
self._operand = None
74+
if self._operator is None:
75+
self._operator = input
76+
else:
77+
# Perform current calculation before changing inputs
78+
if self._operand is not None:
79+
self._accumulator = self._calculate(self._accumulator, self._operator, self._operand)
80+
self._set_text(self._accumulator)
81+
self._operand = None
82+
self._operator = input
83+
self._accumulator = self._get_text()
84+
self._equal_pressed = False
85+
elif input == ".":
86+
if not input in self._get_text():
87+
self._set_text(self._get_text() + input)
88+
self._set_button_ce(True)
89+
self._equal_pressed = False
90+
elif input == "+/-":
91+
self._set_text(self._calculate(self._get_text(), "*", "-1"))
92+
elif input == "%":
93+
self._set_text(self._calculate(self._get_text(), "/", "100"))
94+
elif input == "=":
95+
if self._operator is not None:
96+
if self._operand is None:
97+
self._operand = self._get_text()
98+
self._accumulator = self._calculate(self._accumulator, self._operator, self._operand)
99+
self._set_text(self._accumulator)
100+
self._equal_pressed = True
101+
# For Debugging
102+
print("\n----------------")
103+
print("Input: {}".format(input))
104+
print("Accumulator: {}".format(self._accumulator))
105+
print("Operator: {}".format(self._operator))
106+
print("Operand: {}".format(self._operand))
107+
except (ZeroDivisionError, RuntimeError) as error:
108+
self._all_clear()
109+
self._set_text("Error")

PyPortal_Calculator/code.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"""
2+
PyPortal Calculator Demo
3+
"""
4+
import time
5+
import board
6+
import displayio
7+
import os
8+
from collections import namedtuple
9+
from adafruit_display_text.label import Label
10+
from adafruit_bitmap_font import bitmap_font
11+
from adafruit_display_shapes.rect import Rect
12+
from adafruit_button import Button
13+
from calculator import Calculator
14+
import adafruit_touchscreen
15+
coords = namedtuple("Point", "x y")
16+
17+
ts = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR,
18+
board.TOUCH_YD, board.TOUCH_YU,
19+
calibration=((5200, 59000), (5800, 57000)),
20+
size=(320, 240))
21+
22+
# Settings
23+
BUTTON_WIDTH = 60
24+
BUTTON_HEIGHT = 30
25+
BUTTON_MARGIN = 8
26+
MAX_DIGITS = 29
27+
BLACK = 0x0
28+
ORANGE = 0xFF8800
29+
WHITE = 0xFFFFFF
30+
GRAY = 0x888888
31+
LABEL_OFFSET = 290
32+
33+
# Make the display context
34+
calc_group = displayio.Group(max_size=25)
35+
board.DISPLAY.show(calc_group)
36+
37+
# Make a background color fill
38+
color_bitmap = displayio.Bitmap(320, 240, 1)
39+
color_palette = displayio.Palette(1)
40+
color_palette[0] = GRAY
41+
bg_sprite = displayio.TileGrid(color_bitmap,
42+
pixel_shader=color_palette,
43+
x=0, y=0)
44+
calc_group.append(bg_sprite)
45+
46+
# Load the font
47+
font = bitmap_font.load_font("/fonts/Arial-12.bdf")
48+
buttons = []
49+
50+
# Some button placement functions
51+
def button_grid(row, col):
52+
return coords(BUTTON_MARGIN * (row + 1) + BUTTON_WIDTH * row + 20,
53+
BUTTON_MARGIN * (col + 1) + BUTTON_HEIGHT * col + 40)
54+
55+
def make_button(row, col, label, width=1, color=WHITE, text_color=BLACK):
56+
pos = button_grid(row, col)
57+
button = Button(x=pos.x, y=pos.y,
58+
width=BUTTON_WIDTH * width + BUTTON_MARGIN * (width - 1), height=BUTTON_HEIGHT,
59+
label=label, label_font=font, label_color=text_color, fill_color=color,
60+
style=Button.ROUNDRECT)
61+
buttons.append(button)
62+
return button
63+
64+
border = Rect(20, 8, 280, 35, fill=WHITE, outline=BLACK, stroke=2)
65+
calc_display = Label(font, text="0", color=BLACK, max_glyphs=MAX_DIGITS)
66+
calc_display.y = 25
67+
68+
clear_button = make_button(0, 0, "AC")
69+
make_button(1, 0, "+/-")
70+
make_button(2, 0, "%")
71+
make_button(3, 0, "/", 1, ORANGE, WHITE)
72+
make_button(0, 1, "7")
73+
make_button(1, 1, "8")
74+
make_button(2, 1, "9")
75+
make_button(3, 1, "x", 1, ORANGE, WHITE)
76+
make_button(0, 2, "4")
77+
make_button(1, 2, "5")
78+
make_button(2, 2, "6")
79+
make_button(3, 2, "-", 1, ORANGE, WHITE)
80+
make_button(0, 3, "1")
81+
make_button(1, 3, "2")
82+
make_button(2, 3, "3")
83+
make_button(3, 3, "+", 1, ORANGE, WHITE)
84+
make_button(0, 4, "0", 2)
85+
make_button(2, 4, ".")
86+
make_button(3, 4, "=", 1, ORANGE, WHITE)
87+
88+
# Add the display and buttons to the main calc group
89+
calc_group.append(border)
90+
calc_group.append(calc_display)
91+
for b in buttons:
92+
calc_group.append(b.group)
93+
94+
calculator = Calculator(calc_display, clear_button, LABEL_OFFSET)
95+
96+
button = ""
97+
while True:
98+
point = ts.touch_point
99+
if point is not None:
100+
for i, b in enumerate(buttons):
101+
if b.contains(point) and button == "":
102+
b.selected = True
103+
button = b.label
104+
time.sleep(0.1)
105+
b.selected = False
106+
break
107+
else:
108+
if button != "":
109+
calculator.add_input(button)
110+
button = ""
111+
time.sleep(0.05)

0 commit comments

Comments
 (0)