247 lines
5.9 KiB
Python
247 lines
5.9 KiB
Python
import math
|
|
import json
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
import customtkinter as ctk
|
|
|
|
|
|
class OutputEntry:
|
|
def __init__(self, master, count, text):
|
|
self.master = master
|
|
self.count = count
|
|
self.text = text
|
|
self.txtvar = ctk.StringVar()
|
|
self._create()
|
|
self.hide_number(hide_linenumber.get())
|
|
|
|
def _create(self):
|
|
self.fr_lo = ctk.CTkFrame(self.master)
|
|
self.fr_lo.pack(expand=True, fill='x')
|
|
self.lb_ln = ctk.CTkLabel(self.fr_lo, textvariable=self.txtvar, anchor='w')
|
|
self.lb_ln.pack(side='left')
|
|
self.lb_output = ctk.CTkLabel(self.fr_lo, text=self.text, anchor='w')
|
|
self.lb_output.pack(expand=True, fill='x', side='left')
|
|
|
|
def hide_number(self, state):
|
|
if state:
|
|
self.txtvar.set(str(self.count) + ') ')
|
|
else:
|
|
self.txtvar.set('')
|
|
|
|
def hide(self):
|
|
self.fr_lo.pack_forget()
|
|
|
|
|
|
def write_config(config):
|
|
with open('config_abacus.json', 'w') as file:
|
|
json.dump(config, file)
|
|
|
|
|
|
def load_config():
|
|
try:
|
|
with open('config_abacus.json') as file:
|
|
return json.load(file)
|
|
except FileNotFoundError:
|
|
config = {
|
|
"resolution": "400x400"
|
|
}
|
|
write_config(config)
|
|
|
|
|
|
config = load_config()
|
|
|
|
assert config is not None
|
|
|
|
|
|
def on_exit():
|
|
config['resolution'] = app.geometry()
|
|
config['linenumber'] = hide_linenumber.get()
|
|
config['variable_names'] = None
|
|
config['variables'] = variables
|
|
write_config(config)
|
|
app.destroy()
|
|
|
|
|
|
app = ctk.CTk()
|
|
app.geometry(config.get('resolution'))
|
|
app.title('AbacusNG')
|
|
app.grid_columnconfigure((0, 1, 2, 3), weight=1)
|
|
app.grid_rowconfigure((0, 1), weight=0)
|
|
app.grid_rowconfigure((2), weight=1)
|
|
app.protocol("WM_DELETE_WINDOW", on_exit)
|
|
|
|
|
|
def round2(x):
|
|
return round(x, 2)
|
|
|
|
|
|
def round3(x):
|
|
return round(x, 3)
|
|
|
|
|
|
def gz(x):
|
|
return int(x)
|
|
|
|
|
|
def show(x):
|
|
output = ''
|
|
for k, v in variables.items():
|
|
output += k + ': ' + str(v) + '\n'
|
|
create_output_entry(output)
|
|
|
|
|
|
def clear():
|
|
global output_entries
|
|
global count
|
|
count = 0
|
|
for oe in output_entries:
|
|
oe.hide()
|
|
output_entries = list()
|
|
input_str.set(str(0))
|
|
return 'Cleared'
|
|
|
|
|
|
variables = config.get('variables')
|
|
count = 0
|
|
|
|
output_entries = list()
|
|
|
|
functions = {'r2': round2, 'r3': round3, 'show': show, 'gz': int}
|
|
input_str = ctk.StringVar()
|
|
hide_linenumber = ctk.BooleanVar(value=config.get('linenumber'))
|
|
|
|
|
|
def hide_numbers():
|
|
for oe in output_entries:
|
|
oe.hide_number(hide_linenumber.get())
|
|
|
|
|
|
def create_output_entry(text):
|
|
global count
|
|
count = count + 1
|
|
output_entries.append(OutputEntry(fr_output, count, text))
|
|
|
|
|
|
def build_chunks(text):
|
|
begin = 0
|
|
chunks = list()
|
|
j = 0
|
|
for i, c in enumerate(text):
|
|
j = i + 1
|
|
if c in ['+', '-', '/', '*', '(', ')', '.']:
|
|
chunk = text[begin:i]
|
|
chunk = chunk.strip()
|
|
if chunk.isalnum():
|
|
chunks.append(chunk)
|
|
chunks.append(c)
|
|
begin = i + 1
|
|
chunk = text[begin:j]
|
|
chunk = chunk.strip()
|
|
if chunk.isalnum():
|
|
chunks.append(chunk)
|
|
return chunks
|
|
|
|
|
|
def get_input(event):
|
|
inp = input_str.get()
|
|
result = parse_input_new(inp)
|
|
create_output_entry(result)
|
|
|
|
|
|
def calculate(t):
|
|
try:
|
|
output = eval(t)
|
|
except Exception as e:
|
|
output = e
|
|
return output
|
|
|
|
|
|
def parse_input_new(t: str):
|
|
t = t.strip()
|
|
t = t.replace('.', '')
|
|
t = t.replace(',', '.')
|
|
input = t
|
|
comment = None
|
|
var = None
|
|
func = None
|
|
|
|
# kommentar
|
|
if input[0] == '#': # ganze zeile ist ein kommentar
|
|
comment = input[1:]
|
|
elif input.find('#') > -1: # nur ein teil ist ein kommentar
|
|
input, comment = input.split('#')
|
|
input = input.strip()
|
|
comment = comment.strip()
|
|
|
|
# variablenzuweisung
|
|
if input.find('=') > -1:
|
|
var, input = input.split('=')
|
|
var = var.strip()
|
|
input = input.strip()
|
|
if input.find(':') > -1:
|
|
func, input = input.split(':')
|
|
func = func.strip()
|
|
input = input.strip()
|
|
print('input', input)
|
|
|
|
chunks = build_chunks(input)
|
|
|
|
for i, c in enumerate(chunks):
|
|
v = variables.get(c)
|
|
print('v:', v)
|
|
if v:
|
|
chunks[i] = v
|
|
print('chunks after', chunks)
|
|
|
|
result = ''.join(chunks)
|
|
if len(result) > 0:
|
|
result = calculate(result)
|
|
if func:
|
|
if func == 'show':
|
|
if len(str(result)) <= 0:
|
|
show(count)
|
|
result = str(input) + ' = ' + str(result)
|
|
else:
|
|
f = functions.get(func)
|
|
if f:
|
|
result = f(result)
|
|
if var:
|
|
variables[var] = str(result)
|
|
|
|
result = str(result)
|
|
result = result.replace('.', ',')
|
|
|
|
input_str.set(result)
|
|
|
|
# output modifikatoren
|
|
|
|
result = input + ' = ' + result
|
|
if comment:
|
|
result = result + ' # ' + comment
|
|
|
|
return result
|
|
|
|
|
|
ent_input = ctk.CTkEntry(app, placeholder_text='Enter it', font=('CTkFont', 18), justify='right',
|
|
textvariable=input_str)
|
|
ent_input.focus()
|
|
ent_input.grid(row=0, column=0, pady=(10, 20), columnspan=4, sticky='ew')
|
|
|
|
ent_input.bind('<Return>', get_input)
|
|
ent_input.bind('<KP_Enter>', get_input)
|
|
|
|
checkbox_ln = ctk.CTkCheckBox(app, text="Linenumber", variable=hide_linenumber, command=hide_numbers)
|
|
checkbox_ln.grid(row=1, column=0, padx=20, pady=(10, 20), sticky="w")
|
|
checkbox_var = ctk.CTkCheckBox(app, text="variables")
|
|
checkbox_var.grid(row=1, column=1, padx=20, pady=(10, 20), sticky="w")
|
|
|
|
btn_clear = ctk.CTkButton(app, text="clear", command=clear)
|
|
btn_clear.grid(row=1, column=2, padx=20, pady=(10, 20), sticky="w")
|
|
btn_save = ctk.CTkButton(app, text="save")
|
|
btn_save.grid(row=1, column=3, padx=20, pady=(10, 20), sticky="w")
|
|
|
|
fr_output = ctk.CTkScrollableFrame(app)
|
|
fr_output.grid(row=2, column=0, columnspan=4, sticky='news')
|
|
|
|
app.mainloop()
|