mirror of
https://github.com/IgorTimofeev/MineOS.git
synced 2025-12-20 19:19:21 +01:00
2105 lines
68 KiB
Lua
2105 lines
68 KiB
Lua
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.rename(mainPath)
|
||
local name = fs.name(mainPath)
|
||
path = fs.path(mainPath)
|
||
|
||
--Рисуем окошко ввода нового имени файла
|
||
local inputs = ECSAPI.universalWindow("auto", "auto", 30, ECSAPI.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, "Переименовать"}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, name}, {"EmptyLine"}, {"Button", 0xbbbbbb, 0xffffff, "Ok!"})
|
||
|
||
--Если ввели в окошко хуйню какую-то
|
||
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 = ECSAPI.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
|
||
|
||
|
||
|
||
|