mirror of
https://github.com/IgorTimofeev/MineOS.git
synced 2026-01-10 05:02:40 +01:00
Обновленное приложение HEX
This commit is contained in:
parent
74b960c913
commit
6c885bf204
@ -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",
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
Applications/HEX/Icon.pic
Normal file → Executable file
BIN
Applications/HEX/Icon.pic
Normal file → Executable file
Binary file not shown.
379
Applications/HEX/Main.lua
Executable file
379
Applications/HEX/Main.lua
Executable file
@ -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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
39
lib/GUI.lua
39
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user