MineOS/lib/ECSAPI.lua
2015-09-13 00:17:35 +03:00

2126 lines
69 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local component = require("component")
local term = require("term")
local unicode = require("unicode")
local event = require("event")
local fs = require("filesystem")
local shell = require("shell")
local keyboard = require("keyboard")
local computer = require("computer")
local fs = require("filesystem")
--local thread = require("thread")
local gpu = component.gpu
local screen = component.screen
local ECSAPI = {}
----------------------------------------------------------------------------------------------------
ECSAPI.windowColors = {
background = 0xeeeeee,
usualText = 0x444444,
subText = 0x888888,
tab = 0xaaaaaa,
title = 0xffffff,
shadow = 0x444444,
}
ECSAPI.colors = {
white = 0xF0F0F0,
orange = 0xF2B233,
magenta = 0xE57FD8,
lightBlue = 0x99B2F2,
yellow = 0xDEDE6C,
lime = 0x7FCC19,
pink = 0xF2B2CC,
gray = 0x4C4C4C,
lightGray = 0x999999,
cyan = 0x4C99B2,
purple = 0xB266E5,
blue = 0x3366CC,
brown = 0x7F664C,
green = 0x57A64E,
red = 0xCC4C4C,
black = 0x000000
}
----------------------------------------------------------------------------------------------------
--МАСШТАБ МОНИТОРА
function ECSAPI.setScale(scale, debug)
--КОРРЕКЦИЯ МАСШТАБА, ЧТОБЫ ВСЯКИЕ ДАУНЫ НЕ ДЕЛАЛИ ТОГО, ЧЕГО НЕ СЛЕДУЕТ
if scale > 1 then
scale = 1
elseif scale < 0.1 then
scale = 0.1
end
--Просчет пикселей в блоках кароч - забей, так надо
local function calculateAspect(screens)
local abc = 12
if screens == 2 then
abc = 28
elseif screens > 2 then
abc = 28 + (screens - 2) * 16
end
return abc
end
--Собсна, арсчет масштаба
local xScreens, yScreens = component.screen.getAspectRatio()
local xPixels, yPixels = calculateAspect(xScreens), calculateAspect(yScreens)
local proportion = xPixels / yPixels
--Костыль
local xMax, yMax = gpu.maxResolution()
xMax = yMax * 2
local newWidth, newHeight
if proportion >= 1 then
newWidth = math.floor(xMax * scale)
newHeight = math.floor(newWidth / proportion / 2)
else
newHeight = math.floor(yMax * scale)
newWidth = math.floor(newHeight * proportion * 2)
end
if debug then
print(" ")
print("Максимальное разрешение: "..xMax.."x"..yMax)
print("Пропорция монитора: "..xPixels.."x"..yPixels)
print(" ")
print("Новое разрешение: "..newWidth.."x"..newHeight)
print(" ")
end
gpu.setResolution(newWidth, newHeight)
end
--Сделать строку пригодной для отображения в ОпенКомпах
function ECSAPI.stringOptimize(sto4ka, indentatonWidth)
indentatonWidth = indentatonWidth or 2
sto4ka = string.gsub(sto4ka, "\r\n", "\n")
sto4ka = string.gsub(sto4ka, " ", string.rep(" ", indentatonWidth))
return stro4ka
end
--ИЗ ДЕСЯТИЧНОЙ В ШЕСТНАДЦАТИРИЧНУЮ
function ECSAPI.decToBase(IN,BASE)
local hexCode = "0123456789ABCDEFGHIJKLMNOPQRSTUVW"
OUT = ""
local ostatok = 0
while IN>0 do
ostatok = math.fmod(IN,BASE) + 1
IN = math.floor(IN/BASE)
OUT = string.sub(hexCode,ostatok,ostatok)..OUT
end
if #OUT == 1 then OUT = "0"..OUT end
if OUT == "" then OUT = "00" end
return OUT
end
--ИЗ 16 В РГБ
function ECSAPI.HEXtoRGB(color)
color = math.ceil(color)
local rr = bit32.rshift( color, 16 )
local gg = bit32.rshift( bit32.band(color, 0x00ff00), 8 )
local bb = bit32.band(color, 0x0000ff)
return rr, gg, bb
end
--ИЗ РГБ В 16
function ECSAPI.RGBtoHEX(rr, gg, bb)
return bit32.lshift(rr, 16) + bit32.lshift(gg, 8) + bb
end
--ИЗ ХСБ В РГБ
function ECSAPI.HSBtoRGB(h, s, v)
local rr, gg, bb = 0, 0, 0
local const = 255
s = s/100
v = v/100
local i = math.floor(h/60)
local f = h/60 - i
local p = v*(1-s)
local q = v*(1-s*f)
local t = v*(1-(1-f)*s)
if ( i == 0 ) then rr, gg, bb = v, t, p end
if ( i == 1 ) then rr, gg, bb = q, v, p end
if ( i == 2 ) then rr, gg, bb = p, v, t end
if ( i == 3 ) then rr, gg, bb = p, q, v end
if ( i == 4 ) then rr, gg, bb = t, p, v end
if ( i == 5 ) then rr, gg, bb = v, p, q end
return rr*const, gg*const, bb*const
end
--КЛИКНУЛИ ЛИ В ЗОНУ
function ECSAPI.clickedAtArea(x,y,sx,sy,ex,ey)
if (x >= sx) and (x <= ex) and (y >= sy) and (y <= ey) then return true end
return false
end
--ОЧИСТКА ЭКРАНА ЦВЕТОМ
function ECSAPI.clearScreen(color)
if color then gpu.setBackground(color) end
term.clear()
end
--ПРОСТОЙ СЕТПИКСЕЛЬ, ИБО ЗАЕБАЛО
function ECSAPI.setPixel(x,y,color)
gpu.setBackground(color)
gpu.set(x,y," ")
end
--ЦВЕТНОЙ ТЕКСТ
function ECSAPI.colorText(x,y,textColor,text)
gpu.setForeground(textColor)
gpu.set(x,y,text)
end
--ЦВЕТНОЙ ТЕКСТ С ЖОПКОЙ!
function ECSAPI.colorTextWithBack(x,y,textColor,backColor,text)
gpu.setForeground(textColor)
gpu.setBackground(backColor)
gpu.set(x,y,text)
end
--ИНВЕРСИЯ HEX-ЦВЕТА
function ECSAPI.invertColor(color)
return 0xffffff - color
end
--
--АДАПТИВНЫЙ ТЕКСТ, ПОДСТРАИВАЮЩИЙСЯ ПОД ФОН
function ECSAPI.adaptiveText(x,y,text,textColor)
gpu.setForeground(textColor)
x = x - 1
for i=1,unicode.len(text) do
local info = {gpu.get(x+i,y)}
gpu.setBackground(info[3])
gpu.set(x+i,y,unicode.sub(text,i,i))
end
end
--ИНВЕРТИРОВАННЫЙ ПО ЦВЕТУ ТЕКСТ НА ОСНОВЕ ФОНА
function ECSAPI.invertedText(x,y,symbol)
local info = {gpu.get(x,y)}
ECSAPI.adaptiveText(x,y,symbol,ECSAPI.invertColor(info[3]))
end
--АДАПТИВНОЕ ОКРУГЛЕНИЕ ЧИСЛА
function ECSAPI.adaptiveRound(chislo)
local celaya,drobnaya = math.modf(chislo)
if drobnaya >= 0.5 then
return (celaya + 1)
else
return celaya
end
end
--Округление до опред. кол-ва знаков после запятой
function ECSAPI.round(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
function ECSAPI.square(x,y,width,height,color)
gpu.setBackground(color)
gpu.fill(x,y,width,height," ")
end
function ECSAPI.border(x, y, width, height, back, fore)
local stringUp = ""..string.rep("", width - 2)..""
local stringDown = ""..string.rep("", width - 2)..""
gpu.setForeground(fore)
gpu.setBackground(back)
gpu.set(x, y, stringUp)
gpu.set(x, y + height - 1, stringDown)
local yPos = 1
for i = 1, (height - 2) do
gpu.set(x, y + yPos, "")
gpu.set(x + width - 1, y + yPos, "")
yPos = yPos + 1
end
end
function ECSAPI.separator(x, y, width, back, fore)
ECSAPI.colorTextWithBack(x, y, fore, back, string.rep("", width))
end
--АВТОМАТИЧЕСКОЕ ЦЕНТРИРОВАНИЕ ТЕКСТА ПО КООРДИНАТЕ
function ECSAPI.centerText(mode,coord,text)
local dlina = unicode.len(text)
local xSize,ySize = gpu.getResolution()
if mode == "x" then
gpu.set(math.floor(xSize/2-dlina/2),coord,text)
elseif mode == "y" then
gpu.set(coord,math.floor(ySize/2),text)
else
gpu.set(math.floor(xSize/2-dlina/2),math.floor(ySize/2),text)
end
end
--
function ECSAPI.drawCustomImage(x,y,pixels)
x = x - 1
y = y - 1
local pixelsWidth = #pixels[1]
local pixelsHeight = #pixels
local xEnd = x + pixelsWidth
local yEnd = y + pixelsHeight
for i=1,pixelsHeight do
for j=1,pixelsWidth do
if pixels[i][j][3] ~= "#" then
gpu.setBackground(pixels[i][j][1])
gpu.setForeground(pixels[i][j][2])
gpu.set(x+j,y+i,pixels[i][j][3])
end
end
end
return (x+1),(y+1),xEnd,yEnd
end
--КОРРЕКТИРОВКА СТАРТОВЫХ КООРДИНАТ
function ECSAPI.correctStartCoords(xStart,yStart,xWindowSize,yWindowSize)
local xSize,ySize = gpu.getResolution()
if xStart == "auto" then
xStart = math.floor(xSize/2 - xWindowSize/2)
end
if yStart == "auto" then
yStart = math.floor(ySize/2 - yWindowSize/2)
end
return xStart,yStart
end
--ЗАПОМНИТЬ ОБЛАСТЬ ПИКСЕЛЕЙ
function ECSAPI.rememberOldPixels(x, y, x2, y2)
local newPNGMassiv = { ["backgrounds"] = {} }
newPNGMassiv.x, newPNGMassiv.y = x, y
--Перебираем весь массив стандартного PNG-вида по высоте
local xCounter, yCounter = 1, 1
for j = y, y2 do
xCounter = 1
for i = x, x2 do
local symbol, fore, back = gpu.get(i, j)
newPNGMassiv["backgrounds"][back] = newPNGMassiv["backgrounds"][back] or {}
newPNGMassiv["backgrounds"][back][fore] = newPNGMassiv["backgrounds"][back][fore] or {}
table.insert(newPNGMassiv["backgrounds"][back][fore], {xCounter, yCounter, symbol} )
xCounter = xCounter + 1
back, fore, symbol = nil, nil, nil
end
yCounter = yCounter + 1
end
return newPNGMassiv
end
--НАРИСОВАТЬ ЗАПОМНЕННЫЕ ПИКСЕЛИ ИЗ МАССИВА
function ECSAPI.drawOldPixels(massivSudaPihay)
--Отнимаем разок
--massivSudaPihay.x, massivSudaPihay.y = massivSudaPihay.x - 1, massivSudaPihay.y - 1
--Перебираем массив с фонами
for back, backValue in pairs(massivSudaPihay["backgrounds"]) do
gpu.setBackground(back)
for fore, foreValue in pairs(massivSudaPihay["backgrounds"][back]) do
gpu.setForeground(fore)
for pixel = 1, #massivSudaPihay["backgrounds"][back][fore] do
if massivSudaPihay["backgrounds"][back][fore][pixel][3] ~= transparentSymbol then
gpu.set(massivSudaPihay.x + massivSudaPihay["backgrounds"][back][fore][pixel][1] - 1, massivSudaPihay.y + massivSudaPihay["backgrounds"][back][fore][pixel][2] - 1, massivSudaPihay["backgrounds"][back][fore][pixel][3])
end
end
end
end
end
--ОГРАНИЧЕНИЕ ДЛИНЫ СТРОКИ
function ECSAPI.stringLimit(mode, text, size, noDots)
if unicode.len(text) <= size then return text end
local length = unicode.len(text)
if mode == "start" then
if noDots then
return unicode.sub(text, length - size + 1, -1)
else
return "" .. unicode.sub(text, length - size + 2, -1)
end
else
if noDots then
return unicode.sub(text, 1, size)
else
return unicode.sub(text, 1, size - 1) .. ""
end
end
end
--ПОЛУЧИТЬ СПИСОК ФАЙЛОВ ИЗ КОНКРЕТНОЙ ДИРЕКТОРИИ
function ECSAPI.getFileList(path)
local list = fs.list(path)
local massiv = {}
for file in list do
--if string.find(file, "%/$") then file = unicode.sub(file, 1, -2) end
table.insert(massiv, file)
end
list = nil
return massiv
end
--ПОЛУЧИТЬ ВСЕ ДРЕВО ФАЙЛОВ
function ECSAPI.getFileTree(path)
local massiv = {}
local list = ECSAPI.getFileList(path)
for key, file in pairs(list) do
if fs.isDirectory(path.."/"..file) then
table.insert(massiv, getFileTree(path.."/"..file))
else
table.insert(massiv, file)
end
end
list = nil
return massiv
end
--ПОЛУЧЕНИЕ ФОРМАТА ФАЙЛА
function ECSAPI.getFileFormat(path)
local name = fs.name(path)
local starting, ending = string.find(name, "(.)%.[%d%w]*$")
if starting == nil then
return nil
else
return unicode.sub(name,starting + 1, -1)
end
name, starting, ending = nil, nil, nil
end
--ПРОВЕРКА, СКРЫТЫЙ ЛИ ФАЙЛ
function ECSAPI.isFileHidden(path)
local name = fs.name(path)
local starting, ending = string.find(name, "^%.(.*)$")
if starting == nil then
return false
else
return true
end
name, starting, ending = nil, nil, nil
end
--СКРЫТЬ РАСШИРЕНИЕ ФАЙЛА
function ECSAPI.hideFileFormat(path)
local name = fs.name(path)
local fileFormat = ECSAPI.getFileFormat(name)
if fileFormat == nil then
return name
else
return unicode.sub(name, 1, unicode.len(name) - unicode.len(fileFormat))
end
end
function ECSAPI.reorganizeFilesAndFolders(massivSudaPihay, showHiddenFiles)
showHiddenFiles = showHiddenFiles or true
local massiv = {}
for i = 1, #massivSudaPihay do
if ECSAPI.isFileHidden(massivSudaPihay[i]) then
table.insert(massiv, massivSudaPihay[i])
end
end
for i = 1, #massivSudaPihay do
local cyka = massivSudaPihay[i]
if fs.isDirectory(cyka) and not ECSAPI.isFileHidden(cyka) and ECSAPI.getFileFormat(massivSudaPihay[i]) ~= ".app" then
table.insert(massiv, massivSudaPihay[i])
end
cyka = nil
end
for i = 1, #massivSudaPihay do
local cyka = massivSudaPihay[i]
if (not fs.isDirectory(cyka) and not ECSAPI.isFileHidden(cyka)) or (fs.isDirectory(cyka) and not ECSAPI.isFileHidden(cyka) and ECSAPI.getFileFormat(massivSudaPihay[i]) == ".app") then
table.insert(massiv, massivSudaPihay[i])
end
cyka = nil
end
return massiv
end
--Бесполезна теперь, используй string.gsub()
function ECSAPI.stringReplace(stroka, chto, nachto)
local searchFrom = 1
while true do
local starting, ending = string.find(stroka, chto, searchFrom)
if starting then
stroka = unicode.sub(stroka, 1, starting - 1) .. nachto .. unicode.sub(stroka, ending + 1, -1)
searchFrom = ending + unicode.len(nachto) + 1
else
break
end
end
return stroka
end
--Ожидание клика либо нажатия какой-либо клавиши
function ECSAPI.waitForTouchOrClick()
while true do
local e = {event.pull()}
if e[1] == "key_down" or e[1] == "touch" then break end
end
end
----------------------------ОКОШЕЧКИ, СУКА--------------------------------------------------
--ECSAPI.windows = {}
function ECSAPI.drawButton(x,y,width,height,text,backColor,textColor)
x,y = ECSAPI.correctStartCoords(x,y,width,height)
local textPosX = math.floor(x + width / 2 - unicode.len(text) / 2)
local textPosY = math.floor(y + height / 2)
ECSAPI.square(x,y,width,height,backColor)
ECSAPI.colorText(textPosX,textPosY,textColor,text)
return x, y, (x + width - 1), (y + height - 1)
end
function ECSAPI.drawAdaptiveButton(x,y,offsetX,offsetY,text,backColor,textColor)
local length = unicode.len(text)
local width = offsetX*2 + length
local height = offsetY*2 + 1
x,y = ECSAPI.correctStartCoords(x,y,width,height)
ECSAPI.square(x,y,width,height,backColor)
ECSAPI.colorText(x+offsetX,y+offsetY,textColor,text)
return x,y,(x+width-1),(y+height-1)
end
function ECSAPI.windowShadow(x,y,width,height)
gpu.setBackground(ECSAPI.windowColors.shadow)
gpu.fill(x+width,y+1,2,height," ")
gpu.fill(x+1,y+height,width,1," ")
end
--Просто белое окошко безо всего
function ECSAPI.blankWindow(x,y,width,height)
local oldPixels = ECSAPI.rememberOldPixels(x,y,x+width+1,y+height)
ECSAPI.square(x,y,width,height,ECSAPI.windowColors.background)
ECSAPI.windowShadow(x,y,width,height)
return oldPixels
end
function ECSAPI.emptyWindow(x,y,width,height,title)
local oldPixels = ECSAPI.rememberOldPixels(x,y,x+width+1,y+height)
--ОКНО
gpu.setBackground(ECSAPI.windowColors.background)
gpu.fill(x,y+1,width,height-1," ")
--ТАБ СВЕРХУ
gpu.setBackground(ECSAPI.windowColors.tab)
gpu.fill(x,y,width,1," ")
--ТИТЛ
gpu.setForeground(ECSAPI.windowColors.title)
local textPosX = x + math.floor(width/2-unicode.len(title)/2) -1
gpu.set(textPosX,y,title)
--ТЕНЬ
ECSAPI.windowShadow(x,y,width,height)
return oldPixels
end
function ECSAPI.error(...)
local arg = {...}
local text = arg[1] or "С твоим компом опять хуйня"
local buttonText = arg[2] or "ОК"
local sText = unicode.len(text)
local xSize, ySize = gpu.getResolution()
local width = math.ceil(xSize * 3 / 5)
if (width - 11) > (sText) then width = 11 + sText end
local textLimit = width - 11
--Восклицательный знак
local image = {
{{0xff0000,0xffffff,"#"},{0xff0000,0xffffff,"#"},{0xff0000,0xffffff," "},{0xff0000,0xffffff,"#"},{0xff0000,0xffffff,"#"}},
{{0xff0000,0xffffff,"#"},{0xff0000,0xffffff," "},{0xff0000,0xffffff,"!"},{0xff0000,0xffffff," "},{0xff0000,0xffffff,"#"}},
{{0xff0000,0xffffff," "},{0xff0000,0xffffff," "},{0xff0000,0xffffff," "},{0xff0000,0xffffff," "},{0xff0000,0xffffff," "}}
}
--Парсинг строки ошибки
local parsedErr = {}
local countOfStrings = math.ceil(sText / textLimit)
for i=1, countOfStrings do
parsedErr[i] = unicode.sub(text, i * textLimit - textLimit + 1, i * textLimit)
end
--Расчет высоты
local height = 6
if #parsedErr > 1 then height = height + #parsedErr - 1 end
--Расчет позиции окна
local xStart,yStart = ECSAPI.correctStartCoords("auto","auto",width,height)
local xEnd,yEnd = xStart + width - 1, yStart + height - 1
--Рисуем окно
local oldPixels = ECSAPI.emptyWindow(xStart,yStart,width,height," ")
--Рисуем воскл знак
ECSAPI.drawCustomImage(xStart + 2,yStart + 2,image)
--Рисуем текст ошибки
gpu.setBackground(ECSAPI.windowColors.background)
gpu.setForeground(ECSAPI.windowColors.usualText)
local xPos, yPos = xStart + 9, yStart + 2
for i=1, #parsedErr do
gpu.set(xPos, yPos, parsedErr[i])
yPos = yPos + 1
end
--Рисуем кнопу
local xButton = xEnd - unicode.len(buttonText) - 7
local button = {ECSAPI.drawAdaptiveButton(xButton,yEnd - 1,3,0,buttonText,ECSAPI.colors.lightBlue,0xffffff)}
--Ждем
while true do
local e = {event.pull()}
if e[1] == "touch" then
if ECSAPI.clickedAtArea(e[3],e[4],button[1],button[2],button[3],button[4]) then
ECSAPI.drawAdaptiveButton(button[1],button[2],3,0,buttonText,ECSAPI.colors.blue,0xffffff)
os.sleep(0.4)
break
end
elseif e[1] == "key_down" and e[4] == 28 then
ECSAPI.drawAdaptiveButton(button[1],button[2],3,0,buttonText,ECSAPI.colors.blue,0xffffff)
os.sleep(0.4)
break
end
end
--Профит
ECSAPI.drawOldPixels(oldPixels)
end
function ECSAPI.prepareToExit(color1, color2)
ECSAPI.clearScreen(color1 or 0x333333)
gpu.setForeground(color2 or 0xffffff)
gpu.set(1, 1, "")
end
--А ЭТО КАРОЧ ИЗ ЮНИКОДА В СИМВОЛ - ВРОДЕ РАБОТАЕТ, НО ВСЯКОЕ БЫВАЕТ
function ECSAPI.convertCodeToSymbol(code)
local symbol
if code ~= 0 and code ~= 13 and code ~= 8 and code ~= 9 and code ~= 200 and code ~= 208 and code ~= 203 and code ~= 205 and not keyboard.isControlDown() then
symbol = unicode.char(code)
if keyboard.isShiftPressed then symbol = unicode.upper(symbol) end
end
return symbol
end
function ECSAPI.progressBar(x, y, width, height, background, foreground, percent)
local activeWidth = math.ceil(width * percent / 100)
ECSAPI.square(x, y, width, height, background)
ECSAPI.square(x, y, activeWidth, height, foreground)
end
--ВВОД ТЕКСТА ПО ЛИМИТУ ВО ВСЯКИЕ ПОЛЯ - УДОБНАЯ ШТУКА КАРОЧ
function ECSAPI.inputText(x, y, limit, cheBiloVvedeno, background, foreground, justDrawNotEvent, maskTextWith)
limit = limit or 10
cheBiloVvedeno = cheBiloVvedeno or ""
background = background or 0xffffff
foreground = foreground or 0x000000
gpu.setBackground(background)
gpu.setForeground(foreground)
gpu.fill(x, y, limit, 1, " ")
local text = cheBiloVvedeno
local function draw()
term.setCursorBlink(false)
local dlina = unicode.len(text)
local xCursor = x + dlina
if xCursor > (x + limit - 1) then xCursor = (x + limit - 1) end
if maskTextWith then
gpu.set(x, y, ECSAPI.stringLimit("start", string.rep("", dlina), limit))
else
gpu.set(x, y, ECSAPI.stringLimit("start", text, limit))
end
term.setCursor(xCursor, y)
term.setCursorBlink(true)
end
draw()
if justDrawNotEvent then term.setCursorBlink(false); return cheBiloVvedeno end
while true do
local e = {event.pull()}
if e[1] == "key_down" then
if e[4] == 14 then
term.setCursorBlink(false)
text = unicode.sub(text, 1, -2)
if unicode.len(text) < limit then gpu.set(x + unicode.len(text), y, " ") end
draw()
elseif e[4] == 28 then
term.setCursorBlink(false)
return text
else
local symbol = ECSAPI.convertCodeToSymbol(e[3])
if symbol then
text = text..symbol
draw()
end
end
elseif e[1] == "touch" then
term.setCursorBlink(false)
return text
end
end
end
function ECSAPI.selector(x, y, limit, cheBiloVvedeno, varianti, background, foreground, justDrawNotEvent)
local selectionHeight = #varianti
local oldPixels
local obj = {}
local function newObj(class, name, ...)
obj[class] = obj[class] or {}
obj[class][name] = {...}
end
local function drawPimpo4ka(color)
ECSAPI.colorTextWithBack(x + limit - 1, y, color, 0xffffff - color, "")
end
local function drawText(color)
gpu.setForeground(color)
gpu.set(x, y, ECSAPI.stringLimit("start", cheBiloVvedeno, limit - 1))
end
local function drawSelection()
local yPos = y + 1
oldPixels = ECSAPI.rememberOldPixels(x, yPos, x + limit + 1, yPos + selectionHeight + 1)
ECSAPI.windowShadow(x, yPos, limit, selectionHeight)
ECSAPI.square(x, yPos, limit, selectionHeight, background)
gpu.setForeground(foreground)
for i = 1, #varianti do
gpu.set(x, y + i, varianti[i])
newObj("selector", varianti[i], x, y + i, x + limit - 1)
end
end
ECSAPI.square(x, y, limit, 1, background)
drawText(foreground)
drawPimpo4ka(background - 0x555555)
if justDrawNotEvent then return cheBiloVvedeno end
drawPimpo4ka(0xffffff)
drawSelection()
while true do
local e = {event.pull()}
if e[1] == "touch" then
for key, val in pairs(obj["selector"]) do
if obj["selector"] and ECSAPI.clickedAtArea(e[3], e[4], obj["selector"][key][1], obj["selector"][key][2], obj["selector"][key][3], obj["selector"][key][2]) then
ECSAPI.square(x, obj["selector"][key][2], limit, 1, ECSAPI.colors.blue)
gpu.setForeground(0xffffff)
gpu.set(x, obj["selector"][key][2], key)
os.sleep(0.3)
ECSAPI.drawOldPixels(oldPixels)
cheBiloVvedeno = key
drawPimpo4ka(background - 0x555555)
ECSAPI.square(x, y, limit - 1, 1, background)
drawText(foreground)
return cheBiloVvedeno
end
end
end
end
end
function ECSAPI.input(x, y, limit, title, ...)
local obj = {}
local function newObj(class, name, ...)
obj[class] = obj[class] or {}
obj[class][name] = {...}
end
local activeData = 1
local data = {...}
local sizeOfTheLongestElement = 1
for i = 1, #data do
sizeOfTheLongestElement = math.max(sizeOfTheLongestElement, unicode.len(data[i][2]))
end
local width = 2 + sizeOfTheLongestElement + 2 + limit + 2
local height = 2 + #data * 2 + 2
--ПО ЦЕНТРУ ЭКРАНА, А ТО МАЛО ЛИ ЧЕ
x, y = ECSAPI.correctStartCoords(x, y, width, height)
local oldPixels = ECSAPI.rememberOldPixels(x, y, x + width + 1, y + height)
ECSAPI.emptyWindow(x, y, width, height, title)
local xPos, yPos
local function drawElement(i, justDrawNotEvent)
xPos = x + 2
yPos = y + i * 2
local color = 0x666666
if i == activeData then color = 0x000000 end
gpu.setBackground(ECSAPI.windowColors.background)
ECSAPI.colorText(xPos, yPos, color, data[i][2])
xPos = (x + width - 2 - limit)
local data1
if data[i][1] == "select" or data[i][1] == "selector" or data[i][1] == "selecttion" then
data1 = ECSAPI.selector(xPos, yPos, limit, data[i][3] or "", data[i][4] or {"What?", "Bad API use :("}, 0xffffff, color, justDrawNotEvent)
else
data1 = ECSAPI.inputText(xPos, yPos, limit, data[i][3] or "", 0xffffff, color, justDrawNotEvent)
end
newObj("elements", i, xPos, yPos, xPos + limit - 1)
return data1
end
local coodrs = { ECSAPI.drawAdaptiveButton(x + width - 10, y + height - 2, 3, 0, "OK", ECSAPI.colors.lightBlue, 0xffffff) }
newObj("OK", "OK", coodrs[1], coodrs[2], coodrs[3])
local function pressButton(press, press2)
if press then
ECSAPI.drawAdaptiveButton(obj["OK"]["OK"][1], obj["OK"]["OK"][2], 3, 0, "OK", press, press2)
else
ECSAPI.drawAdaptiveButton(obj["OK"]["OK"][1], obj["OK"]["OK"][2], 3, 0, "OK", ECSAPI.colors.lightBlue, 0xffffff)
end
end
local function drawAll()
gpu.setBackground(ECSAPI.windowColors.background)
for i = 1, #data do
drawElement(i, true)
end
if activeData > #data then
pressButton(ECSAPI.colors.blue, 0xffffff)
else
pressButton(false)
end
end
local function getMassiv()
local massiv = {}
for i = 1, #data do
table.insert(massiv, data[i][3])
end
return massiv
end
local function drawKaro4()
if activeData ~= -1 then data[activeData][3] = drawElement(activeData, false) end
end
------------------------------------------------------------------------------------------------
drawAll()
drawKaro4()
activeData = activeData + 1
drawAll()
while true do
local e = {event.pull()}
if e[1] == "key_down" then
if e[4] == 28 and activeData > #data then pressButton(false); os.sleep(0.2); pressButton(ECSAPI.colors.blue, 0xffffff); break end
if e[4] == 200 and activeData > 1 then activeData = activeData - 1; drawAll() end
if e[4] == 208 and activeData ~= -1 and activeData <= #data then activeData = activeData + 1; drawAll() end
if e[4] == 28 then
drawKaro4()
if activeData <= #data and activeData ~= -1 then activeData = activeData + 1 end
drawAll()
end
elseif e[1] == "touch" then
for key, val in pairs(obj["elements"]) do
if ECSAPI.clickedAtArea(e[3], e[4], obj["elements"][key][1], obj["elements"][key][2], obj["elements"][key][3], obj["elements"][key][2]) then
if key ~= activeData then activeData = key else drawKaro4(); if activeData <= #data then activeData = activeData + 1 end end
drawAll()
--activeData = key
--activeData = -1
--if activeData <= #data then activeData = activeData + 1 end
break
end
end
if ECSAPI.clickedAtArea(e[3], e[4], obj["OK"]["OK"][1], obj["OK"]["OK"][2], obj["OK"]["OK"][3], obj["OK"]["OK"][2]) then
if activeData > #data then
pressButton(false); os.sleep(0.2); pressButton(ECSAPI.colors.blue, 0xffffff)
else
pressButton(ECSAPI.colors.blue, 0xffffff)
os.sleep(0.3)
end
break
end
end
end
ECSAPI.drawOldPixels(oldPixels)
return getMassiv()
end
function ECSAPI.getHDDs()
local candidates = {}
for address in component.list("filesystem") do
local dev = component.proxy(address)
if not dev.isReadOnly() and dev.address ~= computer.tmpAddress() and fs.get(os.getenv("_")).address then
table.insert(candidates, dev)
end
end
return candidates
end
function ECSAPI.parseErrorMessage(error, translate)
local parsedError = {}
-- --ВСТАВКА ВСЕГО ГОВНА ДО ПЕРВОГО ЭНТЕРА
-- local starting, ending = string.find(error, "\n", 1)
-- table.insert(parsedError, unicode.sub(error, 1, ending or #error))
--ПОИСК ЭНТЕРОВ
local starting, ending, searchFrom = nil, nil, 1
for i = 1, unicode.len(error) do
starting, ending = string.find(error, "\n", searchFrom)
if starting then
table.insert(parsedError, unicode.sub(error, searchFrom, starting - 1))
searchFrom = ending + 1
else
break
end
end
--На всякий случай, если сообщение об ошибке без энтеров вообще, т.е. однострочное
if #parsedError == 0 and error ~= "" and error ~= nil and error ~= " " then
table.insert(parsedError, error)
end
--Замена /r/n и табсов
for i = 1, #parsedError do
parsedError[i] = string.gsub(parsedError[i], "\r\n", "\n")
parsedError[i] = string.gsub(parsedError[i], " ", " ")
end
if translate then
for i = 1, #parsedError do
parsedError[i] = string.gsub(parsedError[i], "interrupted", "Выполнение программы прервано пользователем")
parsedError[i] = string.gsub(parsedError[i], " got ", " получена ")
parsedError[i] = string.gsub(parsedError[i], " expected,", " ожидается,")
parsedError[i] = string.gsub(parsedError[i], "bad argument #", "Неверный аргумент №")
parsedError[i] = string.gsub(parsedError[i], "stack traceback", "Отслеживание ошибки")
parsedError[i] = string.gsub(parsedError[i], "tail calls", "Дочерние функции")
parsedError[i] = string.gsub(parsedError[i], "in function", "в функции")
parsedError[i] = string.gsub(parsedError[i], "in main chunk", "в основной программе")
parsedError[i] = string.gsub(parsedError[i], "unexpected symbol near", "неожиданный символ рядом с")
parsedError[i] = string.gsub(parsedError[i], "attempt to index", "несуществующий индекс")
parsedError[i] = string.gsub(parsedError[i], "attempt to get length of", "не удается получить длину")
parsedError[i] = string.gsub(parsedError[i], ": ", ", ")
parsedError[i] = string.gsub(parsedError[i], " module ", " модуль ")
parsedError[i] = string.gsub(parsedError[i], "not found", "не найден")
parsedError[i] = string.gsub(parsedError[i], "no field package.preload", "не найдена библиотека")
parsedError[i] = string.gsub(parsedError[i], "no file", "нет файла")
parsedError[i] = string.gsub(parsedError[i], "local", "локальной")
parsedError[i] = string.gsub(parsedError[i], "global", "глобальной")
parsedError[i] = string.gsub(parsedError[i], "no primary", "не найден компонент")
parsedError[i] = string.gsub(parsedError[i], "available", "в доступе")
parsedError[i] = string.gsub(parsedError[i], "attempt to concatenate", "не могу присоединить")
end
end
starting, ending = nil, nil
return parsedError
end
function ECSAPI.displayCompileMessage(y, reason, translate, withAnimation)
local xSize, ySize = gpu.getResolution()
--Переводим причину в массив
reason = ECSAPI.parseErrorMessage(reason, translate)
--Получаем ширину и высоту окошка
local width = math.floor(xSize * 7 / 10)
local height = #reason + 6
local textWidth = width - 11
--Просчет вот этой хуйни, аааахаахах
local difference = ySize - (height + y)
if difference < 0 then
for i = 1, (math.abs(difference) + 1) do
table.remove(reason, 1)
end
table.insert(reason, 1, "")
height = #reason + 6
end
local x = math.floor(xSize / 2 - width / 2)
--Иконочка воскл знака на красном фоне
local errorImage = {
{{0xff0000,0xffffff,"#"},{0xff0000,0xffffff,"#"},{0xff0000,0xffffff," "},{0xff0000,0xffffff,"#"},{0xff0000,0xffffff,"#"}},
{{0xff0000,0xffffff,"#"},{0xff0000,0xffffff," "},{0xff0000,0xffffff,"!"},{0xff0000,0xffffff," "},{0xff0000,0xffffff,"#"}},
{{0xff0000,0xffffff," "},{0xff0000,0xffffff," "},{0xff0000,0xffffff," "},{0xff0000,0xffffff," "},{0xff0000,0xffffff," "}}
}
--Запоминаем, че было отображено
local oldPixels = ECSAPI.rememberOldPixels(x, y, x + width + 1, y + height)
--Типа анимация, ога
if withAnimation then
for i = 1, height, 1 do
ECSAPI.square(x, y, width, i, ECSAPI.windowColors.background)
ECSAPI.windowShadow(x, y, width, i)
os.sleep(0.01)
end
else
ECSAPI.square(x, y, width, height, ECSAPI.windowColors.background)
ECSAPI.windowShadow(x, y, width, height)
end
--Рисуем воскл знак
ECSAPI.drawCustomImage(x + 2, y + 1, errorImage)
--Рисуем текст
local yPos = y + 1
local xPos = x + 9
gpu.setBackground(ECSAPI.windowColors.background)
ECSAPI.colorText(xPos, yPos, ECSAPI.windowColors.usualText, "Код ошибки:")
yPos = yPos + 2
gpu.setForeground( 0xcc0000 )
for i = 1, #reason do
gpu.set(xPos, yPos, ECSAPI.stringLimit("end", reason[i], textWidth))
yPos = yPos + 1
end
yPos = yPos + 1
ECSAPI.colorText(xPos, yPos, ECSAPI.windowColors.usualText, ECSAPI.stringLimit("end", "Нажмите любую клавишу, чтобы продолжить", textWidth))
--Пикаем звуком кароч
for i = 1, 3 do
computer.beep(1000)
end
--Ждем сам знаешь чего
ECSAPI.waitForTouchOrClick()
--Рисуем, че было нарисовано
ECSAPI.drawOldPixels(oldPixels)
end
function ECSAPI.select(x, y, title, textLines, buttons)
--Ну обжекты, хули
local obj = {}
local function newObj(class, name, ...)
obj[class] = obj[class] or {}
obj[class][name] = {...}
end
--Вычисление ширны на основе текста
local sizeOfTheLongestElement = 0
for i = 1, #textLines do
sizeOfTheLongestElement = math.max(sizeOfTheLongestElement, unicode.len(textLines[i][1]))
end
local width = sizeOfTheLongestElement + 4
--Вычисление ширины на основе размера кнопок
local buttonOffset = 2
local spaceBetweenButtons = 2
local sizeOfButtons = 0
for i = 1, #buttons do
sizeOfButtons = sizeOfButtons + unicode.len(buttons[i][1]) + buttonOffset * 2 + spaceBetweenButtons
end
--Финальное задание ширины и высоты
width = math.max(width, sizeOfButtons + 2)
local height = #textLines + 5
--Рисуем окно
x, y = ECSAPI.correctStartCoords(x, y, width, height)
local oldPixels = ECSAPI.emptyWindow(x, y, width, height, title)
--Рисуем текст
local xPos, yPos = x + 2, y + 2
gpu.setBackground(ECSAPI.windowColors.background)
for i = 1, #textLines do
ECSAPI.colorText(xPos, yPos, textLines[i][2] or ECSAPI.windowColors.usualText, textLines[i][1] or "Ну ты че, текст-то введи!")
yPos = yPos + 1
end
--Рисуем кнопочки
xPos, yPos = x + width - sizeOfButtons, y + height - 2
for i = 1, #buttons do
newObj("Buttons", buttons[i][1], ECSAPI.drawAdaptiveButton(xPos, yPos, buttonOffset, 0, buttons[i][1], buttons[i][2] or ECSAPI.colors.lightBlue, buttons[i][3] or 0xffffff))
xPos = xPos + buttonOffset * 2 + spaceBetweenButtons + unicode.len(buttons[i][1])
end
--Жмякаем на кнопочки
local action
while true do
if action then break end
local e = {event.pull()}
if e[1] == "touch" then
for key, val in pairs(obj["Buttons"]) do
if ECSAPI.clickedAtArea(e[3], e[4], obj["Buttons"][key][1], obj["Buttons"][key][2], obj["Buttons"][key][3], obj["Buttons"][key][4]) then
ECSAPI.drawAdaptiveButton(obj["Buttons"][key][1], obj["Buttons"][key][2], buttonOffset, 0, key, ECSAPI.colors.blue, 0xffffff)
os.sleep(0.3)
action = key
break
end
end
elseif e[1] == "key_down" then
if e[4] == 28 then
action = buttons[#buttons][1]
ECSAPI.drawAdaptiveButton(obj["Buttons"][action][1], obj["Buttons"][action][2], buttonOffset, 0, action, ECSAPI.colors.blue, 0xffffff)
os.sleep(0.3)
break
end
end
end
ECSAPI.drawOldPixels(oldPixels)
return action
end
function ECSAPI.askForReplaceFile(path)
if fs.exists(path) then
action = ECSAPI.select("auto", "auto", " ", {{"Файл \"".. fs.name(path) .. "\" уже имеется в этом месте."}, {"Заменить его перемещаемым объектом?"}}, {{"Оставить оба", 0xffffff, 0x000000}, {"Отмена", 0xffffff, 0x000000}, {"Заменить"}})
if action == "Оставить оба" then
return "keepBoth"
elseif action == "Отмена" then
return "cancel"
else
return "replace"
end
end
end
-- --Копирование файлов для операционки
-- function ECSAPI.copy(from, to)
-- local name = fs.name(from)
-- local toName = to.."/"..name
-- local action = ECSAPI.askForReplaceFile(toName)
-- if action == nil or action == "replace" then
-- fs.remove(toName)
-- if fs.isDirectory(from) then
-- ECSAPI.error("Копирование папок отключено во избежание перегрузки файловой системы. Мод говно, смирись.")
-- else
-- fs.copy(from, toName)
-- end
-- elseif action == "keepBoth" then
-- if fs.isDirectory(from) then
-- ECSAPI.error("Копирование папок отключено во избежание перегрузки файловой системы. Мод говно, смирись.")
-- else
-- fs.copy(from, fs.path(toName) .. "/(copy)"..fs.name(toName))
-- end
-- end
-- end
--Переименование файлов для операционки
function ECSAPI.rename(mainPath)
local name = fs.name(mainPath)
path = fs.path(mainPath)
--Рисуем окошко ввода нового имени файла
local inputs = ECSAPI.input("auto", "auto", 20, " ", {"input", "Новое имя", name})
--Если ввели в окошко хуйню какую-то
if inputs[1] == "" or inputs[1] == " " or inputs[1] == nil then
ECSAPI.error("Неверное имя файла.")
else
--Получаем новый путь к новому файлу
local newPath = path..inputs[1]
--Если файл с новым путем уже существует
if fs.exists(newPath) then
ECSAPI.error("Файл \"".. name .. "\" уже имеется в этом месте.")
return
else
fs.rename(mainPath, newPath)
end
end
end
--Простое информационное окошечко
function ECSAPI.info(x, y, title, text)
x = x or "auto"
y = y or "auto"
title = title or " "
text = text or "Sample text"
local width = unicode.len(text) + 4
local height = 4
x, y = ECSAPI.correctStartCoords(x, y, width, height)
local oldPixels = ECSAPI.rememberOldPixels(x, y, x + width + 1, y + height)
ECSAPI.emptyWindow(x, y, width, height, title)
ECSAPI.colorTextWithBack(x + 2, y + 2, ECSAPI.windowColors.usualText, ECSAPI.windowColors.background, text)
return oldPixels
end
--Скроллбар вертикальный
function ECSAPI.srollBar(x, y, width, height, countOfAllElements, currentElement, backColor, frontColor)
local sizeOfScrollBar = math.ceil(1 / countOfAllElements * height)
local displayBarFrom = math.floor(y + height * ((currentElement - 1) / countOfAllElements))
ECSAPI.square(x, y, width, height, backColor)
ECSAPI.square(x, displayBarFrom, width, sizeOfScrollBar, frontColor)
sizeOfScrollBar, displayBarFrom = nil, nil
end
--Поле с текстом. Сюда пихать массив вида {"строка1", "строка2", "строка3", ...}
function ECSAPI.textField(x, y, width, height, lines, displayFrom, background, foreground, scrollbarBackground, scrollbarForeground)
x, y = ECSAPI.correctStartCoords(x, y, width, height)
background = background or 0xffffff
foreground = foreground or ECSAPI.windowColors.usualText
local sLines = #lines
local lineLimit = width - 3
--Парсим строки
local line = 1
while lines[line] do
local sLine = unicode.len(lines[line])
if sLine > lineLimit then
local part1, part2 = unicode.sub(lines[line], 1, lineLimit), unicode.sub(lines[line], lineLimit + 1, -1)
lines[line] = part1
table.insert(lines, line + 1, part2)
part1, part2 = nil, nil
end
line = line + 1
sLine = nil
end
line = nil
ECSAPI.square(x, y, width - 1, height, background)
ECSAPI.srollBar(x + width - 1, y, 1, height, sLines, displayFrom, scrollbarBackground, scrollbarForeground)
gpu.setBackground(background)
gpu.setForeground(foreground)
local yPos = y
for i = displayFrom, (displayFrom + height - 1) do
if lines[i] then
gpu.set(x + 1, yPos, lines[i])
yPos = yPos + 1
else
break
end
end
return sLines
end
function ECSAPI.beautifulInput(x, y, width, title, buttonText, back, fore, otherColor, autoRedraw, ...)
if not width or width < 30 then width = 30 end
data = {...}
local sData = #data
local height = 3 + sData * 3 + 1
x, y = ECSAPI.correctStartCoords(x, y, width, height)
local xCenter = math.floor(x + width / 2 - 1)
local oldPixels = ECSAPI.rememberOldPixels(x, y, x + width - 1, y + height + 2)
--Рисуем фон
ECSAPI.square(x, y, width, height, back)
--ECSAPI.windowShadow(x, y, width, height)
local xText = x + 3
local inputLimit = width - 6
--Авторизация
ECSAPI.drawButton(x, y, width, 3, title, back, fore)
local fields
local function drawData()
local i = y + 4
fields = {}
for j = 1, sData do
ECSAPI.border(x + 1, i - 1, width - 2, 3, back, fore)
if data[j][3] == "" or not data[j][3] or data[j][3] == " " then
ECSAPI.colorTextWithBack(xText, i, fore, back, data[j][1])
else
if data[j][2] then
ECSAPI.inputText(xText, i, inputLimit, data[j][3], back, fore, true, true)
else
ECSAPI.inputText(xText, i, inputLimit, data[j][3], back, fore, true)
end
end
table.insert(fields, { x + 1, i - 1, x + inputLimit - 1, i + 1 })
i = i + 3
end
end
local function getData()
local massiv = {}
for i = 1, sData do
table.insert(massiv, data[i][3])
end
return massiv
end
drawData()
--Нижняя кнопа
local button = { ECSAPI.drawButton(x, y + sData * 3 + 4, width, 3, buttonText, otherColor, fore) }
while true do
local e = {event.pull()}
if e[1] == "touch" then
if ECSAPI.clickedAtArea(e[3], e[4], button[1], button[2], button[3], button[4]) then
ECSAPI.drawButton(button[1], button[2], width, 3, buttonText, ECSAPI.colors.blue, 0xffffff)
os.sleep(0.3)
if autoRedraw then ECSAPI.drawOldPixels(oldPixels) end
return getData()
end
for key, val in pairs(fields) do
if ECSAPI.clickedAtArea(e[3], e[4], fields[key][1], fields[key][2], fields[key][3], fields[key][4]) then
ECSAPI.border(fields[key][1], fields[key][2], width - 2, 3, back, otherColor)
data[key][3] = ECSAPI.inputText(xText, fields[key][2] + 1, inputLimit, "", back, fore, false, data[key][2])
--ECSAPI.border(fields[key][1], fields[key][2], width - 2, 3, back, fore)
drawData()
break
end
end
elseif e[1] == "key_down" then
if e[4] == 28 then
ECSAPI.drawButton(button[1], button[2], width, 3, buttonText, ECSAPI.colors.blue, 0xffffff)
os.sleep(0.3)
if autoRedraw then ECSAPI.drawOldPixels(oldPixels) end
return getData()
end
end
end
end
function ECSAPI.beautifulSelect(x, y, width, title, buttonText, back, fore, otherColor, autoRedraw, ...)
if not width or width < 30 then width = 30 end
data = {...}
local sData = #data
local height = 3 + sData * 3 + 1
x, y = ECSAPI.correctStartCoords(x, y, width, height)
local xCenter = math.floor(x + width / 2 - 1)
local oldPixels = ECSAPI.rememberOldPixels(x, y, x + width - 1, y + height + 2)
--Рисуем фон
ECSAPI.square(x, y, width, height, back)
local xText = x + 3
local inputLimit = width - 9
--Первая кнопа
ECSAPI.drawButton(x, y, width, 3, title, back, fore)
--Нижняя кнопа
local button = { ECSAPI.drawButton(x, y + sData * 3 + 4, width, 3, buttonText, otherColor, fore) }
local fields
local selectedData = 1
local symbol = ""
--Рисуем данные
local function drawData()
local i = y + 4
fields = {}
for j = 1, sData do
--Квадратик для галочки
ECSAPI.border(x + 1, i - 1, 5, 3, back, fore)
--Галочку рисуем или снимаем
local text = " "
if j == selectedData then text = symbol end
ECSAPI.colorText(x + 3, i, otherColor, text)
ECSAPI.colorText(x + 7, i, fore, ECSAPI.stringLimit("end", data[j], inputLimit))
table.insert(fields, { x + 1, i - 1, x + inputLimit - 1, i + 1 })
i = i + 3
end
end
drawData()
while true do
local e = {event.pull()}
if e[1] == "touch" then
if ECSAPI.clickedAtArea(e[3], e[4], button[1], button[2], button[3], button[4]) then
ECSAPI.drawButton(button[1], button[2], width, 3, buttonText, ECSAPI.colors.blue, 0xffffff)
os.sleep(0.3)
if autoRedraw then ECSAPI.drawOldPixels(oldPixels) end
return data[selectedData]
end
for key, val in pairs(fields) do
if ECSAPI.clickedAtArea(e[3], e[4], fields[key][1], fields[key][2], fields[key][3], fields[key][4]) then
selectedData = key
drawData()
break
end
end
elseif e[1] == "key_down" then
if e[4] == 28 then
ECSAPI.drawButton(button[1], button[2], width, 3, buttonText, ECSAPI.colors.blue, 0xffffff)
os.sleep(0.3)
if autoRedraw then ECSAPI.drawOldPixels(oldPixels) end
return data[selectedData]
end
end
end
end
--Получение верного имени языка. Просто для безопасности.
function ECSAPI.getCorrectLangName(pathToLangs)
local language = _OSLANGUAGE .. ".lang"
if not fs.exists(pathToLangs .. "/" .. language) then
language = "English.lang"
end
return language
end
--Чтение языкового файла
function ECSAPI.readCorrectLangFile(pathToLangs)
local lang
local language = ECSAPI.getCorrectLangName(pathToLangs)
lang = config.readAll(pathToLangs .. "/" .. language)
return lang
end
----------------------------------------------------------------------------------------------------------------
--Создать ярлык для конкретной проги
function ECSAPI.createShortCut(path, pathToProgram)
fs.remove(path)
fs.makeDirectory(fs.path(path))
local file = io.open(path, "w")
file:write("return ", "\"", pathToProgram, "\"")
file:close()
end
--Получить данные о файле из ярлыка
function ECSAPI.readShortcut(path)
local success, filename = pcall(loadfile(path))
if success then
return filename
else
error("Ошибка чтения файла ярлыка. Вероятно, он создан криво, либо не существует в папке " .. path)
end
end
-- Копирование папки через рекурсию, т.к. fs.copy() не поддерживает папки
-- Ну долбоеб автор мода - хули я тут сделаю? Придется так вот
-- swg2you, привет маме ;)
function ECSAPI.copyFolder(path, toPath)
local function doCopy(path)
local fileList = ecs.getFileList(path)
for i = 1, #fileList do
if fs.isDirectory(path..fileList[i]) then
doCopy(path..fileList[i])
else
fs.makeDirectory(toPath..path)
fs.copy(path..fileList[i], toPath ..path.. fileList[i])
end
end
end
toPath = fs.path(toPath)
doCopy(path.."/")
end
--Копирование файлов для операционки
function ECSAPI.copy(from, to)
local name = fs.name(from)
local toName = to .. "/" .. name
local action = ECSAPI.askForReplaceFile(toName)
if action == nil or action == "replace" then
fs.remove(toName)
if fs.isDirectory(from) then
ECSAPI.copyFolder(from, toName)
else
fs.copy(from, toName)
end
elseif action == "keepBoth" then
if fs.isDirectory(from) then
ECSAPI.copyFolder(from, to .. "/(copy)" .. name)
else
fs.copy(from, to .. "/(copy)" .. name)
end
end
end
ECSAPI.OSIconsWidth = 12
ECSAPI.OSIconsHeight = 6
--Вся необходимая информация для иконок
local function OSIconsInit()
if not ECSAPI.OSIcons then
--Константы для иконок
ECSAPI.OSIcons = {}
ECSAPI.pathToIcons = "System/OS/Icons/"
--Иконки
ECSAPI.OSIcons.folder = image.load(ECSAPI.pathToIcons .. "Folder.png")
ECSAPI.OSIcons.script = image.load(ECSAPI.pathToIcons .. "Script.png")
ECSAPI.OSIcons.text = image.load(ECSAPI.pathToIcons .. "Text.png")
ECSAPI.OSIcons.config = image.load(ECSAPI.pathToIcons .. "Config.png")
ECSAPI.OSIcons.lua = image.load(ECSAPI.pathToIcons .. "Lua.png")
ECSAPI.OSIcons.image = image.load(ECSAPI.pathToIcons .. "Image.png")
ECSAPI.OSIcons.imageJPG = image.load(ECSAPI.pathToIcons .. "ImageJPG.png")
ECSAPI.OSIcons.pastebin = image.load(ECSAPI.pathToIcons .. "Pastebin.png")
ECSAPI.OSIcons.fileNotExists = image.load(ECSAPI.pathToIcons .. "FileNotExists.png")
end
end
--Отрисовка одной иконки
function ECSAPI.drawOSIcon(x, y, path, showFileFormat, nameColor)
--Инициализируем переменные иконок. Чисто для уменьшения расхода оперативки.
OSIconsInit()
--Получаем формат файла
local fileFormat = ECSAPI.getFileFormat(path)
--Создаем пустую переменную для конкретной иконки, для ее типа
local icon
--Если данный файл является папкой, то
if fs.isDirectory(path) then
if fileFormat == ".app" then
icon = path .. "/Resources/Icon.png"
--Если данной иконки еще нет в оперативке, то загрузить ее
if not ECSAPI.OSIcons[icon] then
ECSAPI.OSIcons[icon] = image.load(icon)
end
else
icon = "folder"
end
else
if fileFormat == ".lnk" then
local shortcutLink = ECSAPI.readShortcut(path)
ECSAPI.drawOSIcon(x, y, shortcutLink, showFileFormat)
--Стрелочка
ECSAPI.colorTextWithBack(x + ECSAPI.OSIconsWidth - 4, y + ECSAPI.OSIconsHeight - 3, 0x000000, 0xffffff, "")
return 0
elseif fileFormat == ".cfg" or fileFormat == ".config" then
icon = "config"
elseif fileFormat == ".txt" or fileFormat == ".rtf" then
icon = "text"
elseif fileFormat == ".lua" then
icon = "lua"
elseif fileFormat == ".png" then
icon = "image"
elseif fileFormat == ".jpg" then
icon = "imageJPG"
elseif fileFormat == ".paste" then
icon = "pastebin"
elseif not fs.exists(path) then
icon = "fileNotExists"
else
icon = "script"
end
end
--Рисуем иконку
image.draw(x + 2, y, ECSAPI.OSIcons[icon])
--Делаем текст для иконки
local text = fs.name(path)
if not showFileFormat then
if fileFormat then
text = unicode.sub(text, 1, -(unicode.len(fileFormat) + 1))
end
end
text = ECSAPI.stringLimit("end", text, ECSAPI.OSIconsWidth)
--Рассчитываем позицию текста
local textPos = x + math.floor(ECSAPI.OSIconsWidth / 2 - unicode.len(text) / 2)
--Рисуем текст под иконкой
ECSAPI.adaptiveText(textPos, y + ECSAPI.OSIconsHeight - 1, text, nameColor or 0xffffff)
end
--ЗАПУСТИТЬ ПРОГУ
function ECSAPI.launchIcon(path, arguments)
--Запоминаем, какое разрешение было
local oldWidth, oldHeight = gpu.getResolution()
--Создаем нормальные аргументы для Шелла
if arguments then arguments = " " .. arguments else arguments = "" end
--Получаем файл формат заранее
local fileFormat = ECSAPI.getFileFormat(path)
--Если это приложение
if fileFormat == ".app" then
ECSAPI.prepareToExit()
local cyka = path .. "/" .. ECSAPI.hideFileFormat(fs.name(path)) .. ".lua"
local success, reason = shell.execute(cyka)
ECSAPI.prepareToExit()
if not success then ECSAPI.displayCompileMessage(1, reason, true) end
--Если это обычный луа файл - т.е. скрипт
elseif fileFormat == ".lua" or fileFormat == nil then
ECSAPI.prepareToExit()
local success, reason = shell.execute(path .. arguments)
ECSAPI.prepareToExit()
if success then
print("Program sucessfully executed. Press any key to continue.")
else
ECSAPI.displayCompileMessage(1, reason, true)
end
--Если это фоточка
elseif fileFormat == ".png" then
shell.execute("Photoshop.app/Photoshop.lua open "..path)
--Если это фоточка
elseif fileFormat == ".jpg" then
shell.execute("Photoshop.app/Photoshop.lua open "..path)
--Если это текст или конфиг или языковой
elseif fileFormat == ".txt" or fileFormat == ".cfg" or fileFormat == ".lang" then
ECSAPI.prepareToExit()
shell.execute("edit "..path)
--Если это ярлык
elseif fileFormat == ".lnk" then
local shortcutLink = ECSAPI.readShortcut(path)
if fs.exists(shortcutLink) then
ECSAPI.launchIcon(shortcutLink)
else
ECSAPI.error("File from shortcut link doesn't exists.")
end
--Если это ссылка на пастебин
elseif fileFormat == ".paste" then
local shortcutLink = ECSAPI.readShortcut(path)
ECSAPI.prepareToExit()
local success, reason = shell.execute("pastebin run " .. shortcutLink)
if success then
print(" ")
print("Program sucessfully executed. Press any key to continue.")
ECSAPI.waitForTouchOrClick()
else
ECSAPI.displayCompileMessage(1, reason, false)
end
end
--Ставим старое разрешение
gpu.setResolution(oldWidth, oldHeight)
end
--ECSAPI.drawOSIcon(2, 2, "Pastebin1.app", true)
----------------------------------------------------------------------------------------------------------------
--Описание ниже, ебана
function ECSAPI.universalWindow(x, y, width, background, closeWindowAfter, ...)
local objects = {...}
local countOfObjects = #objects
local pressedButton
--Задаем высотные константы для объектов
local objectsHeights = {
["button"] = 3,
["centertext"] = 1,
["emptyline"] = 1,
["input"] = 3,
["slider"] = 3,
["select"] = 3,
["selector"] = 3,
["separator"] = 1,
}
--Считаем высоту этой хуйни
local height = 0
for i = 1, countOfObjects do
local objectType = string.lower(objects[i][1])
if objectType == "select" then
height = height + (objectsHeights[objectType] * (#objects[i] - 3))
elseif objectType == "textfield" then
height = height + objects[i][2]
else
height = height + objectsHeights[objectType]
end
end
--Нужные стартовые прелесссти
x, y = ECSAPI.correctStartCoords(x, y, width, height)
local oldPixels = ECSAPI.rememberOldPixels(x, y, x + width - 1, y + height - 1)
--Считаем все координаты объектов
objects[1].y = y
if countOfObjects > 1 then
for i = 2, countOfObjects do
local objectType = string.lower(objects[i - 1][1])
if objectType == "select" then
objects[i].y = objects[i - 1].y + (objectsHeights[objectType] * (#objects[i - 1] - 3))
elseif objectType == "textfield" then
objects[i].y = objects[i - 1].y + objects[i - 1][2]
else
objects[i].y = objects[i - 1].y + objectsHeights[objectType]
end
end
end
--Объекты для тача
local obj = {}
local function newObj(class, name, ...)
obj[class] = obj[class] or {}
obj[class][name] = {...}
end
--Отображение объекта по номеру
local function displayObject(number, active)
local objectType = string.lower(objects[number][1])
if objectType == "button" then
local back, fore, text = objects[number][2], objects[number][3], objects[number][4]
if active then
newObj("Buttons", number, ECSAPI.drawButton(x, objects[number].y, width, objectsHeights.button, text, fore, back))
else
newObj("Buttons", number, ECSAPI.drawButton(x, objects[number].y, width, objectsHeights.button, text, back, fore))
end
elseif objectType == "centertext" then
local xPos = x + math.floor(width / 2 - unicode.len(objects[number][3]) / 2)
gpu.setForeground(objects[number][2])
gpu.set(xPos, objects[number].y, objects[number][3])
elseif objectType == "input" then
if active then
--Рамочка
ECSAPI.border(x + 1, objects[number].y, width - 2, objectsHeights.input, background, objects[number][3])
--Тестик
objects[number][4] = ECSAPI.inputText(x + 3, objects[number].y + 1, width - 6, "", background, objects[number][3], false, objects[number][5])
else
--Рамочка
ECSAPI.border(x + 1, objects[number].y, width - 2, objectsHeights.input, background, objects[number][2])
--Текстик
gpu.set(x + 3, objects[number].y + 1, ECSAPI.stringLimit("start", objects[number][4], width - 6))
end
newObj("Inputs", number, x + 1, objects[number].y, x + width - 2, objects[number].y + 2)
elseif objectType == "slider" then
local widthOfSlider = width - 2
local xOfSlider = x + 1
local yOfSlider = objects[number].y + 1
local countOfSliderThings = objects[number][5] - objects[number][4]
local showSliderValue = objects[number][7]
local dolya = widthOfSlider / countOfSliderThings
local position = math.floor(dolya * objects[number][6])
--Костыль
if (xOfSlider + position) > (xOfSlider + widthOfSlider - 1) then position = widthOfSlider - 2 end
--Две линии
ECSAPI.separator(xOfSlider, yOfSlider, position, background, objects[number][3])
ECSAPI.separator(xOfSlider + position, yOfSlider, widthOfSlider - position, background, objects[number][2])
--Слудир
ECSAPI.square(xOfSlider + position, yOfSlider, 2, 1, objects[number][3])
--Текстик под слудиром
if showSliderValue then
local text = showSliderValue .. tostring(objects[number][6])
local textPos = (xOfSlider + widthOfSlider / 2 - unicode.len(text) / 2)
ECSAPI.square(x, yOfSlider + 1, width, 1, background)
ECSAPI.colorText(textPos, yOfSlider + 1, objects[number][2], text)
end
newObj("Sliders", number, xOfSlider, yOfSlider, x + widthOfSlider, yOfSlider, dolya)
elseif objectType == "select" then
local usualColor = objects[number][2]
local selectionColor = objects[number][3]
objects[number].selectedData = objects[number].selectedData or 1
local symbol = ""
local yPos = objects[number].y
for i = 4, #objects[number] do
--Коробка для галочки
ECSAPI.border(x + 1, yPos, 5, 3, background, usualColor)
--Текст
gpu.set(x + 7, yPos + 1, objects[number][i])
--Галочка
if objects[number].selectedData == (i - 3) then
ECSAPI.colorText(x + 3, yPos + 1, selectionColor, symbol)
else
gpu.set(x + 3, yPos + 1, " ")
end
obj["Selects"] = obj["Selects"] or {}
obj["Selects"][number] = obj["Selects"][number] or {}
obj["Selects"][number][i - 3] = { x + 1, yPos, x + width - 2, yPos + 2 }
yPos = yPos + objectsHeights.select
end
elseif objectType == "selector" then
local borderColor = objects[number][2]
local arrowColor = objects[number][3]
local selectorWidth = width - 2
objects[number].selectedElement = objects[number].selectedElement or objects[number][4]
local topLine = "" .. string.rep("", selectorWidth - 6) .. "┬───┐"
local midLine = "" .. string.rep(" ", selectorWidth - 6) .. "│ │"
local botLine = "" .. string.rep("", selectorWidth - 6) .. "┴───┘"
local yPos = objects[number].y
local function bordak(borderColor)
gpu.setBackground(background)
gpu.setForeground(borderColor)
gpu.set(x + 1, objects[number].y, topLine)
gpu.set(x + 1, objects[number].y + 1, midLine)
gpu.set(x + 1, objects[number].y + 2, botLine)
gpu.set(x + 3, objects[number].y + 1, ECSAPI.stringLimit("start", objects[number].selectedElement, width - 6))
ECSAPI.colorText(x + width - 4, objects[number].y + 1, arrowColor, "")
end
bordak(borderColor)
--Выпадающий список, самый гемор, блядь
if active then
local xPos, yPos = x + 2, objects[number].y + 3
local spisokWidth = width - 4
local countOfElements = #objects[number] - 3
local spisokHeight = countOfElements
local oldPixels = ECSAPI.rememberOldPixels( xPos, yPos, xPos + spisokWidth - 1, yPos + spisokHeight - 1)
local coords = {}
bordak(arrowColor)
--Белый фоник рисуем-с
ECSAPI.square( xPos, yPos, spisokWidth, spisokHeight, 0xffffff )
xPos = xPos + 1
for i = 1, countOfElements do
ECSAPI.colorText(xPos, yPos, 0x000000, ECSAPI.stringLimit("start", objects[number][i + 3], spisokWidth - 2))
coords[i] = {xPos - 1, yPos, xPos + spisokWidth - 1, yPos}
yPos = yPos + 1
end
--Обработка
local exit
while true do
if exit then break end
local e = {event.pull()}
if e[1] == "touch" then
for i = 1, #coords do
if ECSAPI.clickedAtArea(e[3], e[4], coords[i][1], coords[i][2], coords[i][3], coords[i][4]) then
ECSAPI.square(coords[i][1], coords[i][2], spisokWidth, 1, ECSAPI.colors.blue)
ECSAPI.colorText(coords[i][1] + 1, coords[i][2], 0xffffff, objects[number][i + 3])
os.sleep(0.3)
objects[number].selectedElement = objects[number][i + 3]
exit = true
break
end
end
end
end
ECSAPI.drawOldPixels(oldPixels)
end
newObj("Selectors", number, x + 1, objects[number].y, x + width - 2, objects[number].y + 2)
elseif objectType == "separator" then
ECSAPI.separator(x, objects[number].y, width, background, objects[number][2])
elseif objectType == "textfield" then
objects[number].displayFrom = objects[number].displayFrom or 1
ECSAPI.textField(x + 1, objects[number].y, width - 2, objects[number][2], objects[number][7], objects[number].displayFrom, objects[number][3], objects[number][4], objects[number][5], objects[number][6])
end
end
--Отображение всех объектов
local function displayAllObjects()
for i = 1, countOfObjects do
displayObject(i)
end
end
--Подготовить массив возвращаемый
local function getReturn()
local massiv = {}
for i = 1, countOfObjects do
local type = string.lower(objects[i][1])
if type == "button" then
table.insert(massiv, pressedButton)
elseif type == "input" then
table.insert(massiv, objects[i][4])
elseif type == "select" then
table.insert(massiv, objects[i].selectedData)
elseif type == "selector" then
table.insert(massiv, objects[i].selectedElement)
elseif type == "slider" then
table.insert(massiv, objects[i][6])
else
table.insert(massiv, nil)
end
end
return massiv
end
--Рисуем окно
ECSAPI.square(x, y, width, height, background)
displayAllObjects()
while true do
local e = {event.pull()}
if e[1] == "touch" or event == "drag" then
--ECSAPI.error("x1 = "..obj["Buttons"][3][1]..", y1 = "..obj["Buttons"][3][2]..", e3 = "..e[3]..", e4 = "..e[4])
--Анализируем клик на кнопки
if obj["Buttons"] then
for key in pairs(obj["Buttons"]) do
if ECSAPI.clickedAtArea(e[3], e[4], obj["Buttons"][key][1], obj["Buttons"][key][2], obj["Buttons"][key][3], obj["Buttons"][key][4]) then
displayObject(key, true)
os.sleep(0.3)
pressedButton = objects[key][4]
if closeWindowAfter then ECSAPI.drawOldPixels(oldPixels) end
return getReturn()
end
end
end
--А теперь клик на инпуты!
if obj["Inputs"] then
for key in pairs(obj["Inputs"]) do
if ECSAPI.clickedAtArea(e[3], e[4], obj["Inputs"][key][1], obj["Inputs"][key][2], obj["Inputs"][key][3], obj["Inputs"][key][4]) then
displayObject(key, true)
displayObject(key)
break
end
end
end
--А теперь галочковыбор!
if obj["Selects"] then
for key in pairs(obj["Selects"]) do
for i in pairs(obj["Selects"][key]) do
if ECSAPI.clickedAtArea(e[3], e[4], obj["Selects"][key][i][1], obj["Selects"][key][i][2], obj["Selects"][key][i][3], obj["Selects"][key][i][4]) then
objects[key].selectedData = i
displayObject(key)
break
end
end
end
end
--Хм, а вот и селектор подъехал!
if obj["Selectors"] then
for key in pairs(obj["Selectors"]) do
if ECSAPI.clickedAtArea(e[3], e[4], obj["Selectors"][key][1], obj["Selectors"][key][2], obj["Selectors"][key][3], obj["Selectors"][key][4]) then
displayObject(key, true)
displayObject(key)
break
end
end
end
--Слайдеры, епта! "Потный матан", все делы
if obj["Sliders"] then
for key in pairs(obj["Sliders"]) do
if ECSAPI.clickedAtArea(e[3], e[4], obj["Sliders"][key][1], obj["Sliders"][key][2], obj["Sliders"][key][3], obj["Sliders"][key][4]) then
local xOfSlider, dolya = obj["Sliders"][key][1], obj["Sliders"][key][5]
local currentPixels = e[3] - xOfSlider
local currentValue = math.floor(currentPixels / dolya)
--Костыль
if e[3] == obj["Sliders"][key][3] then currentValue = objects[key][5] end
objects[key][6] = currentValue
displayObject(key)
break
end
end
end
end
end
end
--local strings = {"Hello world! This is a test string and I'm so happy to show it!", "Awesome! It works!", "Cool!"}
-- ECSAPI.prepareToExit()
-- --ECSAPI.universalWindow("auto", "auto", 30, ECSAPI.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, "Хелло пидар!"}, {"EmptyLine"}, {"Input", 0x262626, 0x000000, "Суда вводи"}, {"Selector", 0x262626, 0x880000, "PNG", "JPG", "PSD"}, {"Slider", 0x262626, 0x880000, 0, 100, 50}, {"Select", 0x262626, 0x880000, "Выбор1", "Выбор2"}, {"EmptyLine"}, {"Button", 0xbbbbbb, 0xffffff, "Ok!"})
-- local data = ECSAPI.universalWindow("auto", "auto", 30, ECSAPI.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, "Хелло пидар!"}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, "Суда вводи"}, {"Selector", 0x262626, 0x880000, "PNG", "JPG", "PSD"}, {"Slider", 0x262626, 0x880000, 0, 100, 50, "Количество: "}, {"Select", 0x262626, 0x880000, "Выбор1", "Выбор2"}, {"EmptyLine"}, {"Button", 0xbbbbbb, 0xffffff, "Ok!"})
-- ECSAPI.prepareToExit()
-- print(table.unpack(data))
--[[
Функция universalWindow(x, y, width, background, closeWindowAfter, ...)
Это универсальная модульная функция для максимально удобного и быстрого
отображения необходимой вам информации. С ее помощью вводить данные
с клавиатуры, осуществлять выбор из предложенных вариантов, рисовать
красивые кнопки, отрисовывать обычный текст, отрисовывать текстовые
поля с возможностью прокрутки, рисовать разделители и прочее.
Любой объект выделяется с помощью клика мыши, после чего функция
приступает к работе с этим объектом.
Аргументы функции:
x и y:
Это числа, обозначающие стартовые координаты левого верхнего угла
данного окна.
Вместо цифр вы также можете написать "auto" - и программа
автоматически разместит окно по центру экрана по выбранной
координате. Или по обеим координатам, если вам угодно.
width:
Это ширина окна, которую вы можете задать по собственному желанию.
Если некторые объекты требуют расширения окна, то окно будет
автоматически расширено до нужной ширины. Да, вот такая вот тавтология ;)
background:
Базовый цвет окна (цвет фона, кому как понятнее).
closeWindowAfter:
Если true, то окно по завершению функции будет выгружено, а на его месте отрисуются пиксели,
которые имелись на экране до выполнения функции. Удобно, если не хочешь париться
с перерисовкой интерфейса.
...:
Многоточием тут является перечень объектов, указанных через запятую.
Каждый объект является массивом и имеет собственный формат.
Ниже перечислены все типы объектов:
{"Button", Цвет кнопки, Цвет текста на кнопке, Сам текст}
{"Selector", Цвет рамки, Цвет стрелки, Выбор 1, Выбор 2, Выбор 3 ...}
{"Input", Цвет рамки и текста, Цвет при выделении, Стартовый текст, Маскировать символом}
{"Select", Цвет рамки, Цвет галочки, Выбор 1, Выбор 2, Выбор 3 ...}
{"TextField", Высота, Цвет фона, Цвет текста, Цвет скроллбара, Цвет пимпочки скроллбара, Массив со строками}
{"CenterText", Цвет текста, Сам текст}
{"Separator", Цвет разделителя}
{"Slider", Цвет линии слайдера, Цвет пимпочки слайдера, Значения слайдера ОТ, Значения слайдера ДО, Текущее значение, Текст-подсказка}
{"Switch", Цвет актива, Цвет пассива, Цвет текста, Текст, Изначальное состояние}
{"EmptyLine"}
Каждый из объектов рисуется по порядку сверху вниз. Каждый объект автоматически
увеличивает высоту окна до необходимого значения.
Что возвращает функция:
Возвратом является массив, пронумерованный от 1 до <количества объектов>.
К примеру, 1 индекс данного массива соответствует 1 указанному объекту.
Каждый индекс данного массива несет в себе какие-то данные, которые вы
внесли в объект во время работы функции.
Например, если в 1-ый объект типа "Input" вы ввели фразу "Hello world",
то первый индекс в возвращенном массиве будет равен "Hello world".
Конкретнее это будет вот так: massiv[1] = "Hello world".
Если взаимодействие с объектом невозможно - например, как с EmptyLine или
CenterText, то в возвращенном массиве этот элемент будет равен nil.
Готовые примеры использования функции:
]]
----------------------------------------------------------------------------------------------------
return ECSAPI