local GUI = require("GUI") local system = require("System") local color = require("Color") local screen = require("Screen") local paths = require("Paths") -------------------------------------------------------------------- local buttonWidth = 7 local buttonHeight = 3 local displayHeight = 5 local binaryHeight = 8 local value = 0 local memory = 0 local absValue local oldValue local action local binaryButtons = {} local digitHexadecimalButtons = {} local digitOctalButtons = {} local digitDecimalButtons = {} -------------------------------------------------------------------- local workspace, window, menu = system.addWindow(GUI.window(1, 1, buttonWidth * 12, buttonHeight * 5 + displayHeight + binaryHeight)) local displayContainer = window:addChild(GUI.container(1, 1, window.width, displayHeight + binaryHeight)) local displayPanel = displayContainer:addChild(GUI.panel(1, 1, window.width, displayHeight, 0x1E1E1E, 0.1)) local actionButtons = window:addChild(GUI.actionButtons(3, 3, true)) actionButtons.close.onTouch = function() window:remove() end actionButtons.minimize.onTouch = function() window:minimize() end local binaryPanel = displayContainer:addChild(GUI.panel(1, displayHeight + 1, window.width, binaryHeight, 0x2D2D2D)) local binaryLayout = displayContainer:addChild(GUI.layout(1, displayHeight + 2, window.width, binaryHeight, 1, 1)) binaryLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP) binaryLayout:setSpacing(1, 1, 0) local binaryListsLayout = binaryLayout:addChild(GUI.layout(1, 1, binaryLayout.width, 1, 1, 1)) binaryListsLayout:setSpacing(1, 1, 2) binaryListsLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP) binaryListsLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL) binaryLayout:addChild(GUI.object(1, 1, 1, 1)) local function addBinaryLayoutList(width) local list = binaryListsLayout:addChild(GUI.list(1, 1, width, 1, 2, 0, 0x5A5A5A, 0xE1E1E1, 0x5A5A5A, 0xE1E1E1, 0xE1E1E1, 0x5A5A5A, true)) list:setDirection(GUI.DIRECTION_HORIZONTAL) return list end -- local binaryPanelButton = binaryListsLayout:addChild(GUI.adaptiveButton(1, 1, 2, 0, 0x5A5A5A, 0xD2D2D2, 0xE1E1E1, 0x5A5A5A, "Binary panel")) -- binaryPanelButton.switchMode = true local charList = addBinaryLayoutList(18) charList:addItem("UTF-8") charList:addItem("ASCII") local degereeList = addBinaryLayoutList(14) degereeList:addItem("RAD") degereeList:addItem("DEG") local floatingList = addBinaryLayoutList(16) floatingList:addItem("INT") floatingList:addItem("FRACT") table.insert(digitDecimalButtons, floatingList) local modeList = addBinaryLayoutList(17) modeList.selectedItem = 2 local displayWidget = displayContainer:addChild(GUI.object(10, 1, window.width - 12, displayHeight)) local function parseFloat(v) v = tostring(v) local integer, fractional = v:match("(.+)%.(.+)") if integer then return integer, fractional else return v, "0" end end local function isNumber(v) return v ~= "inf" and v ~= "-inf" and v ~= "nan" end local function format(v) local integer, fractional = parseFloat(v) if not isNumber(integer) then return integer elseif modeList.selectedItem == 1 then return string.format("%o", integer) elseif modeList.selectedItem == 2 then return integer .. "." .. fractional, #integer else return string.format("0x%X", integer) end end displayWidget.draw = function() local x, y = displayWidget.x + displayWidget.width, displayWidget.y + 2 local result, integerLength = format(value) -- Result x = x - #result screen.drawText(x, y, 0xFFFFFF, result) -- Digit mode if modeList.selectedItem == 2 and integerLength then if floatingList.selectedItem == 1 then screen.drawText(x, y + 1, 0x696969, string.rep("─", integerLength)) else screen.drawText(x + integerLength + 1, y + 1, 0x696969, string.rep("─", #result - integerLength - 1)) end end -- Action and old value if oldValue then local oldValueText = format(oldValue) .. " " .. action.button.text .. " " screen.drawText(x - #oldValueText, y, 0xA5A5A5, oldValueText) end -- Char local char = charList.selectedItem == 1 and (absValue <= 0x10FFFF and unicode.char(absValue) or "?") or (absValue <= 0xFF and string.char (absValue) or "?") screen.drawText(displayWidget.x, y, 0x696969, "\"") screen.drawText(displayWidget.x + 1, y, 0xFFFFFF, char) screen.drawText(displayWidget.x + 2, y, 0x696969, "\"") end local function setValueRaw(v) value, absValue = v, math.floor(math.abs(v)) end local function numberToBinary() for i = 1, #binaryButtons do binaryButtons[i].text = "0" end local i, copy = #binaryButtons, absValue while copy > 0 do binaryButtons[i].text = tostring(bit32.band(copy, 1)) copy = bit32.rshift(copy, 1) i = i - 1 end end local function setValue(v) setValueRaw(v) numberToBinary() end local function setButtonsDisabled(array, state) for i = 1, #array do array[i].disabled = state end end modeList:addItem("8").onTouch = function() setButtonsDisabled(digitOctalButtons, true) setButtonsDisabled(digitDecimalButtons, true) setButtonsDisabled(digitHexadecimalButtons, true) floatingList.selectedItem = 1 setValue(math.floor(value)) workspace:draw() end modeList:addItem("10").onTouch = function() setButtonsDisabled(digitOctalButtons, false) setButtonsDisabled(digitDecimalButtons, false) setButtonsDisabled(digitHexadecimalButtons, true) workspace:draw() end modeList:addItem("16").onTouch = function() setButtonsDisabled(digitOctalButtons, false) setButtonsDisabled(digitDecimalButtons, true) setButtonsDisabled(digitHexadecimalButtons, false) floatingList.selectedItem = 1 setValue(math.floor(value)) workspace:draw() end local function binaryToNumber() local firstNotNullBitIndex = 0 for i = 1, #binaryButtons do if binaryButtons[i].text == "1" then firstNotNullBitIndex = i break end end local number = 1 for i = firstNotNullBitIndex + 1, #binaryButtons do number = bit32.bor(bit32.lshift(number, 1), binaryButtons[i].text == "1" and 1 or 0) end setValueRaw(number) end local function addBinaryButtonsRowLayout() local layout = binaryLayout:addChild(GUI.layout(1, 1, binaryLayout.width, 2, 1, 1)) layout:setSpacing(1, 1, 3) layout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP) layout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL) return layout end local function addBinaryButtonsContainer(row, leftText, rightText) local container = row:addChild(GUI.container(1, 1, 15, 2)) local x = 1 for i = 1, 8 do local button = container:addChild(GUI.button(x, 1, 1, 1, nil, 0x696969, nil, 0xFFFFFF, "0")) button.onTouch = function() button.text = button.text == "0" and "1" or "0" binaryToNumber() end table.insert(binaryButtons, button) x = x + 2 end container:addChild(GUI.text(1, 2, 0xE1E1E1, leftText)) container:addChild(GUI.text(container.width - #rightText + 1, 2, 0xE1E1E1, rightText)) end local row1 = addBinaryButtonsRowLayout() addBinaryButtonsContainer(row1, "64", "57") addBinaryButtonsContainer(row1, "56", "49") addBinaryButtonsContainer(row1, "48", "41") addBinaryButtonsContainer(row1, "40", "33") local row2 = addBinaryButtonsRowLayout() addBinaryButtonsContainer(row2, "32", "25") addBinaryButtonsContainer(row2, "24", "17") addBinaryButtonsContainer(row2, "16", "9") addBinaryButtonsContainer(row2, "8", "1") local buttonsContainer = window:addChild(GUI.container(1, displayContainer.height + 1, window.width, window.height - displayContainer.height)) local function addButton(x, y, c1, c2, c3, c4, text, onTouch, width, height) local button = buttonsContainer:addChild(GUI.button( (x - 1) * buttonWidth + 1, (y - 1) * buttonHeight + 1, (width or 1) * buttonWidth, (height or 1) * buttonHeight, c1, c2, c3, c4, text )) button.onTouch = onTouch button.colors.disabled.background = c1 button.colors.disabled.text = 0xB4B4B4 return button end local function addEngineerButton(x, y, ...) return addButton(x, y, 0xD2D2D2, 0x2D2D2D, 0xB4B4B4, 0x2D2D2D, ...) end local function addBinaryButton(x, y, ...) return addButton(x, y, 0xE1E1E1, 0x2D2D2D, 0xB4B4B4, 0x2D2D2D, ...) end local function addRegularButton(x, y, ...) return addButton(x, y, 0xF0F0F0, 0x2D2D2D, 0xB4B4B4, 0x2D2D2D, ...) end local function addMathButton(x, y, ...) return addButton(x, y, 0xFF9240, 0xFFFFFF, 0xCC6D00, 0xFFFFFF, ...) end local function onDigitPressed(digit) if modeList.selectedItem == 1 then setValue(tonumber(string.format("%o", value) .. digit, 8)) elseif modeList.selectedItem == 2 then local integer, fractional = parseFloat(value) if isNumber(integer) then if floatingList.selectedItem == 1 then setValue(tonumber(integer .. digit .. "." .. fractional)) else setValue(tonumber(integer .. "." .. (fractional == "0" and "" or fractional) .. digit)) end end else setValue(math.floor(value) * 16 + digit) end end local function reset() oldValue = nil floatingList.selectedItem = 1 if action then action.button.pressed = false action = nil end end local function getActionResult() setValue(action.getResult()) end local function addAction(button, getResult) button.switchMode = true button.onTouch = function() -- Если уже имеется какое-то действие if action then -- Если мы повторно жмякаем на ранее нажатую кнопку if action.button == button then button.pressed = true -- Отжимаем кнопку другого действия, если она была ранее нажата else action.button.pressed = false end getActionResult() end oldValue = value setValue(0) floatingList.selectedItem = 1 action = { button = button, getResult = getResult } end end local function getDegree(v) return degereeList.selectedItem == 1 and v or math.rad(v) end -------------------------------------------------------------------- -- Digits row 1 addRegularButton(9, 1, "C", function() setValue(0) reset() end) addRegularButton(10, 1, "CE", function() setValue(0) end) addRegularButton(11, 1, "%", function() value = value / 100 if action then getActionResult() reset() else setValue(value) end end) addAction(addMathButton(12, 1, "/"), function() return oldValue / value end) -- Digits row 2 addRegularButton(9, 2, "7", function() onDigitPressed(7) end) table.insert(digitOctalButtons, addRegularButton(10, 2, "8", function() onDigitPressed(8) end)) table.insert(digitOctalButtons, addRegularButton(11, 2, "9", function() onDigitPressed(9) end)) addAction(addMathButton(12, 2, "*"), function() return oldValue * value end) -- Digits row 3 for i = 4, 6 do addRegularButton(i + 5, 3, tostring(i), function() onDigitPressed(i) end) end addAction(addMathButton(12, 3, "-"), function() return oldValue - value end) -- Digits row 4 for i = 1, 3 do addRegularButton(i + 8, 4, tostring(i), function() onDigitPressed(i) end) end addAction(addMathButton(12, 4, "+"), function() return oldValue + value end) -- Digits row 5 addRegularButton(9, 5, "0", function() onDigitPressed(0) end) table.insert(digitDecimalButtons, addRegularButton(10, 5, ".", function() floatingList.selectedItem = floatingList.selectedItem == 1 and 2 or 1 end)) addRegularButton(11, 5, "+-", function() setValue(-value) end) addMathButton(12, 5, "=", function() if action then getActionResult() reset() end end) -------------------------------------------------------------------- -- Engineer row 1 addEngineerButton(1, 1, "mc", function() memory = 0 end) addEngineerButton(2, 1, "m+", function() memory = memory + value end) addEngineerButton(3, 1, "m-", function() memory = memory - value end) addEngineerButton(4, 1, "mr", function() setValue(memory) reset() end) addEngineerButton(5, 1, "rnd", function() setValue(math.random()) reset() end) -- Engineer row 2 addEngineerButton(1, 2, "x^2", function() setValue(value ^ 2) reset() end) addAction(addEngineerButton(2, 2, "x^y"), function() return oldValue ^ value end) addEngineerButton(3, 2, "√x", function() setValue(math.sqrt(value)) reset() end) addAction(addEngineerButton(4, 2, "y√x"), function() return oldValue ^ (1 / value) end) addEngineerButton(5, 2, "x!", function() local fact = 1 for i = 2, absValue do fact = fact * i end setValue(fact) reset() end) -- Engineer row 3 addEngineerButton(1, 3, "sin", function() setValue(math.sin(getDegree(value))) reset() end) addEngineerButton(2, 3, "cos", function() setValue(math.cos(getDegree(value))) reset() end) addEngineerButton(3, 3, "tan", function() setValue(math.tan(getDegree(value))) reset() end) addEngineerButton(4, 3, "1/x", function() setValue(1 / value) reset() end) addAction(addEngineerButton(5, 3, "e^x"), function() return math.exp(value) end) -- Engineer row 4 addEngineerButton(1, 4, "asin", function() setValue(math.asin(getDegree(value))) reset() end) addEngineerButton(2, 4, "acos", function() setValue(math.acos(getDegree(value))) reset() end) addEngineerButton(3, 4, "atan", function() setValue(math.atan(getDegree(value))) reset() end) addAction(addEngineerButton(4, 4, "log"), function() return math.log(oldValue, value) end) addAction(addEngineerButton(5, 4, "mod"), function() return oldValue % value end) -- Engineer row 5 addEngineerButton(1, 5, "sinh", function() setValue(math.sinh(getDegree(value))) reset() end) addEngineerButton(2, 5, "cosh", function() setValue(math.cosh(getDegree(value))) reset() end) addEngineerButton(3, 5, "tanh", function() setValue(math.tanh(getDegree(value))) reset() end) addEngineerButton(4, 5, "e", function() setValue(2.718281828459045) reset() end) addEngineerButton(5, 5, "π", function() setValue(math.pi) reset() end) -------------------------------------------------------------------- -- Binary row 1 table.insert(digitHexadecimalButtons, addBinaryButton(6, 1, "D", function() onDigitPressed(0xD) end)) table.insert(digitHexadecimalButtons, addBinaryButton(7, 1, "E", function() onDigitPressed(0xE) end)) table.insert(digitHexadecimalButtons, addBinaryButton(8, 1, "F", function() onDigitPressed(0xF) end)) -- Binary row 2 table.insert(digitHexadecimalButtons, addBinaryButton(6, 2, "A", function() onDigitPressed(0xA) end)) table.insert(digitHexadecimalButtons, addBinaryButton(7, 2, "B", function() onDigitPressed(0xB) end)) table.insert(digitHexadecimalButtons, addBinaryButton(8, 2, "C", function() onDigitPressed(0xC) end)) -- Binary row 3 addAction(addBinaryButton(6, 3, "AND"), function() return bit32.band(math.floor(oldValue), math.floor(value)) end) addAction(addBinaryButton(7, 3, "OR"), function() return bit32.bor(math.floor(oldValue), math.floor(value)) end) addAction(addBinaryButton(8, 3, "XOR"), function() return bit32.bxor(math.floor(oldValue), math.floor(value)) end) -- Binary row 4 addAction(addBinaryButton(6, 4, "NOR"), function() return bit32.bnot(bit32.bor(math.floor(oldValue), math.floor(value))) end) addAction(addBinaryButton(7, 4, "ROL"), function() return bit32.lrotate(math.floor(oldValue), math.floor(value)) end) addAction(addBinaryButton(8, 4, "ROR"), function() return bit32.rrotate(math.floor(oldValue), math.floor(value)) end) -- Binary row 5 addAction(addBinaryButton(6, 5, "x<>y"), function() return bit32.rshift(math.floor(oldValue), math.floor(value)) end) -------------------------------------------------------------------- setValue(0) modeList:getItem(2).onTouch()