-- a simple calculator require("keys") require("logger") calc = {} calc.value = "" calc.buttons = { {"log", "exp", "pi", "(",")","^","/"}, {"sin", "cos", "tan", "7","8","9","*"}, {"asin","acos", "atan","4","5","6","-"}, {"abs", "floor","ceil","1","2","3","+"}, {"sqrt","%", ",", "0",".","C","="} } calc.row = 5 calc.col = 4 calc.rows = #(calc.buttons) calc.cols = #(calc.buttons[1]) calc.font = FONT.LARGE calc.border = COLOR.gray(75) calc.background = COLOR.gray(5) calc.foreground = COLOR.WHITE calc.highlight = COLOR.BLUE calc.error_forground = COLOR.RED calc.pad = 20 calc.cell_size = calc.pad * 2 + calc.font.height calc.height = (calc.rows + 1) * calc.cell_size calc.width = (calc.cols) * calc.cell_size calc.left = display.width // 2 - calc.width // 2 calc.top = display.height // 2 - calc.height // 2 calc.error = false calc.mlmenu = menu.new { name = "Calculator", help = "A simple calculator in Lua", select = function(this) task.create(function() calc:run() end) end, update = function(this) return calc.value end } -- The main program loop function calc:run() local status, error = xpcall(function() menu.block(true) self:main_loop() end, debug.traceback) if status == false then handle_error(error) end menu.block(false) keys:stop() end function calc:main_loop() menu.block(true) self:draw() keys:start() while true do if menu.visible == false then break end local key = keys:getkey() if key ~= nil then if self:handle_key(key) == false then break end self:draw() end task.yield(100) end keys:stop() if self.running == false then menu.block(false) end end function calc:handle_key(key) if key == KEY.Q or key == KEY.MENU then return false elseif key == KEY.UP or key == KEY.WHEEL_UP then self.row = dec(self.row,1,self.rows) elseif key == KEY.DOWN or key == KEY.WHEEL_DOWN then self.row = inc(self.row,1,self.rows) elseif key == KEY.LEFT or key == KEY.WHEEL_LEFT then self.col = dec(self.col,1,self.cols) elseif key == KEY.RIGHT or key == KEY.WHEEL_RIGHT then self.col = inc(self.col,1,self.cols) elseif key == KEY.INFO then self:handle_button("C") elseif key == KEY.PLAY then self:handle_button("=") elseif key == KEY.SET then self:handle_button(self.buttons[self.row][self.col]) end end function calc:handle_button(c) if self.error or type(self.value) ~= "string" then self.value = "" end self.error = false if c == "C" then self.value = "" elseif c == "=" then local status,result = pcall(load,"return "..self.value) if status == false or result == nil then self.error = true self.value = "syntax error" else status,self.value = pcall(result) if self.status == false or self.value == nil then self.error = true self.value = "syntax error" else self.value = tostring(self.value) end end else self.value = self.value..c if #c > 2 then self.value = self.value.."(" end end end function calc:draw() display.draw(function() display.rect(self.left-4,self.top-4,self.width+8,self.height+8,self.border,self.border) display.rect(self.left,self.top,self.width,self.cell_size,self.border,self.background) local fg = self.foreground if self.error then fg = self.error_forground end display.print(tostring(self.value),self.left + self.pad,self.top + self.pad,self.font,fg,self.background, self.width - self.pad * 2) for i=1,self.rows,1 do local row = self.buttons[i] for j=1,self.cols,1 do local c = row[j] local x = self.left + (j - 1) * self.cell_size local y = self.top + i * self.cell_size local bg = self.background if i == self.row and j == self.col then bg = self.highlight end display.rect(x,y,self.cell_size,self.cell_size,self.border,bg) local pad = self.cell_size // 2 - self.font:width(c) // 2 display.print(c,x + pad, y + self.pad,self.font,self.border,bg) end end end) end --export all the math functions to the global namespace for k,v in pairs(math) do if k ~= "type" then _G[k] = v end end function inc(val,min,max) if val == max then return min end if val < min then return min end return val + 1 end function dec(val,min,max) if val == min then return max end if val > max then return max end return val - 1 end function handle_error(error) if error == nil then error = "Unknown Error!\n" end local f = FONT.MONO_20 display.rect(0,0,display.width,display.height,COLOR.RED,COLOR.BLACK) local pos = 10 for line in error:gmatch("[^\r\n]+") do local clipped = display.print(line,10,pos,f) while clipped ~= nil do pos = pos + f.height clipped = display.print(clipped,10,pos,f) end pos = pos + f.height end local log = logger("CALC.ERR") log:write(error) log:close() keys:anykey() end