if not _G.buffer then _G.buffer = require("doubleBuffering") end if not _G.ecs then _G.ecs = require("ECSAPI") end if not _G.unicode then _G.unicode = require("unicode") end local GUI = {} ---------------------------------------------------- Универсальные методы -------------------------------------------------------- GUI.directions = { horizontal = 0, vertical = 1, } GUI.buttonTypes = { default = 0, adaptive = 1, framedDefault = 2, framedAdaptive = 3, } -- Универсальный метод для проверки клика на прямоугольный объект local function clickedAtObject(object, x, y) if x >= object.x and y >= object.y and x <= object.x + object.width - 1 and y <= object.y + object.height - 1 then return true end return false end --Создание базового примитива-объекта function GUI.object(x, y, width, height) return { x = x, y = y, width = width, height = height, isClicked = clickedAtObject, } end ---------------------------------------------------- Кнопки -------------------------------------------------------------------- -- Универсальынй метод-рисоватор кнопки local function drawButton(buttonObject, isPressed) local textLength = unicode.len(buttonObject.text) if textLength > buttonObject.width then buttonObject.text = unicode.sub(buttonObject.text, 1, buttonObject.width) end local xText = math.floor(buttonObject.x + buttonObject.width / 2 - textLength / 2) local yText = math.floor(buttonObject.y + buttonObject.height / 2) local buttonColor = isPressed and buttonObject.colors.pressed.button or buttonObject.colors.default.button local textColor = isPressed and buttonObject.colors.pressed.text or buttonObject.colors.default.text if buttonObject.type == GUI.buttonTypes.default or buttonObject.type == GUI.buttonTypes.adaptive then buffer.square(buttonObject.x, buttonObject.y, buttonObject.width, buttonObject.height, buttonColor, textColor, " ") buffer.text(xText, yText, textColor, buttonObject.text) elseif buttonObject.type == GUI.buttonTypes.framedDefault or buttonObject.type == GUI.buttonTypes.framedAdaptive then buffer.frame(buttonObject.x, buttonObject.y, buttonObject.width, buttonObject.height, buttonColor) buffer.text(xText, yText, textColor, buttonObject.text) end end -- Метод-нажиматор кнопки local function pressButton(buttonObject, pressTime) drawButton(buttonObject, true) buffer.draw() os.sleep(pressTime or 0.2) drawButton(buttonObject, false) buffer.draw() end -- Создание таблицы кнопки со всеми необходимыми параметрами local function createButtonObject(buttonType, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text) local buttonObject = GUI.object(x, y, width, height) buttonObject.colors = { default = { button = buttonColor, text = textColor }, pressed = { button = buttonPressedColor, text = textPressedColor }, } buttonObject.type = buttonType buttonObject.text = text buttonObject.press = pressButton buttonObject.draw = drawButton return buttonObject end -- Кнопка фиксированных размеров function GUI.button(x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text) local buttonObject = createButtonObject(GUI.buttonTypes.default, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text) buttonObject:draw() return buttonObject end -- Кнопка, подстраивающаяся под размер текста function GUI.adaptiveButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text) local buttonObject = createButtonObject(GUI.buttonTypes.adaptive, x, y, xOffset * 2 + unicode.len(text), yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text) buttonObject:draw() return buttonObject end -- Кнопка в рамке function GUI.framedButton(x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text) local buttonObject = createButtonObject(GUI.buttonTypes.framedDefault, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text) buttonObject:draw() return buttonObject end -- Кнопка в рамке, подстраивающаяся под размер текста function GUI.adaptiveFramedButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text) local buttonObject = createButtonObject(GUI.buttonTypes.framedAdaptive, x, y, xOffset * 2 + unicode.len(text), yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text) buttonObject:draw() return buttonObject end -- Вертикальный или горизонтальный ряд кнопок -- Каждая кнопка - это массив вида {enum GUI.buttonTypes.default или GUI.buttonTypes.adaptive, int ширина/отступ, int высота/отступ, int цвет кнопки, int цвет текста, int цвет нажатой кнопки, int цвет нажатого текста, string текст} -- Метод возвращает обычный массив кнопочных объектов (см. выше) function GUI.buttons(x, y, direction, spaceBetweenButtons, ...) local buttons = {...} local buttonObjects = {} local function drawCorrectButton(i) if buttons[i][1] == GUI.buttonTypes.default then return GUI.button(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) elseif buttons[i][1] == GUI.buttonTypes.adaptive then return GUI.adaptiveButton(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) elseif buttons[i][1] == GUI.buttonTypes.framedDefault then return GUI.framedButton(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) elseif buttons[i][1] == GUI.buttonTypes.framedAdaptive then return GUI.adaptiveFramedButton(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) else error("Неподдерживаемый тип кнопки: " .. tostring(buttons[i][1])) end end for i = 1, #buttons do buttonObjects[i] = drawCorrectButton(i) if direction == GUI.directions.horizontal then x = x + buttonObjects[i].width + spaceBetweenButtons elseif direction == GUI.directions.vertical then y = y + buttonObjects[i].height + spaceBetweenButtons else error("Неподдерживаемое направление: " .. tostring(buttons[i][1])) end end return buttonObjects end ------------------------------------------------- Окна ------------------------------------------------------------------- -- Красивое окошко для отображения сообщения об ошибке. Аргумент errorWindowParameters может принимать следующие значения: -- local errorWindowParameters = { -- backgroundColor = 0x262626, -- textColor = 0xFFFFFF, -- truncate = 50, -- title = {color = 0xFF8888, text = "Ошибочка"} -- noAnimation = true, -- } function GUI.error(text, errorWindowParameters) --Всякие константы, бла-бла local backgroundColor = (errorWindowParameters and errorWindowParameters.backgroundColor) or 0x1b1b1b local errorPixMap = { {{0xffdb40 , 0xffffff,"#"}, {0xffdb40 , 0xffffff, "#"}, {backgroundColor, 0xffdb40, "▟"}, {backgroundColor, 0xffdb40, "▙"}, {0xffdb40 , 0xffffff, "#"}, {0xffdb40 , 0xffffff, "#"}}, {{0xffdb40 , 0xffffff,"#"}, {backgroundColor, 0xffdb40, "▟"}, {0xffdb40 , 0xffffff, " "}, {0xffdb40 , 0xffffff, " "}, {backgroundColor, 0xffdb40, "▙"}, {0xffdb40 , 0xffffff, "#"}}, {{backgroundColor, 0xffdb40,"▟"}, {0xffdb40 , 0xffffff, "c"}, {0xffdb40 , 0xffffff, "y"}, {0xffdb40 , 0xffffff, "k"}, {0xffdb40 , 0xffffff, "a"}, {backgroundColor, 0xffdb40, "▙"}}, } local textColor = (errorWindowParameters and errorWindowParameters.textColor) or 0xFFFFFF local buttonWidth = 12 local verticalOffset = 2 local minimumHeight = verticalOffset * 2 + #errorPixMap local height = 0 local widthOfText = math.floor(buffer.screen.width * 0.5) --Ебемся с текстом, делаем его пиздатым во всех смыслах if type(text) == "table" then text = serialization.serialize(text) end text = tostring(text) text = (errorWindowParameters and errorWindowParameters.truncate) and ecs.stringLimit("end", text, errorWindowParameters.truncate) or text text = { text } text = ecs.stringWrap(text, widthOfText) --Ебашим высоту правильнуюe height = verticalOffset * 2 + #text + 1 if errorWindowParameters and errorWindowParameters.title then height = height + 2 end if height < minimumHeight then height = minimumHeight end --Ебашим стартовые коорды отрисовки local x, y = math.ceil(buffer.screen.width / 2 - widthOfText / 2), math.ceil(buffer.screen.height / 2 - height / 2) local OKButton = {} local oldPixels = buffer.copy(1, y, buffer.screen.width, height) --Отрисовочка local function draw() local yPos = y --Подложка buffer.square(1, yPos, buffer.screen.width, height, backgroundColor, 0x000000); yPos = yPos + verticalOffset buffer.customImage(x - #errorPixMap[1] - 3, yPos, errorPixMap) --Титл, епта! if errorWindowParameters and errorWindowParameters.title then buffer.text(x, yPos, errorWindowParameters.title.color, errorWindowParameters.title.text); yPos = yPos + 2 end --Текстус for i = 1, #text do buffer.text(x, yPos, textColor, text[i]); yPos = yPos + 1 end; yPos = yPos + 1 --Кнопачка OKButton = GUI.button(x + widthOfText - buttonWidth, y + height - 2, buttonWidth, 1, 0x3392FF, 0xFFFFFF, 0xFFFFFF, 0x262626, "OK") --Атрисовачка buffer.draw() end --Графонистый выход local function quit() OKButton:press(0.2) buffer.paste(1, y, oldPixels) buffer.draw() end --Онимацыя if not (errorWindowParameters and errorWindowParameters.noAnimation) then for i = 1, height do buffer.setDrawLimit(1, math.floor(buffer.screen.height / 2) - i, buffer.screen.width, i * 2); draw(); os.sleep(0.05) end; buffer.resetDrawLimit() end draw() --Анализ говнища while true do local e = {event.pull()} if e[1] == "key_down" then if e[4] == 28 then quit(); return end elseif e[1] == "touch" then if OKButton:isClicked(e[3], e[4]) then quit(); return end end end end -------------------------------------------------------------------------------------------------------------------------------- -- buffer.clear(0xFFAAAA) -- buffer.draw(true) -- GUI.error("Ублюдок, мать твою, а ну иди сюда, говно собачье, а ну решил ко мне лезть, ты... засранец вонючий, мать твою. А?! ну иди сюда, попробуй меня трахнуть, я тебя сам трахну ублюдок, анонист чертов, будь ты проклят, иди идиот, трахать тебя за свою семью, говно собачье, жлоб вонючий, дерьмо, сука, падла, иди сюда мерзавец, негодяй, гад, иди сюда ты говно, жопа!", {title = {color = 0xFF7777, text = "Ошибка авторизации"}}) -- local event = require("event") -- local myButton = GUI.adaptiveButton(2, 2, 2, 1, 0xFFFFFF, 0x000000, 0xFF8888, 0xFFFFFF, "Кнопачка") -- buffer.draw() -- while true do -- local e = {event.pull("touch")} -- if myButton:isClicked(e[3], e[4]) then -- myButton:press(0.2) -- end -- end -- local myButtons = GUI.buttons(2, 2, GUI.directions.horizontal, 2, {GUI.buttonTypes.adaptive, 2, 0, 0xCCCCCC, 0x262626, 0xFF8888, 0xFFFFFF, "Кнопачка1"}, {GUI.buttonTypes.default, 30, 1, 0xCCCCCC, 0x262626, 0xFF8888, 0xFFFFFF, "Кнопачка2"}, {GUI.buttonTypes.adaptive, 2, 0, 0xCCCCCC, 0x262626, 0xFF8888, 0xFFFFFF, "Кнопачка3"}) -- buffer.draw() -- while true do -- local e = {event.pull("touch")} -- for _, button in pairs(myButtons) do -- if button:isClicked(e[3], e[4]) then -- button:press(0.2) -- end -- end -- end -------------------------------------------------------------------------------------------------------------------------------- return GUI