2019-01-19 11:31:04 +03:00

644 lines
15 KiB
Lua

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, 0x2D2D2D, 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, 0x3C3C3C))
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
screen.drawText(displayWidget.x, y, 0x696969, "\"")
screen.drawText(displayWidget.x + 1, y, 0xFFFFFF, charList.selectedItem == 1 and unicode.char(absValue) or (absValue < 256 and string.char(absValue) or "?"))
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, 0x969696, 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.lshift(math.floor(oldValue), math.floor(value))
end)
addAction(addBinaryButton(7, 5, "NOT"), function()
return bit32.bnot(math.floor(oldValue), math.floor(value))
end)
addAction(addBinaryButton(8, 5, "x>>y"), function()
return bit32.rshift(math.floor(oldValue), math.floor(value))
end)
--------------------------------------------------------------------
setValue(0)
modeList:getItem(2).onTouch()