# --- Material UI calculator --- # import strutils, nodesnim type TokenType {.size: sizeof(int8).} = enum NUMBER, OPERATOR, RPAR, LPAR Token = ref object token_type: TokenType token_value: string TokenTree = seq[Token] proc parseQuery(query: string): TokenTree = result = @[] for c in query: if c.isDigit() or c == '.': if result.len > 0 and not result[^1].isNil() and result[^1].token_type == NUMBER: result[^1].token_value &= $c else: result.add(Token(token_type: NUMBER, token_value: $c)) elif c in "+-/*": result.add(Token(token_type: OPERATOR, token_value: $c)) when false: for i in result: echo i.token_value proc findHigh(tree: TokenTree): int = result = -1 let tokens = "/*-+" for token in tokens: for i in tree.low..tree.high: if tree[i].token_type == OPERATOR and tree[i].token_value == $token: return i-1 proc calculate(tree: TokenTree): float = result = 0f var t = tree index = t.findHigh() while index != -1: case t[index+1].token_value of "/": t[index].token_value = $(t[index].token_value.parseFloat() / t[index+2].token_value.parseFloat()) of "*": t[index].token_value = $(t[index].token_value.parseFloat() * t[index+2].token_value.parseFloat()) of "-": t[index].token_value = $(t[index].token_value.parseFloat() - t[index+2].token_value.parseFloat()) of "+": t[index].token_value = $(t[index].token_value.parseFloat() + t[index+2].token_value.parseFloat()) t.del(index+2) t.del(index+1) index = t.findHigh() if t.len == 1: result = parseFloat(t[0].token_value) Window("material ui calculator", ((64+32)*4)+16, 480) env.setBackgroundColor(Color("#FAFAFA")) var query: string = "" big_font = loadFont(standard_font_path, 32) medium = loadFont(standard_font_path, 24) small = loadFont(standard_font_path, 16) build: - Button number_button: call setStyle(style({color: "#EEEEEE"})) call resize(64+32, 64) call setTextFont(loadFont(standard_font_path, 24)) - Button operator_button: call setStyle(style({color: "#F5F5F5"})) call resize(64+32, 51.2f) call setTextFont(loadFont(standard_font_path, 22)) number_button.normal_background.setStyle(style({background-color: "#424242"})) number_button.hover_background.setStyle(style({background-color: "#616161"})) number_button.press_background.setStyle(style({background-color: "#757575"})) operator_button.normal_background.setStyle(style({background-color: "#616161"})) operator_button.hover_background.setStyle(style({background-color: "#757575"})) operator_button.press_background.setStyle(style({background-color: "#9E9E9E"})) when false: query = "123+1*5-200/10" var parsed = parseQuery(query) calculated = calculate(parsed) build: - Scene main: - HBox hbox: separator: 0 call setPadding(8, 8, 8, 8) call move(0, 200) - GridBox numbers: separator: 0 call setRow(3) - Vbox operators: separator: 0 - Control result_back: call resize(((64+32)*4), 200) call move(8, 8) call setStyle(style({ background-color: "#4DD0E1", shadow: true, shadow-offset: "0 8" })) - Label text: call setTextFont(loadFont(standard_font_path, 32)) call setTextColor(Color("#fff")) call setTextAlign(1, 1, 1, 1) call setAnchor(1, 1, 1, 1) call setSizeAnchor(1, 0.5) call setPadding(16, 16, 16, 16) for i in 0..11: numbers.addChild(number_button.duplicate()) if i < 9: numbers.getChild(i).ButtonRef.setText($(i+1)) numbers.getChild(i).ButtonRef@onClick(self, x, y): query &= self.ButtonRef.getText() text.setText(query) elif i == 9: numbers.getChild(i).ButtonRef.setText(".") numbers.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0 and query[^1] != '.': query &= self.ButtonRef.getText() text.setText(query) elif i == 10: numbers.getChild(i).ButtonRef.setText("0") numbers.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0: query &= self.ButtonRef.getText() text.setText(query) elif i == 11: numbers.getChild(i).ButtonRef.setText("=") numbers.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0 and query[^1] in "/*-+": query = "0" var calculated = parseQuery(query).calculate() query = $calculated text.setText(query) for i in 0..4: operators.addChild(operator_button.duplicate()) case i of 0: operators.getChild(i).ButtonRef.setText("DEL") operators.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0: query = query[0..^2] text.setText(query) of 1: operators.getChild(i).ButtonRef.setText("+") operators.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0: if query[^1] notin "-+/*": query &= "+" else: query = query[0..^2] & "+" text.setText(query) of 2: operators.getChild(i).ButtonRef.setText("−") operators.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0: if query[^1] notin "-+/*": query &= "-" else: query = query[0..^2] & "-" text.setText(query) of 3: operators.getChild(i).ButtonRef.setText("÷") operators.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0: if query[^1] notin "-+/*": query &= "/" else: query = query[0..^2] & "/" text.setText(query) else: operators.getChild(i).ButtonRef.setText("×") operators.getChild(i).ButtonRef@onClick(self, x, y): if query.len > 0: if query[^1] notin "-+/*": query &= "*" else: query = query[0..^2] & "*" text.setText(query) addMainScene(main) windowLaunch()