diff --git a/Applications.cfg b/Applications.cfg index 30c857b5..b6db2d8a 100644 --- a/Applications.cfg +++ b/Applications.cfg @@ -308,7 +308,7 @@ url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/GUI.lua", type="Library", preloadFile=true, - version=1.90, + version=1.91, }, { path="/lib/rayEngine.lua", @@ -481,15 +481,6 @@ }, } }, - { - path="/MineOS/Applications/Finder", - url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/Main.lua", - about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/About/", - type="Application", - icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/Icon.pic", - forceDownload=true, - version=1.25, - }, { path="/MineOS/Applications/3DTest", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DTest/3DTest.lua", @@ -500,6 +491,15 @@ forceDownload=true, version=1.22, }, + { + path="/MineOS/Applications/HEX", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/Icon.pic", + createShortcut=true, + version=1.04, + }, { path="/MineOS/Applications/Spinner", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Spinner/Main.lua", @@ -596,6 +596,15 @@ }, }, }, + { + path="/MineOS/Applications/Finder", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/Main.lua", + about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/About/", + type="Application", + icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Finder/Icon.pic", + forceDownload=true, + version=1.25, + }, { path="/MineOS/Applications/Weather", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Weather/Weather.lua", @@ -1001,15 +1010,6 @@ createShortcut=true, version=1.01, }, - { - path="/MineOS/Applications/HEX", - url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/HEX.lua", - about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/About/", - type="Application", - icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/HEX/Icon.pic", - createShortcut=true, - version=1.03, - }, { path="/MineOS/Applications/ChristmasTree", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/ChristmasTree/ChristmasTree.lua", diff --git a/Applications/HEX/HEX.lua b/Applications/HEX/HEX.lua deleted file mode 100644 index dc631fe2..00000000 --- a/Applications/HEX/HEX.lua +++ /dev/null @@ -1,402 +0,0 @@ -require("advancedLua") -local unicode = require("unicode") -local buffer = require("doubleBuffering") -local event = require("event") -local fs = require("filesystem") -local context = require("context") -local ecs = require("ECSAPI") - --------------------------------------------------------------------------------------------------------------------------------- - -local xSize, ySize = buffer.width, buffer.height -local file = {} - -local config = { - x = 1, - y = 1, - width = 98, - height = 25, - heightOfTopBar = 3, - fromString = 1, - xCurrentByte = 1, - yCurrentByte = 1, - pathToFile = "bin/resolution.lua", - sizeOfFile = 1, - transparency = 30, - colors = { - background = 0xdddddd, - topBar = 0xdddddd, - topBarText = 0x262626, - topBarButton = 0x444444, - hexText = 0x262626, - hexSelection = 0x880000, - hexSelectionText = 0xffffff, - numberBar = 0x262626, - numberBarText = 0xcccccc, - infoPanel = 0x880000, - infoPanelText = 0xffffff, - } -} - --------------------------------------------------------------------------------------------------------------------------------- - -local obj = {} -local function newObj(class, name, ...) - obj[class] = obj[class] or {} - obj[class][name] = {...} -end - -local function convertIndexToCoords(index) - local ostatok = index % 16 - local x = (ostatok == 0) and 16 or ostatok - local y = math.ceil(index / 16) - return x, y -end - -local function convertCoordsToIndex(xByte, yByte) - return (yByte - 1) * 16 + xByte -end - -local function readFile() - config.fromString = 1 - config.CurrentByte = 1 - config.CurrentByte = 1 - - file = {} - local fileStream = io.open(config.pathToFile, "rb") - - while true do - local readedByte = fileStream:read(1) - if not readedByte then break end - table.insert(file, string.format("%02X", string.byte(readedByte))) - end - - fileStream:close() - config.sizeOfFile = math.ceil(fs.size(config.pathToFile) / 1024) -end - -local function drawInfoPanel() - local x = config.x - local y = config.y - - local width = 30 - local xPos = x + math.floor(config.width / 2 - width / 2) - 1 - buffer.square(xPos, y, width, config.heightOfTopBar, config.colors.infoPanel, 0x000000, " ") - - local text = fs.name(config.pathToFile) - xPos = x + math.floor(config.width / 2 - unicode.len(text) / 2) - 1 - buffer.text(xPos, y, config.colors.infoPanelText, unicode.sub(text, 1, width - 2)) - - text = "Размер файла: " .. config.sizeOfFile .. " КБ" - xPos = x + math.floor(config.width / 2 - unicode.len(text) / 2) - 1 - buffer.text(xPos, y + 1, 0xffaaaa, unicode.sub(text, 1, width - 2)) - - text = "Текущий байт: " .. convertCoordsToIndex(config.xCurrentByte, config.yCurrentByte) - xPos = x + math.floor(config.width / 2 - unicode.len(text) / 2) - 1 - buffer.text(xPos, y + 2, 0xffaaaa, unicode.sub(text, 1, width - 2)) -end - -local function drawTopBar() - local x = config.x - local y = config.y - - buffer.square(x, y, config.width, 3, 0xffffff, 0xffffff, " ", config.transparency) - newObj("Buttons", 1, buffer.button(x, y, 10, 3, 0xdddddd, 0x000000, "Файл")) - - drawInfoPanel() -end - -local function printDebug(line, text) - if debug then - ecs.square(1, line, buffer.width, 1, 0x262626) - ecs.colorText(2, line, 0xFFFFFF, text) - end -end - -local function drawHexAndText() - local x, y = config.x, config.y + 3 - local textOffset = 67 - local hexOffset = 12 - local xHex, yHex = x + hexOffset, y + 2 - local xText, yText = xHex + textOffset, y + 2 - - obj["hex"] = {} - obj["text"] = {} - - --Главный белый - buffer.square(config.x, config.y + 3, config.width, config.height - 3, config.colors.background, 0x000000, " ") - --Левый серый - buffer.square(x, y, 10, config.height - 3, config.colors.numberBar, 0xffffff, " ") - --Верхний серый - buffer.square(x, y, config.width, 1, config.colors.numberBar, 0xffffff, " ") - --Вертикальная полоска - buffer.square(xText - 3, y + 1, 1, config.height - 4, config.colors.background, 0xaaaaaa, "│") - --Скроллбар - buffer.scrollBar(x + config.width - 1, y + 1, 1, config.height - 4, math.ceil(#file / 16), config.fromString, 0x262626, ecs.colors.lightBlue) - - --Рисуем верхние номерки - local xCyka = xHex - for i = 1, 16 do - if i == config.xCurrentByte then - buffer.square(xCyka - 1, y, 4, 1, config.colors.hexSelection, 0xffffff, " ") - buffer.text(xCyka, y, config.colors.hexSelectionText, string.format("%02X", i - 1)) - else - buffer.text(xCyka, y, config.colors.numberBarText, string.format("%02X", i - 1)) - end - - xCyka = xCyka + 4 - end - - --Рисуем хекс и текст - local xByte, yByte, text - local byteCounter = 1 - local fromByte = config.fromString * 16 - 15 - for byte = fromByte, fromByte + 10 * 16 - 1 do - - if not file[byte] then break end - - xByte, yByte = convertIndexToCoords(byte) - - text = unicode.char(tonumber("0x" .. file[byte])) - if unicode.isWide(text) then text = "." end - - if config.xCurrentByte == xByte and config.yCurrentByte == yByte then - buffer.square(xHex - 1, yHex, 4, 1, config.colors.hexSelection, 0xffffff, " ") - buffer.set(xText, yText, config.colors.hexSelection, 0xffffff, " ") - - buffer.text(xHex, yHex, config.colors.hexSelectionText, file[byte]) - buffer.text(xText, yText, config.colors.hexSelectionText, text) - else - buffer.text(xHex, yHex, config.colors.hexText, file[byte]) - buffer.text(xText, yText, config.colors.hexText, text) - end - - --Рисуем левые номерки - if yByte == config.yCurrentByte then - buffer.square(x, yHex, 10, 1, config.colors.hexSelection, 0xffffff, " ") - buffer.text(x + 1, yHex, config.colors.hexSelectionText, string.format("%07X", yByte - 1) .. "0") - else - buffer.text(x + 1, yHex, config.colors.numberBarText, string.format("%07X", yByte - 1) .. "0") - end - - --Обжектыыы!! Ы! - newObj("hex", byteCounter, xHex, yHex, xByte, yByte) - newObj("text", byteCounter, xText, yText, xByte, yByte) - byteCounter = byteCounter + 1 - - --Коорды! - if xByte == 16 then - xHex = x + hexOffset - xText = xHex + textOffset - yHex = yHex + 2 - yText = yText + 2 - else - xHex = xHex + 4 - xText = xText + 1 - end - end -end - - -local function drawAll(force) - drawTopBar() - drawHexAndText() - --Тень - buffer.square(config.x + config.width, config.y + 1, 2, config.height, 0x000000, 0xffffff, " ", 50) - buffer.square(config.x + 2, config.y + config.height, config.width - 2, 1, 0x000000, 0xffffff, " ", 50) - buffer.draw(force) -end - -local function getCenterOfScreen() - config.x = math.floor(xSize / 2 - config.width / 2) - config.y = math.floor(ySize / 2 - config.height / 2) -end - -local function checkInput(text, pattern) - if string.find(text, pattern) then - return true - else - ecs.error("Что за говно ты сюда ввел? Переделывай на хуй!") - end -end - -local function editByte(xByte, yByte) - local index = convertCoordsToIndex(xByte, yByte) - local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Редактировать байт"}, {"EmptyLine"}, {"Input", 0xffffff, 0xff5555, "Введите значение HEX"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Принять"}, {0xaaaaaa, 0xffffff, "Отмена"}}) - if data[2] == "Принять" and checkInput(data[1], "^[1234567890abcdefABCDEF][1234567890abcdefABCDEF]$") then - file[index] = data[1] - end -end - -local function editText(xByte, yByte) - local index = convertCoordsToIndex(xByte, yByte) - local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Редактировать байт"}, {"EmptyLine"}, {"Input", 0xffffff, 0xff5555, "Введите значение CHAR"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Принять"}, {0xaaaaaa, 0xffffff, "Отмена"}}) - if data[2] == "Принять" and checkInput(data[1], "^.$") then - file[index] = string.format("%02X", string.byte(byteValue)) - end -end - -local function insertByte(xByte, yByte) - local index = convertCoordsToIndex(xByte, yByte) - local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Вставить байт"}, {"EmptyLine"}, {"Input", 0xffffff, 0xff5555, "Введите значение HEX"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Вставить"}, {0xaaaaaa, 0xffffff, "Отмена"}}) - if data[2] == "Вставить" and checkInput(data[1], "^[1234567890abcdefABCDEF][1234567890abcdefABCDEF]$") then - table.insert(file, index, data[1]) - end -end - -local function invertByte(xByte, yByte) - local index = convertCoordsToIndex(xByte, yByte) - file[index] = bit32.band( bit32.bnot(tonumber("0x" .. file[index])), 0xff ) - file[index] = string.format("%02X", string.byte(file[index])) -end - -local function askForWhatToDoWithByte(x, y, xByte, yByte, asByte) - local action = context.menu(x, y, {"Редактировать байт"}, {"Инвертировать байт"}, {"Вставить байт"}, "-", {"Удалить байт"}) - - if action == "Редактировать байт" then - if asByte then - editByte(xByte, yByte) - else - editText(xByte, yByte) - end - elseif action == "Инвертировать байт" then - local index = convertCoordsToIndex(xByte, yByte) - invertByte(xByte, yByte) - elseif action == "Вставить байт" then - insertByte(xByte, yByte) - elseif action == "Удалить байт" then - local index = convertCoordsToIndex(xByte, yByte) - table.remove(file, index) - end -end - -local function save(path) - fs.makeDirectory(fs.path(path) or "") - local fileStream = io.open(path, "w") - for i = 1, #file do - fileStream:write(unicode.char(tonumber(table.concat({"0x", file[i]})))) - end - fileStream:close() -end - --------------------------------------------------------------------------------------------------------------------------------- - -readFile() ---buffer.square(1, 1, xSize, ySize, ecs.colors.red, 0x000000, " ") -getCenterOfScreen() - -local oldPixels = buffer.copy(config.x, config.y, config.width + 2, config.height + 1) -drawAll(true) - -while true do - local e = {event.pull()} - if e[1] == "touch" then - for key in pairs(obj["hex"]) do - if e[3] >= obj["hex"][key][1] - 1 and e[3] <= obj["hex"][key][1] + 2 and e[4] == obj["hex"][key][2] then - if config.xCurrentByte == obj["hex"][key][3] and config.yCurrentByte == obj["hex"][key][4] then - if e[5] == 0 then - editByte(obj["hex"][key][3], obj["hex"][key][4]) - else - askForWhatToDoWithByte(obj["hex"][key][1] - 1, obj["hex"][key][2] + 1, obj["hex"][key][3], obj["hex"][key][4], true) - end - else - config.xCurrentByte = obj["hex"][key][3] - config.yCurrentByte = obj["hex"][key][4] - end - - drawHexAndText() - drawInfoPanel() - buffer.draw() - - break - end - end - - for key in pairs(obj["text"]) do - if e[3] == obj["text"][key][1] and e[4] == obj["text"][key][2] then - if config.xCurrentByte == obj["text"][key][3] and config.yCurrentByte == obj["text"][key][4] then - if e[5] == 0 then - editText(obj["text"][key][3], obj["text"][key][4]) - else - askForWhatToDoWithByte(obj["text"][key][1], obj["text"][key][2] + 1, obj["text"][key][3], obj["text"][key][4], true) - end - else - config.xCurrentByte = obj["text"][key][3] - config.yCurrentByte = obj["text"][key][4] - end - - drawHexAndText() - drawInfoPanel() - buffer.draw() - - break - end - end - - if ecs.clickedAtArea(e[3], e[4], obj["Buttons"][1][1], obj["Buttons"][1][2], obj["Buttons"][1][3], obj["Buttons"][1][4]) then - buffer.button(obj["Buttons"][1][1], obj["Buttons"][1][2], 10, 3, 0x333333, 0xdddddd, "Файл") - buffer.draw() - - local action = context.menu(obj["Buttons"][1][1], obj["Buttons"][1][2] + 3, {"Открыть"}, {"Сохранить"}, {"Сохранить как"}, "-", {"Выход"}) - - buffer.button(obj["Buttons"][1][1], obj["Buttons"][1][2], 10, 3, 0xdddddd, 0x000000, "Файл") - buffer.draw() - - if action == "Открыть" then - local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Открыть файл"}, {"EmptyLine"}, {"Input", 0xffffff, 0x880000, "Путь к файлу"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Открыть"}, {0xaaaaaa, 0xffffff, "Отмена"}}) - if data[2] == "Открыть" then - if fs.exists(data[1]) then - config.pathToFile = data[1] - readFile() - drawHexAndText() - drawInfoPanel() - buffer.draw() - else - ecs.error("Файл \"" .. data[1] .. "\" не существует!") - end - end - elseif action == "Сохранить" then - save(config.pathToFile) - elseif action == "Сохранить как" then - local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", 0xffffff, "Сохранить как"}, {"EmptyLine"}, {"Input", 0xffffff, 0x880000, "Путь к файлу"}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "Сохранить"}, {0xaaaaaa, 0xffffff, "Отмена"}}) - if data[2] == "Сохранить" then - save(data[1]) - end - elseif action == "Выход" then - buffer.paste(config.x, config.y, oldPixels) - buffer.draw() - return - end - end - elseif e[1] == "scroll" then - if e[5] == 1 then - if config.fromString > 1 then - config.fromString = config.fromString - 1 - drawHexAndText() - buffer.draw() - end - else - if config.fromString <= math.ceil(#file / 16) - 1 then - config.fromString = config.fromString + 1 - drawHexAndText() - buffer.draw() - end - end - end -end - - - - - - - - - - - - - - - - diff --git a/Applications/HEX/Icon.pic b/Applications/HEX/Icon.pic old mode 100644 new mode 100755 index a504ec1e..a9a1e314 Binary files a/Applications/HEX/Icon.pic and b/Applications/HEX/Icon.pic differ diff --git a/Applications/HEX/Main.lua b/Applications/HEX/Main.lua new file mode 100755 index 00000000..71f269b2 --- /dev/null +++ b/Applications/HEX/Main.lua @@ -0,0 +1,379 @@ + +require("advancedLua") +local bit32 = require("bit32") +local fs = require("filesystem") +local GUI = require("GUI") +local buffer = require("doubleBuffering") +local unicode = require("unicode") +local MineOSInterface = require("MineOSInterface") + +------------------------------------------------------------------------------------------------------------------ + +local colors = { + background = 0xF0F0F0, + backgroundText = 0x555555, + panel = 0x2D2D2D, + panelText = 0x999999, + panelSeleciton = 0x444444, + panelSelecitonText = 0xE1E1E1, + selectionFrom = 0x990000, + selectionTo = 0x990000, + selectionText = 0xFFFFFF, + selectionBetween = 0xD2D2D2, + selectionBetweenText = 0x000000, + separator = 0xCCCCCC, + titleBackground = 0xCC4940, + titleText = 0xFFFFFF, + titleText2 = 0xE1E1E1, +} + +local bytes = {} +local offset = 0 +local selection = { + from = 1, + to = 1, +} + +local scrollBar, titleTextBox + +------------------------------------------------------------------------------------------------------------------ + +local mainContainer, window = MineOSInterface.addWindow(GUI.filledWindow(nil, nil, 98, 25, colors.background)) + +window.backgroundPanel.localPosition.x, window.backgroundPanel.localPosition.y = 11, 5 +window.backgroundPanel.width, window.backgroundPanel.height = window.width - 10, window.height - 4 + +local function status() + titleTextBox.lines[1] = "Selected byte" .. (selection.from == selection.to and "" or "s") .. ": " .. selection.from .. "-" .. selection.to + titleTextBox.lines[2].text = "UTF-8: \"" .. string.char(table.unpack(bytes, selection.from, selection.to)) .. "\"" + titleTextBox.lines[3].text = "INT: " .. bit32.byteArrayToNumber({table.unpack(bytes, selection.from, selection.to)}) +end + +local function byteFieldDraw(object) + local x, y, index = object.x, object.y, 1 + offset + local xCount, yCount = math.ceil(object.width / object.elementWidth), math.ceil(object.height / object.elementHeight) + + for j = 1, yCount do + for i = 1, xCount do + if bytes[index] then + local textColor = colors.backgroundText + if index == selection.from or index == selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, index == selection.from and colors.selectionFrom or colors.selectionTo, colors.selectionText, " ") + textColor = colors.selectionText + elseif index > selection.from and index < selection.to then + buffer.square(x - object.offset, y, object.elementWidth, 1, colors.selectionBetween, colors.selectionText, " ") + textColor = colors.selectionBetweenText + end + + buffer.text(x, y, textColor, object.asChar and string.char(bytes[index]) or string.format("%02X", bytes[index])) + else + return object + end + + x, index = x + object.elementWidth, index + 1 + end + + local lastLineIndex = index - 1 + if lastLineIndex >= selection.from and lastLineIndex < selection.to then + buffer.square(object.x - object.offset, y + 1, object.width, 1, colors.selectionBetween, colors.selectionText, " ") + end + + x, y = object.x, y + object.elementHeight + end + + return object +end + +local function byteFieldEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + if eventData[5] == 1 then + local menu = GUI.contextMenu(eventData[3], eventData[4]) + + menu:addItem("Select all").onTouch = function() + selection.from = 1 + selection.to = #bytes + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Edit").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Fill byte range [" .. selection.from .. "; " .. selection.to .. "]") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, string.format("%02X" , bytes[selection.from]), "Type byte value")) + input.onInputFinished = function(text) + local number = tonumber("0x" .. input.text) + if number and number >= 0 and number <= 255 then + for i = selection.from, selection.to do + bytes[i] = number + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addItem("Insert").onTouch = function() + local container = MineOSInterface.addUniversalContainer(mainContainer, "Insert bytes at position " .. selection.from .. "") + + local input = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x666666, 0x666666, 0xE1E1E1, 0x2D2D2D, "", "Type byte values separated by space", true)) + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x1E1E1E, 0xE1E1E1, 0xBBBBBB, "Select inserted bytes:", true)).switch + + input.onInputFinished = function() + if input.text:match("[a-fA-F%d%s]+") then + local insertionPosition, count = selection.from, 0 + for word in input.text:gmatch("[^%s]+") do + local number = tonumber("0x" .. word) + if number > 255 then number = 255 end + table.insert(bytes, insertionPosition + count, number) + selection.from, selection.to, count = selection.from + 1, selection.to + 1, count + 1 + end + + if switch.state then + selection.from, selection.to = insertionPosition, insertionPosition + count - 1 + end + + container:delete() + mainContainer:draw() + buffer.draw() + end + end + + mainContainer:draw() + buffer.draw() + end + menu:addSeparator() + menu:addItem("Delete").onTouch = function() + for i = selection.from, selection.to do + table.remove(bytes, selection.from) + end + if #bytes == 0 then + selection.from, selection.to = 1, 1 + else + selection.to = selection.from + end + end + menu:show() + else + local index = (math.ceil((eventData[4] - object.y + 1) / 2) - 1) * 16 + math.ceil((eventData[3] - object.x + 1 + object.offset) / object.elementWidth) + offset + + if bytes[index] then + if eventData[1] == "touch" then + selection.to = index + selection.from = index + selection.touchIndex = index + else + if not selection.touchIndex then selection.touchIndex = index end + + if index < selection.touchIndex then + selection.from = index + selection.to = selection.touchIndex + elseif index > selection.touchIndex then + selection.to = index + selection.from = selection.touchIndex + end + end + + status() + mainContainer:draw() + buffer.draw() + end + end + elseif eventData[1] == "scroll" then + offset = offset - 16 * eventData[5] + if offset < 0 then + offset = 0 + elseif offset > math.floor(#bytes / 16) * 16 then + offset = math.floor(#bytes / 16) * 16 + end + scrollBar.value = offset + + mainContainer:draw() + buffer.draw() + end +end + +local function newByteField(x, y, width, height, elementWidth, elementHeight, asChar) + local object = GUI.object(x, y, width, height) + + object.elementWidth = elementWidth + object.elementHeight = elementHeight + object.offset = asChar and 0 or 1 + object.asChar = asChar + object.draw = byteFieldDraw + object.eventHandler = byteFieldEventHandler + + return object +end + +------------------------------------------------------------------------------------------------------------------ + +window:addChild(GUI.panel(1, 1, window.width, 3, 0xFFFFFF, 0.3)):moveToBack() + +local byteField = window:addChild(newByteField(13, 6, 64, 20, 4, 2, false)) +local charField = window:addChild(newByteField(byteField.localPosition.x + byteField.width + 3, 6, 16, 20, 1, 2, true)) +local separator = window:addChild(GUI.object(byteField.localPosition.x + byteField.width, 5, 1, 21)) +separator.draw = function(object) + for i = object.y, object.y + object.height - 1 do + buffer.text(object.x, i, colors.separator, "│") + end +end + + +window:addChild(GUI.panel(11, 4, window.width - 10, 1, colors.panel)) + +-- Vertical +local verticalCounter = window:addChild(GUI.object(1, 4, 10, window.height - 3)) +verticalCounter.draw = function(object) + buffer.square(object.x, object.y, object.width, object.height, colors.panel, colors.panelText, " ") + + local index = offset + for y = 2, object.height - 1, 2 do + local textColor = colors.panelText + + if index > selection.from and index < selection.to then + buffer.square(object.x, object.y + y - 1, object.width, 2, colors.panelSeleciton, colors.panelSelecitonText, " ") + textColor = colors.panelSelecitonText + end + + if selection.from >= index and selection.from <= index + 15 or selection.to >= index and selection.to <= index + 15 then + buffer.square(object.x, object.y + y, object.width, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + 1, object.y + y, textColor, string.format("%08X", index)) + + index = index + 16 + end +end + +-- Horizontal +window:addChild(GUI.object(13, 4, 62, 1)).draw = function(object) + local counter = 0 + local restFrom, restTo = selection.from % 16, selection.to % 16 + for x = 1, object.width, 4 do + local textColor = colors.panelText + if counter + 1 > restFrom and counter + 1 < restTo then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.panelSeleciton, colors.selectionText, " ") + textColor = colors.panelSelecitonText + elseif restFrom == counter + 1 or restTo == counter + 1 then + buffer.square(object.x + x - 2, object.y, 4, 1, colors.selectionFrom, colors.selectionText, " ") + textColor = colors.selectionText + end + + buffer.text(object.x + x - 1, object.y, textColor, string.format("%02X", counter)) + counter = counter + 1 + end +end + +scrollBar = window:addChild(GUI.scrollBar(window.width, 5, 1, window.height - 4, 0xC3C3C3, 0x393939, 0, 1, 1, 160, 1, true)) +scrollBar.eventHandler = nil + +titleTextBox = window:addChild( + GUI.textBox( + 1, 1, math.floor(window.width * 0.36), 3, + colors.titleBackground, + colors.titleText, + { + "", + {text = "", color = colors.titleText2}, + {text = "", color = colors.titleText2} + }, + 1, 1, 0 + ) +) +titleTextBox.localPosition.x = math.floor(window.width / 2 - titleTextBox.width / 2) +titleTextBox:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +titleTextBox.eventHandler = nil + +local saveFileButton = window:addChild(GUI.adaptiveRoundedButton(titleTextBox.localPosition.x - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Save")) +local openFileButton = window:addChild(GUI.adaptiveRoundedButton(saveFileButton.localPosition.x - 11, 2, 2, 0, colors.panel, colors.panelSelecitonText, colors.panelSelecitonText, colors.panel, "Open")) + +------------------------------------------------------------------------------------------------------------------ + +local function load(path) + local file, reason = io.open(path, "rb") + + if file then + bytes = {} + local char + while true do + local char = file:read(1) + if char then + table.insert(bytes, string.byte(char)) + else + break + end + end + + file:close() + offset = 0 + selection.from, selection.to = 1, 1 + scrollBar.value, scrollBar.maximumValue = 0, #bytes + status() + else + GUI.error("Failed to open file for reading: " .. tostring(reason)) + end +end + +openFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, "Open", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.open, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + load(path) + mainContainer:draw() + buffer.draw() + end +end + +saveFileButton.onTouch = function() + local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, "Save", "Cancel", "File name", "/") + filesystemDialog:setMode(GUI.filesystemModes.save, GUI.filesystemModes.file) + filesystemDialog:show() + filesystemDialog.onSubmit = function(path) + local file = io.open(path, "wb") + if file then + for i = 1, #bytes do + file:write(string.char(bytes[i])) + end + file:close() + else + GUI.error("Failed to open file for writing: " .. tostring(reason)) + end + end +end + +window.actionButtons.maximize.onTouch = function() + window.height = window.parent.height + byteField.height = window.height - 6 + charField.height = byteField.height + scrollBar.height = byteField.height + window.backgroundPanel.height = window.height - 4 + verticalCounter.height = window.backgroundPanel.height + 1 + separator.height = byteField.height + 2 + + window.localPosition.y = 1 + + mainContainer:draw() + buffer.draw() +end + +------------------------------------------------------------------------------------------------------------------ + +load("/bin/resolution.lua") +mainContainer:draw() +buffer.draw() + + + + + + + + + diff --git a/Documentation/GUI.md b/Documentation/GUI.md index eeb41c15..89892800 100644 --- a/Documentation/GUI.md +++ b/Documentation/GUI.md @@ -260,10 +260,12 @@ local image = require("image") local buffer = require("doubleBuffering") local GUI = require("GUI") +------------------------------------------------------------------------------------------ + -- Создаем полноэкранный контейнер, добавляем на него загруженное изображение и полупрозрачную черную панель local mainContainer = GUI.fullScreenContainer() mainContainer:addChild(GUI.image(1, 1, image.load("/MineOS/Pictures/Raspberry.pic"))) -mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x000000, 40)) +mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x000000, 0.4)) -- Добавляем в созданный контейнер layout с сеткой размером 5x1 local layout = mainContainer:addChild(GUI.layout(1, 1, mainContainer.width, mainContainer.height, 5, 1)) @@ -281,6 +283,8 @@ layout:setCellPosition(4, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0 layout:setCellPosition(4, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 8"))) layout:setCellPosition(5, 1, layout:addChild(GUI.button(1, 1, 26, 3, 0xEEEEEE, 0x000000, 0xAAAAAA, 0x000000, "Button 9"))) +------------------------------------------------------------------------------------------ + mainContainer:draw() buffer.draw(true) mainContainer:startEventHandling() diff --git a/lib/GUI.lua b/lib/GUI.lua index e3658c80..864cda58 100755 --- a/lib/GUI.lua +++ b/lib/GUI.lua @@ -2298,8 +2298,8 @@ local function filesystemDialogSetMode(filesystemDialog, IOMode, filesystemMode) if filesystemDialog.IOMode == GUI.filesystemModes.save then filesystemDialog.filesystemTree.showMode = GUI.filesystemModes.directory filesystemDialog.filesystemTree.selectionMode = GUI.filesystemModes.directory - filesystemDialog.input.eventHandler = inputEventHandler - filesystemDialog.extensionComboBox.hidden = not (filesystemDialog.filesystemMode == GUI.filesystemModes.file) + filesystemDialog.input.disabled = false + filesystemDialog.extensionComboBox.hidden = filesystemDialog.filesystemMode ~= GUI.filesystemModes.file or not filesystemDialog.filesystemTree.extensionFilters else if filesystemDialog.filesystemMode == GUI.filesystemModes.file then filesystemDialog.filesystemTree.showMode = GUI.filesystemModes.both @@ -2309,7 +2309,7 @@ local function filesystemDialogSetMode(filesystemDialog, IOMode, filesystemMode) filesystemDialog.filesystemTree.selectionMode = GUI.filesystemModes.directory end - filesystemDialog.input.eventHandler = nil + filesystemDialog.input.disabled = true filesystemDialog.extensionComboBox.hidden = true end @@ -2320,8 +2320,9 @@ local function filesystemDialogAddExtensionFilter(filesystemDialog, extension) filesystemDialog.extensionComboBox:addItem(extension) filesystemDialog.extensionComboBox.width = math.max(filesystemDialog.extensionComboBox.width, unicode.len(extension) + 3) filesystemDialog.extensionComboBox.localPosition.x = filesystemDialog.cancelButton.localPosition.x - filesystemDialog.extensionComboBox.width - 2 - filesystemDialog.filesystemTree:addExtensionFilter(extension) + + filesystemDialog:setMode(filesystemDialog.IOMode, filesystemDialog.filesystemMode) end function GUI.filesystemDialog(x, y, width, height, submitButtonText, cancelButtonText, placeholderText, path) @@ -2334,10 +2335,10 @@ function GUI.filesystemDialog(x, y, width, height, submitButtonText, cancelButto filesystemDialog.submitButton.localPosition.x = filesystemDialog.width - filesystemDialog.submitButton.width - 1 filesystemDialog.cancelButton.localPosition.x = filesystemDialog.submitButton.localPosition.x - filesystemDialog.cancelButton.width - 2 - filesystemDialog.extensionComboBox = filesystemDialog:addChild(GUI.comboBox(1, height - 1, 1, 1, 0xE1E1E1, 0x555555, 0xC3C3C3, 0x888888)) + filesystemDialog.extensionComboBox = filesystemDialog:addChild(GUI.comboBox(1, height - 1, 1, 1, 0xE1E1E1, 0x666666, 0xC3C3C3, 0x888888)) filesystemDialog.extensionComboBox.hidden = true - filesystemDialog.input = filesystemDialog:addChild(GUI.input(2, height - 1, 1, 1, 0xE1E1E1, 0x555555, 0x888888, 0xE1E1E1, 0x777777, "", placeholderText)) + filesystemDialog.input = filesystemDialog:addChild(GUI.input(2, height - 1, 1, 1, 0xE1E1E1, 0x666666, 0x999999, 0xE1E1E1, 0x3C3C3C, "", placeholderText)) filesystemDialog.filesystemTree = filesystemDialog:addChild(GUI.filesystemTree(1, 1, width, height - 3, 0xE1E1E1, 0x3C3C3C, 0x3C3C3C, 0xAAAAAA, 0x3C3C3C, 0xE1E1E1, 0xBBBBBB, 0xAAAAAA, 0xC3C3C3, 0x444444)) filesystemDialog.filesystemTree.workPath = path @@ -2394,7 +2395,8 @@ function GUI.addFilesystemDialogToContainer(parentContainer, ...) path = path .. filesystemDialog.input.text if filesystemDialog.filesystemMode == GUI.filesystemModes.file then - path = path .. filesystemDialog.extensionComboBox:getItem(filesystemDialog.extensionComboBox.selectedItem).text + local selectedItem = filesystemDialog.extensionComboBox:getItem(filesystemDialog.extensionComboBox.selectedItem) + path = path .. (selectedItem and selectedItem.text or "") else path = path .. "/" end @@ -3487,6 +3489,29 @@ function GUI.autoComplete(x, y, width, maximumHeight, backgroundColor, textColor return object end +-------------------------------------------------------------------------------------------------------------------------------- + + +-- buffer.clear() +-- buffer.draw(true) + +-- -- Создаем полноэкранный контейнер, добавляем на него загруженное изображение и полупрозрачную черную панель +-- local mainContainer = GUI.fullScreenContainer() +-- mainContainer:addChild(GUI.image(1, 1, image.load("/MineOS/Pictures/Raspberry.pic"))) + +-- local filesystemDialog = GUI.addFilesystemDialogToContainer(mainContainer, "Save", "Cancel", "File name", "/") +-- filesystemDialog:setMode(GUI.filesystemModes.save, GUI.filesystemModes.file) +-- filesystemDialog:addExtensionFilter(".pic") +-- filesystemDialog:show() +-- filesystemDialog.onSubmit = function(path) +-- GUI.error(path) +-- end + +-- mainContainer:draw() +-- buffer.draw(true) +-- mainContainer:startEventHandling() + + -------------------------------------------------------------------------------------------------------------------------------- return GUI