# ~~~ About ~~~ # This is a percentage calculator app built for the Cardputer platform using MicroHydra. # The app allows users to perform various percentage-related calculations, such as: # 1. Finding what X% of Y is. # 2. Finding what percentage X is of Y. # 3. Calculating the percentage change from X to Y. # 4. Determining what number X is Y% of. # 5. Finding the percentage difference between X and Y. # The display is handled using the `display` module, user input is captured through the `userinput` module, and the configuration is accessed via `config`. from lib import display, userinput from lib.hydra import config import time from font import vga1_8x16 as font # Importing a larger font # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _CONSTANTS: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _MH_DISPLAY_HEIGHT = const(135) # Height is 135 pixels _MH_DISPLAY_WIDTH = const(240) # Width is 240 pixels _MAX_CHARS_PER_LINE = _MH_DISPLAY_WIDTH // 8 # 30 characters per line (8px per char) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GLOBAL_OBJECTS: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # init object for accessing display DISPLAY = display.Display() # object for accessing microhydra config CONFIG = config.Config() # object for reading keypresses (or other user input) INPUT = userinput.UserInput() # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION DEFINITIONS: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def calculate_percentage(option, a, b): """Perform percentage calculations based on the selected option.""" if option == 1: return a * (b / 100) # What is X% of Y? elif option == 2: return (a / b) * 100 # X is what % of Y? elif option == 3: return ((b - a) / a) * 100 # Percentage increase/decrease from X to Y elif option == 4: return a / (b / 100) # X is Y% of what? elif option == 5: return abs(a - b) / ((a + b) / 2) * 100 # Percentage difference between X and Y else: return None def wrap_text(text, max_chars_per_line): """Wrap text into multiple lines based on max characters per line.""" lines = [] while len(text) > max_chars_per_line: space_index = text.rfind(' ', 0, max_chars_per_line) # Find the last space if space_index == -1: # No space found, force break lines.append(text[:max_chars_per_line]) text = text[max_chars_per_line:] else: # Break at the last space lines.append(text[:space_index]) text = text[space_index + 1:] # Skip the space lines.append(text) # Append the remaining text return lines def display_wrapped_text(lines, x, y, color): """Display wrapped text on the display starting from position (x, y).""" line_height = 16 # Line height for vga1_8x16 font for i, line in enumerate(lines): DISPLAY.text(line, x, y + i * line_height, color, font=font) def main_loop(): input_number1 = "" input_number2 = "" result = "" display_mode = "menu" # Modes: "menu", "input1", "input2", "result" option = None # None, 1 to 5 while True: keys = INPUT.get_new_keys() if keys: if display_mode == "menu": if "1" in keys: option = 1 display_mode = "input1" elif "2" in keys: option = 2 display_mode = "input1" elif "3" in keys: option = 3 display_mode = "input1" elif "4" in keys: option = 4 display_mode = "input1" elif "5" in keys: option = 5 display_mode = "input1" elif display_mode == "input1": if "ENT" in keys: if input_number1: display_mode = "input2" else: for key in keys: if key.isdigit() or key == ".": input_number1 += key elif key == "BSPC": input_number1 = input_number1[:-1] elif key == "CLR": input_number1 = "" elif display_mode == "input2": if "ENT" in keys: if input_number2: a = float(input_number1) b = float(input_number2) result = calculate_percentage(option, a, b) display_mode = "result" else: for key in keys: if key.isdigit() or key == ".": input_number2 += key elif key == "BSPC": input_number2 = input_number2[:-1] elif key == "CLR": input_number2 = "" elif display_mode == "result": if "ENT" in keys: input_number1 = "" input_number2 = "" result = "" display_mode = "menu" DISPLAY.fill(CONFIG.palette[2]) if display_mode == "menu": DISPLAY.text( text="1. What is X% of Y?", x=5, y=10, # Adjusted Y position color=CONFIG.palette[8], font=font ) DISPLAY.text( text="2. X is what % of Y?", x=5, y=35, # Reduced spacing color=CONFIG.palette[8], font=font ) DISPLAY.text( text="3. % change from X to Y?", x=5, y=60, # Reduced spacing color=CONFIG.palette[8], font=font ) DISPLAY.text( text="4. X is Y% of what?", x=5, y=85, # Reduced spacing color=CONFIG.palette[8], font=font ) DISPLAY.text( text="5. % difference X and Y?", x=5, y=110, # Fits within the screen color=CONFIG.palette[8], font=font ) elif display_mode == "input1": DISPLAY.text( text="Enter first number:", x=5, y=30, color=CONFIG.palette[8], font=font ) DISPLAY.text( text=input_number1, x=5, y=60, color=CONFIG.palette[8], font=font ) elif display_mode == "input2": DISPLAY.text( text="Enter second number:", x=5, y=30, color=CONFIG.palette[8], font=font ) DISPLAY.text( text=input_number2, x=5, y=60, color=CONFIG.palette[8], font=font ) elif display_mode == "result": result_text = { 1: f"{input_number1}% of {input_number2} = {result}", 2: f"{input_number1} is {result}% of {input_number2}", 3: f"Change from {input_number1} to {input_number2} = {result}%", 4: f"{input_number1} is {input_number2}% of {result}", 5: f"Difference between {input_number1} and {input_number2} = {result}%" }[option] # Wrap the result text and display it wrapped_lines = wrap_text(result_text, _MAX_CHARS_PER_LINE) display_wrapped_text(wrapped_lines, x=5, y=30, color=CONFIG.palette[8]) DISPLAY.show() time.sleep_ms(10) main_loop()