141 lines
4.7 KiB
Python
141 lines
4.7 KiB
Python
|
# windows: pip install windows-curses
|
||
|
import curses
|
||
|
from operator import and_, or_, xor
|
||
|
|
||
|
def initCurses() -> tuple:
|
||
|
"""Initialise curses and any necessary colour pairs"""
|
||
|
screen = curses.initscr()
|
||
|
screen.keypad(True)
|
||
|
|
||
|
curses.cbreak()
|
||
|
curses.noecho()
|
||
|
curses.start_color()
|
||
|
|
||
|
# default
|
||
|
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
|
||
|
default = curses.color_pair(1)
|
||
|
|
||
|
# highlighted
|
||
|
curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
||
|
highlighted = curses.color_pair(2)
|
||
|
|
||
|
# error
|
||
|
curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
|
||
|
error = curses.color_pair(3)
|
||
|
|
||
|
return (screen, (default, highlighted, error))
|
||
|
|
||
|
def destroyCurses(screen):
|
||
|
"""Close out of curses and reverse any destructive changes to the terminal"""
|
||
|
curses.nocbreak()
|
||
|
screen.keypad(False)
|
||
|
curses.echo()
|
||
|
curses.endwin()
|
||
|
|
||
|
def selectMenu(screen, options: list, header: str = "Pick an option:"):
|
||
|
selectedIndex = 0
|
||
|
optionCount = len(options)
|
||
|
|
||
|
while True:
|
||
|
screen.clear()
|
||
|
screen.addstr(f"{header}\n\n", curses.A_BOLD)
|
||
|
|
||
|
for i in range(optionCount):
|
||
|
screen.addstr(f"{i + 1}. ")
|
||
|
screen.addstr(f"{options[i]}\n", highlighted if i == selectedIndex else default)
|
||
|
|
||
|
c = screen.getch()
|
||
|
|
||
|
if c == curses.KEY_UP or c == curses.KEY_LEFT:
|
||
|
selectedIndex -= 1 - optionCount
|
||
|
selectedIndex %= optionCount
|
||
|
|
||
|
elif c == curses.KEY_DOWN or c == curses.KEY_RIGHT:
|
||
|
selectedIndex += 1
|
||
|
selectedIndex %= optionCount
|
||
|
|
||
|
elif c == curses.KEY_ENTER or chr(c) in '\n\r':
|
||
|
return selectedIndex + 1
|
||
|
|
||
|
def getBinary(screen, prompt: str, length: int = None) -> list:
|
||
|
errorMessage = None
|
||
|
|
||
|
while True:
|
||
|
screen.clear()
|
||
|
screen.addstr(0, 0, f"{prompt}", curses.A_BOLD)
|
||
|
|
||
|
# display an error message if necessary
|
||
|
if errorMessage:
|
||
|
screen.addstr(3, 0, errorMessage, error | curses.A_BOLD)
|
||
|
errorMessage = None
|
||
|
|
||
|
# fetch the inputted data
|
||
|
curses.echo()
|
||
|
bits = list(screen.getstr(1, 0, 50).decode("utf-8"))
|
||
|
curses.noecho()
|
||
|
|
||
|
# validate that a binary value was entered
|
||
|
for bit in bits:
|
||
|
if bit not in ["0", "1"]:
|
||
|
errorMessage = "Invalid binary number. Please try again."
|
||
|
|
||
|
if len(bits) == 0:
|
||
|
errorMessage = "Please make sure you enter a value."
|
||
|
|
||
|
elif length and len(bits) != length:
|
||
|
errorMessage = f"Please make sure the value is {length} bits long."
|
||
|
|
||
|
if errorMessage:
|
||
|
continue
|
||
|
|
||
|
return [int(x) for x in bits]
|
||
|
|
||
|
def applyOperator(screen, binary: list, mask: list) -> list:
|
||
|
# todo: fix
|
||
|
# operatorList = list(OPERATORS.keys())
|
||
|
# symbol, operator = OPERATORS[operatorList[selectMenu(screen, operatorList) - 1]]
|
||
|
# output = "".join(str(operator(a, b)) for a, b in zip(binary, mask))
|
||
|
binary = "".join(str(x) for x in binary)
|
||
|
mask = "".join(str(x) for x in mask)
|
||
|
print(binary, mask, screen)
|
||
|
|
||
|
while True:
|
||
|
screen.clear()
|
||
|
screen.addstr(0, 0, f"{binary} {mask}", curses.A_BOLD)
|
||
|
screen.addstr(3, 0, "Press the backspace key to get back to the main menu.")
|
||
|
screen.addstr(4, 0, "")
|
||
|
|
||
|
# get pressed key
|
||
|
c = screen.getch()
|
||
|
|
||
|
if c == 8 or c == 127 or c == curses.KEY_BACKSPACE:
|
||
|
break
|
||
|
|
||
|
OPERATORS = {
|
||
|
'AND': ('&', lambda binary, mask: applyOperator(binary, mask, and_)),
|
||
|
'OR': ('|', lambda binary, mask: applyOperator(binary, mask, or_)),
|
||
|
'XOR': ('^', lambda binary, mask: applyOperator(binary, mask, xor))
|
||
|
}
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
# init curses
|
||
|
screen, (default, highlighted, error) = initCurses()
|
||
|
binary, mask = [], []
|
||
|
|
||
|
while True:
|
||
|
binaryStr = "[NONE]" if len(binary) == 0 else "".join(str(x) for x in binary)
|
||
|
maskStr = "[NONE]" if len(mask) == 0 else "".join(str(x) for x in mask)
|
||
|
|
||
|
choice = selectMenu(screen, ["Apply a gate", "Change the binary number", "Change the mask", "Exit"], f"Current binary number: {binaryStr}\nCurrent mask: {maskStr}\n\nWhat would you like to do?")
|
||
|
|
||
|
if choice == 1:
|
||
|
applyOperator(screen, binary, mask)
|
||
|
elif choice == 2:
|
||
|
binary = getBinary(screen, "Please enter a new binary value:", None if len(mask) == 0 else len)
|
||
|
elif choice == 3:
|
||
|
mask = getBinary(screen, "Please enter a new mask:", None if len(binary) == 0 else len(binary))
|
||
|
elif choice == 4:
|
||
|
break
|
||
|
|
||
|
# destroy curses
|
||
|
destroyCurses(screen)
|