diff --git a/Applications.cfg b/Applications.cfg index 3625a967..70940c9a 100644 --- a/Applications.cfg +++ b/Applications.cfg @@ -5,7 +5,7 @@ about="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/About/", type="Script", forceDownload=true, - version=3.68, + version=3.69, }, { path="/MineOS/Pictures/MoonTouch.pic", @@ -68,131 +68,162 @@ version=1.0, }, { - path="/MineOS/System/OS/Localization/Russian.lang", + path="/MineOS/System/Localization/Russian.lang", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Localization/Russian.lang", type="Script", forceDownload=true, - version=1.27, + version=1.28, }, { - path="/MineOS/System/OS/Localization/English.lang", + path="/MineOS/System/Localization/English.lang", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Localization/English.lang", type="Script", forceDownload=true, - version=1.27, + version=1.28, + }, + ----------------------------------------------------- Ассоциация говна -------------------------------------------------------------------------- + { + path="/MineOS/System/Extension associations/lua/Context menu.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Extension associations/lua/Context menu.lua", + type="Script", + forceDownload=true, + version=1.00, + }, + { + path="/MineOS/System/Extension associations/lua/Launcher.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Extension associations/lua/Launcher.lua", + type="Script", + forceDownload=true, + version=1.00, + }, + -- + { + path="/MineOS/System/Extension associations/pic/Context menu.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Extension associations/pic/Context menu.lua", + type="Script", + forceDownload=true, + version=1.00, + }, + -- + { + path="/MineOS/System/Extension associations/pkg/Launcher.lua", + url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Extension associations/pkg/Launcher.lua", + type="Script", + forceDownload=true, + version=1.00, }, ----------------------------------------------------- Системные иконки -------------------------------------------------------------------------- { - path="/MineOS/System/OS/Icons/Application.pic", + path="/MineOS/System/Icons/Application.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Application.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/3DModel.pic", + path="/MineOS/System/Icons/3DModel.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/3DModel.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Computer.pic", + path="/MineOS/System/Icons/Computer.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Computer.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Robot.pic", + path="/MineOS/System/Icons/Robot.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Robot.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Tablet.pic", + path="/MineOS/System/Icons/Tablet.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Tablet.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Pastebin.pic", + path="/MineOS/System/Icons/Pastebin.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Pastebin.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/HDD.pic", + path="/MineOS/System/Icons/HDD.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/HDD.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Floppy.pic", + path="/MineOS/System/Icons/Floppy.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Floppy.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Steve.pic", + path="/MineOS/System/Icons/Steve.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Steve.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Folder.pic", + path="/MineOS/System/Icons/Folder.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Folder.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/FileNotExists.pic", + path="/MineOS/System/Icons/FileNotExists.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/FileNotExists.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Script.pic", + path="/MineOS/System/Icons/Script.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Script.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Text.pic", + path="/MineOS/System/Icons/Text.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Text.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Config.pic", + path="/MineOS/System/Icons/Config.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Config.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Image.pic", + path="/MineOS/System/Icons/Image.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Image.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Lua.pic", + path="/MineOS/System/Icons/Lua.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Lua.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/SampleIcon.pic", + path="/MineOS/System/Icons/SampleIcon.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/SampleIcon.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Archive.pic", + path="/MineOS/System/Icons/Archive.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Archive.pic", type="Icon", version=1.0, }, { - path="/MineOS/System/OS/Icons/Trash.pic", + path="/MineOS/System/Icons/Trash.pic", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Icons/Trash.pic", type="Icon", version=1.01, @@ -204,14 +235,14 @@ path="/lib/MineOSCore.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/MineOSCore.lua", type="Library", - version=1.70, + version=1.71, }, { path="/lib/advancedLua.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/advancedLua.lua", type="Library", preloadFile=true, - version=1.14, + version=1.15, }, { path="/lib/web.lua", @@ -224,7 +255,7 @@ path="/lib/event.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/event.lua", type="Library", - version=1.01, + version=1.02, }, { path="/lib/ECSAPI.lua", @@ -237,7 +268,7 @@ url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/color.lua", type="Library", preloadFile=true, - version=1.05, + version=1.06, }, { path="/lib/ImageFormatModules/OCIF.lua", @@ -257,14 +288,14 @@ path="/lib/serialization.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/serialization.lua", type="Library", - version=1.06, + version=1.07, }, { path="/lib/GUI.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/GUI.lua", type="Library", preloadFile=true, - version=1.64, + version=1.65, }, { path="/lib/rayEngine.lua", @@ -331,7 +362,7 @@ url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/doubleBuffering.lua", type="Library", preloadFile=true, - version=1.25, + version=1.26, }, { path="/lib/compressor.lua", @@ -361,25 +392,25 @@ path="/lib/OpenComputersGL/Main.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/OpenComputersGL/Main.lua", type="Library", - version=1.08, + version=1.09, }, { path="/lib/OpenComputersGL/Materials.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/OpenComputersGL/Materials.lua", type="Library", - version=1.08, + version=1.09, }, { path="/lib/OpenComputersGL/Renderer.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/OpenComputersGL/Renderer.lua", type="Library", - version=1.08, + version=1.09, }, { path="/lib/MeowEngine/Main.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/MeowEngine/Main.lua", type="Library", - version=1.08, + version=1.09, }, ----------------------------------------------------- Скрипты и дополнения к ним -------------------------------------------------------------------------- @@ -414,21 +445,21 @@ }, ----------------------------------------------------- Screensavers -------------------------------------------------------------------------- { - path="/MineOS/System/OS/Screensavers/Matrix.lua", + path="/MineOS/System/Screensavers/Matrix.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Screensavers/Matrix.lua", type="Script", forceDownload=true, version=1.02, }, { - path="/MineOS/System/OS/Screensavers/Mandala.lua", + path="/MineOS/System/Screensavers/Mandala.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Screensavers/Mandala.lua", type="Script", forceDownload=true, version=1.00, }, { - path="/MineOS/System/OS/Screensavers/Clock.lua", + path="/MineOS/System/Screensavers/Clock.lua", url="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/MineOS/Screensavers/Clock.lua", type="Script", forceDownload=true, @@ -443,7 +474,7 @@ icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/Icon.pic", createShortcut="dock", forceDownload=true, - version=1.74, + version=1.75, resources={ { path="/Localization/Russian.lang", @@ -463,7 +494,7 @@ icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DTest/Icon.pic", createShortcut="desktop", forceDownload=true, - version=1.20, + version=1.21, }, { path="/MineOS/Applications/GeoScan2", @@ -540,7 +571,7 @@ type="Application", icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/3DPrint/Icon.pic", createShortcut="desktop", - version=1.12, + version=1.13, }, { path="/MineOS/Applications/FlappyBird", @@ -687,7 +718,7 @@ type="Application", icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/PrintImage/Icon.pic", createShortcut="desktop", - version=1.12, + version=1.13, }, { path="/MineOS/Applications/Palette", @@ -801,7 +832,7 @@ icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/Photoshop/Icon.pic", createShortcut="dock", forceDownload=true, - version=1.06, + version=1.07, resources={ { path="/Localization/Russian.lang", @@ -967,7 +998,7 @@ type="Application", icon="https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications/BufferDemo/Icon.pic", createShortcut="desktop", - version=1.0, + version=1.01, resources={ { path="/Wallpaper.pic", diff --git a/Applications/3DPrint/3DPrint.lua b/Applications/3DPrint/3DPrint.lua index ba4400af..abccb780 100755 --- a/Applications/3DPrint/3DPrint.lua +++ b/Applications/3DPrint/3DPrint.lua @@ -434,8 +434,8 @@ model = {} fixModelArray() local args = {...} -if args[1] == "open" or args[1] == "-o" then - open(args[2]) +if args[1] and fs.exists(args[1]) then + open(args[1]) end drawAll() diff --git a/Applications/3DTest/3DTest.lua b/Applications/3DTest/3DTest.lua old mode 100644 new mode 100755 index 0d6ecb61..0ee576a7 --- a/Applications/3DTest/3DTest.lua +++ b/Applications/3DTest/3DTest.lua @@ -418,11 +418,11 @@ mainContainer.toolbar.zBufferSwitch = mainContainer.toolbar:addChild(GUI.switch( local function calculateLightComboBox() - mainContainer.toolbar.lightSelectComboBox.items = {} + mainContainer.toolbar.lightSelectComboBox.dropDownMenu.itemsContainer.children = {} for i = 1, #scene.lights do mainContainer.toolbar.lightSelectComboBox:addItem(tostring(i)) end - mainContainer.toolbar.lightSelectComboBox.selectedItem = #mainContainer.toolbar.lightSelectComboBox.items + mainContainer.toolbar.lightSelectComboBox.selectedItem = #mainContainer.toolbar.lightSelectComboBox.dropDownMenu.itemsContainer.children mainContainer.toolbar.lightIntensitySlider.value = scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].intensity * 100 mainContainer.toolbar.lightEmissionSlider.value = scene.lights[mainContainer.toolbar.lightSelectComboBox.selectedItem].emissionDistance end diff --git a/Applications/BufferDemo/BufferDemo.lua b/Applications/BufferDemo/BufferDemo.lua old mode 100644 new mode 100755 index dd6e4f7a..35536f7d --- a/Applications/BufferDemo/BufferDemo.lua +++ b/Applications/BufferDemo/BufferDemo.lua @@ -16,7 +16,7 @@ buffer.start() local function drawBackground() --Заполним весь наш экран цветом фона 0x262626, цветом текста 0xFFFFFF и символом " " if not risovatKartinku then - buffer.square(1, 1, buffer.screen.width, buffer.screen.height, currentBackground, 0xFFFFFF, " ") + buffer.square(1, 1, buffer.width, buffer.height, currentBackground, 0xFFFFFF, " ") else buffer.image(1, 1, fon) end @@ -119,7 +119,7 @@ while true do drawWindow(xWindow, yWindow) buffer.draw() elseif e[4] == 28 then - buffer.square(1, 1, buffer.screen.width, buffer.screen.height, 0x262626, 0xFFFFFF, " ") + buffer.square(1, 1, buffer.width, buffer.height, 0x262626, 0xFFFFFF, " ") buffer.draw() return elseif e[4] == 57 then diff --git a/Applications/MineCodeIDE/MineCodeIDE.lua b/Applications/MineCodeIDE/MineCodeIDE.lua index e23953f4..ac774fbc 100755 --- a/Applications/MineCodeIDE/MineCodeIDE.lua +++ b/Applications/MineCodeIDE/MineCodeIDE.lua @@ -1,13 +1,14 @@ ---------------------------------------------------- Libraries ---------------------------------------------------- --- "/MineOS/Applications/MineCode IDE.app/MineCode IDE.lua" open /OS.lua +-- "/MineOS/Applications/MineCode IDE.app/MineCode IDE.lua" -o /OS.lua -- package.loaded.syntax = nil -- package.loaded.ECSAPI = nil -- package.loaded.GUI = nil -- package.loaded.MineOSCore = nil +local args = {...} require("advancedLua") local computer = require("computer") local component = require("component") @@ -26,8 +27,6 @@ local term = require("term") ---------------------------------------------------- Constants ---------------------------------------------------- -local args = {...} - local about = { "MineCode IDE", "Copyright © 2014-2017 ECS Inc.", @@ -128,7 +127,6 @@ local findStartFrom local clipboard local breakpointLines local lastErrorLine -local lastClickUptime = computer.uptime() local autocompleteDatabase ------------------------------------------------------------------------------------------------------------------ @@ -1353,7 +1351,7 @@ end local function createMainContainer() mainContainer = GUI.fullScreenContainer() - + mainContainer.codeView = mainContainer:addChild(GUI.codeView(1, 1, 1, 1, {""}, 1, 1, 1, {}, {}, config.highlightLuaSyntax, 2)) mainContainer.codeView.scrollBars.vertical.onTouch = function() mainContainer.codeView.fromLine = mainContainer.codeView.scrollBars.vertical.value @@ -1655,14 +1653,16 @@ local function createMainContainer() createEditOrRightClickMenu(eventData[3], eventData[4]) else setCursorPositionAndClearSelection(convertScreenCoordinatesToTextPosition(eventData[3], eventData[4])) - - local newUptime = computer.uptime() - if newUptime - lastClickUptime <= config.doubleClickDelay then selectWord() end - lastClickUptime = newUptime end cursor.blinkState = true tick() + elseif eventData[1] == "double_touch" then + cursor.blinkState = true + selectWord() + + mainContainer:draw() + buffer.draw() elseif eventData[1] == "drag" then if eventData[5] ~= 1 then mainContainer.codeView.selections[1] = mainContainer.codeView.selections[1] or {from = {}, to = {}} @@ -1830,8 +1830,8 @@ updateTitle() updateRAMProgressBar() mainContainer:draw() -if args[1] == "open" and fs.exists(args[2] or "") then - loadFile(args[2]) +if args[1] and fs.exists(args[1]) then + loadFile(args[1]) else newFile() end diff --git a/Applications/Photoshop/Photoshop.lua b/Applications/Photoshop/Photoshop.lua index b4031a72..7f2c1f2c 100755 --- a/Applications/Photoshop/Photoshop.lua +++ b/Applications/Photoshop/Photoshop.lua @@ -907,8 +907,8 @@ end drawAll() --Открываем файлы по аргументам программы -if args[1] == "o" or args[1] == "open" or args[1] == "-o" or args[1] == "load" then - loadImageFromFile(args[2]) +if args[1] and fs.exists(args[1]) then + loadImageFromFile(args[1]) else new() end @@ -1029,9 +1029,15 @@ while true do currentInstrument = key drawLeftBar(); buffer.draw() if instruments[currentInstrument] == "S" then - local action = GUI.contextMenu(obj["Instruments"][key][3] + 1, obj["Instruments"][key][2], {localization.line}, {localization.ellipse}, {localization.rectangle}, {localization.polygon}, {localization.border}):show() - currentShape = action or localization.line + local menu = GUI.contextMenu(obj["Instruments"][key][3] + 1, obj["Instruments"][key][2]) + menu:addItem(localization.line) + menu:addItem(localization.ellipse) + menu:addItem(localization.rectangle) + menu:addItem(localization.polygon) + menu:addItem(localization.border) + local action = menu:show() + currentShape = action or localization.line if currentShape == localization.polygon then local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, @@ -1062,20 +1068,33 @@ while true do buffer.draw() local action if object.text == localization.file then - action = GUI.contextMenu(object.x, object.y + 1, {localization.new, false, "^N"}, {localization.open, false, "^O"}, {localization.createFromString}, "-", {localization.save, (savePath == nil), "^S"}, {localization.saveAs}, "-", {localization.exit}):show() + local menu = GUI.contextMenu(object.x, object.y + 1) + + menu:addItem(localization.new, false, "^N") + menu:addItem(localization.open, false, "^O") + menu:addItem(localization.createFromString) + menu:addSeparator() + menu:addItem(localization.save, savePath == nil, "^S") + menu:addItem(localization.saveAs) + menu:addSeparator() + menu:addItem(localization.exit) + + action = menu:show() elseif object.text == localization.image then - action = GUI.contextMenu(object.x, object.y + 1, - -- {localization.crop}, - {localization.expand}, - -- "-", - -- {localization.rotateBy90}, - -- {localization.rotateBy180}, - "-", - {localization.flipHorizontal}, - {localization.flipVertical} - ):show() + local menu = GUI.contextMenu(object.x, object.y + 1) + + menu:addItem(localization.expand) + menu:addSeparator() + menu:addItem(localization.flipHorizontal) + menu:addItem(localization.flipVertical) + + action = menu:show() elseif object.text == localization.view then - action = GUI.contextMenu(object.x, object.y + 1, {localization.transparencyPad}):show() + local menu = GUI.contextMenu(object.x, object.y + 1) + + menu:addItem(localization.transparencyPad) + + action = menu:show() elseif object.text == localization.about then ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, photoshopVersion}, {"EmptyLine"}, {"CenterText", 0x262626, localization.developers}, {"CenterText", 0x555555, "Тимофеев Игорь"}, {"CenterText", 0x656565, "vk.com/id7799889"}, {"CenterText", 0x656565, "Трифонов Глеб"}, {"CenterText", 0x656565, "vk.com/id88323331"}, {"EmptyLine"}, {"CenterText", 0x262626, localization.testers}, {"CenterText", 0x656565, "Шестаков Тимофей"}, {"CenterText", 0x656565, "vk.com/id113499693"}, {"CenterText", 0x656565, "Вечтомов Роман"}, {"CenterText", 0x656565, "vk.com/id83715030"}, {"CenterText", 0x656565, "Омелаенко Максим"}, {"CenterText", 0x656565, "vk.com/paladincvm"}, {"EmptyLine"},{"Button", {0xbbbbbb, 0xffffff, "OK"}}) elseif object.text == localization.hotkeys then @@ -1259,16 +1278,17 @@ while true do if ecs.clickedAtArea(e[3], e[4], sizes.xStartOfImage, sizes.yStartOfImage, sizes.xEndOfImage, sizes.yEndOfImage) then if instruments[currentInstrument] == "M" and selection then - local action = GUI.contextMenu(e[3], e[4], - {localization.deselect}, - {localization.crop}, - "-", - {localization.fill}, - {localization.border}, - "-", - {localization.clear} - ):show() + local menu = GUI.contextMenu(e[3], e[4]) + + menu:addItem(localization.deselect) + menu:addItem(localization.crop) + menu:addSeparator() + menu:addItem(localization.fill) + menu:addItem(localization.border) + menu:addSeparator() + menu:addItem(localization.clear) + action = menu:show() if action == localization.deselect then selection = nil drawAll() diff --git a/Applications/PrintImage/PrintImage.lua b/Applications/PrintImage/PrintImage.lua index 0fc1ba05..22771add 100755 --- a/Applications/PrintImage/PrintImage.lua +++ b/Applications/PrintImage/PrintImage.lua @@ -15,7 +15,7 @@ local GUI = require("GUI") if not component.isAvailable("printer3d") then GUI.error("This program requires at least one 3D-printer"); return end local args, options = require("shell").parse(...) -local startImagePath = args[1] == "open" and args[2] or "/MineOS/System/OS/Icons/Steve.pic" +local startImagePath = args[1] == "open" and args[2] or "/MineOS/System/Icons/Steve.pic" local configPath = "/MineOS/System/PrintImage/Config.cfg" local panelWidth = 34 local mainContainer diff --git a/MineOS/Extension associations/lua/Context menu.lua b/MineOS/Extension associations/lua/Context menu.lua new file mode 100755 index 00000000..fbce40a6 --- /dev/null +++ b/MineOS/Extension associations/lua/Context menu.lua @@ -0,0 +1,27 @@ + +local args = {...} +local component = require("component") +local computer = require("computer") +local MineOSCore = require("MineOSCore") +local fs = require("filesystem") + +local icon, menu = args[1], args[2] +menu:addItem(MineOSCore.localization.edit).onTouch = function() + MineOSCore.safeLaunch(MineOSCore.paths.editor, icon.path) +end + +menu:addSeparator() + +menu:addItem(MineOSCore.localization.launchWithArguments).onTouch = function() + MineOSCore.launchWithArguments(MineOSCore.OSMainContainer, icon.path) +end + +menu:addItem(MineOSCore.localization.flashEEPROM, not component.isAvailable("eeprom") or fs.size(icon.path) > 4096).onTouch = function() + computer.beep(1500, 0.2) + local file = io.open(icon.path, "r") + component.eeprom.set(file:read("*a")) + file:close() + for i = 1, 2 do + computer.beep(2000, 0.2) + end +end \ No newline at end of file diff --git a/MineOS/Extension associations/lua/Launcher.lua b/MineOS/Extension associations/lua/Launcher.lua new file mode 100755 index 00000000..47c9c4d4 --- /dev/null +++ b/MineOS/Extension associations/lua/Launcher.lua @@ -0,0 +1,8 @@ + +local args = {...} +local MineOSCore = require("MineOSCore") + +MineOSCore.clearTerminal() +if MineOSCore.safeLaunch(args[1]) then + MineOSCore.waitForPressingAnyKey() +end diff --git a/MineOS/Extension associations/pic/Context menu.lua b/MineOS/Extension associations/pic/Context menu.lua new file mode 100755 index 00000000..06124f22 --- /dev/null +++ b/MineOS/Extension associations/pic/Context menu.lua @@ -0,0 +1,12 @@ + +local args = {...} +local computer = require("computer") +local MineOSCore = require("MineOSCore") + +local icon, menu = args[1], args[2] +menu:addItem(MineOSCore.localization.setAsWallpaper).onTouch = function() + MineOSCore.OSSettings.wallpaperEnabled = true + MineOSCore.OSSettings.wallpaper = icon.path + MineOSCore.saveOSSettings() + computer.pushSignal("MineOSCore", "updateWallpaper") +end diff --git a/MineOS/Extension associations/pkg/Launcher.lua b/MineOS/Extension associations/pkg/Launcher.lua new file mode 100755 index 00000000..7fef8b91 --- /dev/null +++ b/MineOS/Extension associations/pkg/Launcher.lua @@ -0,0 +1,5 @@ + +local args = {...} +local fs = require("filesystem") + +require("compressor").unpack(args[1], fs.path(args[1])) \ No newline at end of file diff --git a/MineOS/Localization/English.lang b/MineOS/Localization/English.lang old mode 100644 new mode 100755 index be62902d..cec075da --- a/MineOS/Localization/English.lang +++ b/MineOS/Localization/English.lang @@ -1,4 +1,6 @@ { + openWith = "Open with", + select = "Choose application…", keepInDock = "Keep in dock", launchWithArguments = "Launch with arguments", dontShowAnymore = "Don't show again", @@ -7,13 +9,24 @@ folderName = "Folder name", fileName = "File name", applicationName = "Application name", - fileAlreadyExists = "File already exists", + file = "File", + notExists = "not exists", + alreadyExists = "already exists", + inDirectory = "in directory", + needReplace = "Replace it?", + yes = "Yes", + no = "No", + cancel = "Cancel", + applyToAll = "Apply to all", + toDirectory = "to directory", + copying = "Copying", + faylaBlyad = "file", resolution = "Screen resolution", pressAnyKeyToContinue = "Press any key to continue", screensaver = "Screensaver", screensaverDelay = "Delay", - screensaverDisabled = "Disabled", + screensaverEnabled = "Screensaver enabled", areYouSure = "Are you sure?", emptyTrash = "Empty trash", @@ -24,34 +37,37 @@ folder = "Folder", unknown = "Unknown", calculatingSize = "calculating…", - contextMenuProperties = "Properties", - contextMenuNewFile = "New file", - contextMenuNewFolder = "New folder", - contextMenuNewApplication = "New MineOS application", - contextMenuPaste = "Paste", - contextMenuCopy = "Copy", - contextMenuCut = "Cut", - contextMenuRemoveWallpaper = "Remove wallpaper", - contextMenuEdit = "Edit", - contextMenuEditInPhotoshop = "Edit in Photoshop", - contextMenuRename = "Rename", - contextMenuCreateShortcut = "Create shortcut", - contextMenuAddToDock = "Add to Dock", - contextMenuRemoveFromDock = "Remove from Dock", - contextMenuMoveRight = "Move right", - contextMenuMoveLeft = "Move left", - contextMenuArchive = "Add to archive", - contextMenuDelete = "Delete", - contextMenuAddToFavourites = "Add to favourites", - contextMenuCreateApplication = "Create MineOS application", - contextMenuSetAsWallpaper = "Set as wallpaper", - contextMenuShowPackageContent = "Show package content", - contextMenuShowContainingFolder = "Show containing folder", - contextMenuFlashEEPROM = "Write file to EEPROM", - sortByType = "Sort by type", - sortByName = "Sort by name", - sortByDate = "Sort by date", + view = "View", + properties = "Properties", + newFolder = "New folder", + newFolderFromChosen = "New folder from chosen", + newFile = "New file", + newApplication = "New MineOS application", + paste = "Paste", + copy = "Copy", + cut = "Cut", + edit = "Edit", + editInPhotoshop = "Edit in Photoshop", + rename = "Rename", + editShortcut = "Edit shortcut", + createShortcut = "Create shortcut", + addToDock = "Add to Dock", + removeFromDock = "Remove from Dock", + moveRight = "Move right", + moveLeft = "Move left", + archive = "Add to archive", + delete = "Delete", + addToFavourites = "Add to favourites", + setAsWallpaper = "Set as wallpaper", + showPackageContent = "Show package content", + showContainingFolder = "Show containing folder", + flashEEPROM = "Write on EEPROM", + + sortBy = "Sorting method", + sortByType = "By type", + sortByName = "By name", + sortByDate = "By date", showExtension = "Show file extension", hideExtension = "Hide file extension", showHiddenFiles = "Show hidden files", @@ -87,22 +103,41 @@ mineOSCreatorUsedMasterPassword = "The creator of this operating system has used Master-Password", loginToSystem = "Login", - appearance = "Appearance", - wallpaperProperties = "Wallpaper properties", colorScheme = "Color scheme", + wallpaper = "Wallpaper", wallpaperPath = "Path to wallpaper", wallpaperModeStretch = "Stretch", wallpaperModeCenter = "Center", + wallpaperEnabled = "Wallpaper enabled", + wallpaperSwitchInfo = "Disabling this option will decrease RAM usage and increase system perfomance", backgroundColor = "Background color", - interfaceColor = "Interface color", + menuColor = "Menu color", + dockColor = "Dock color", + transparencyEnabled = "Transparency enabled", + transparencySwitchInfo = "Disabling this option will increase system perfomance", screenResolution = "Screen resolution", changePassword = "Change password", - cancel = "Cancel", - shortcut = "shortcut", - shortcutIsCorrupted = "Shortcut is corrupted", + shortcutIsCorrupted = "Shortcut is linked to non-existent file", + sortAutomatically = "Align to grid", + onDesktop = "On desktop", + inCurrentDirectory = "In current directory", settings = "Preferences", - viewTab = "View", + months = { + Jan = "Jan", + Feb = "Feb", + Mar = "Mar", + Apr = "Apr", + May = "May", + Jun = "Jun", + Jul = "Jul", + Aug = "Aug", + Sep = "Sep", + Oct = "Oct", + Nov = "Nov", + Dec = "Dec", + }, + timezone = "Timezone", errorWhileRunningProgram = "Error while running ", sendedFeedback = "Feedback was sent", diff --git a/MineOS/Localization/Russian.lang b/MineOS/Localization/Russian.lang old mode 100644 new mode 100755 index debb6a9a..fd83c35d --- a/MineOS/Localization/Russian.lang +++ b/MineOS/Localization/Russian.lang @@ -1,4 +1,6 @@ { + openWith = "Открыть с помощью", + select = "Выбрать программу…", keepInDock = "Оставить в Dock", launchWithArguments = "Запустить с аргументами", dontShowAnymore = "Больше не показывать", @@ -7,13 +9,24 @@ folderName = "Имя папки", fileName = "Имя файла", applicationName = "Имя приложения", - fileAlreadyExists = "Файл уже существует", + file = "Файл", + notExists = "не существует", + alreadyExists = "уже существует", + inDirectory = "в директории", + needReplace = "Заменить?", + yes = "Да", + no = "Нет", + cancel = "Отмена", + applyToAll = "Применить ко всем", + toDirectory = "в директории", + copying = "Копирование", + faylaBlyad = "файла", resolution = "Разрешение экрана", pressAnyKeyToContinue = "Нажмите любую клавишу, чтобы продолжить", screensaver = "Заставка", screensaverDelay = "Задержка", - screensaverDisabled = "Отключена", + screensaverEnabled = "Использовать заставку", areYouSure = "Вы уверены?", emptyTrash = "Очистить корзину", @@ -24,34 +37,37 @@ folder = "Папка", unknown = "Неизвестно", calculatingSize = "идет подсчет…", - contextMenuProperties = "Свойства", - contextMenuNewFile = "Новый файл", - contextMenuNewFolder = "Новая папка", - contextMenuNewApplication = "Новое приложение MineOS", - contextMenuPaste = "Вставить", - contextMenuCopy = "Копировать", - contextMenuCut = "Вырезать", - contextMenuRemoveWallpaper = "Удалить обои", - contextMenuEdit = "Редактировать", - contextMenuEditInPhotoshop = "Редактировать в Photoshop", - contextMenuRename = "Переименовать", - contextMenuCreateShortcut = "Создать ярлык", - contextMenuAddToDock = "Добавить в Dock", - contextMenuRemoveFromDock = "Удалить из Dock", - contextMenuMoveRight = "Передвинуть правее", - contextMenuMoveLeft = "Передвинуть левее", - contextMenuArchive = "Добавить в архив", - contextMenuDelete = "Удалить", - contextMenuAddToFavourites = "Добавить в избранное", - contextMenuCreateApplication = "Создать приложение MineOS", - contextMenuSetAsWallpaper = "Установить как обои", - contextMenuShowPackageContent = "Показать содержимое пакета", - contextMenuShowContainingFolder = "Открыть содержащую папку", - contextMenuFlashEEPROM = "Записать файл на EEPROM", + + view = "Вид", + properties = "Свойства", + newFolder = "Новая папка", + newFolderFromChosen = "Новая папка из выбранного", + newFile = "Новый файл", + newApplication = "Новое приложение MineOS", + paste = "Вставить", + copy = "Копировать", + cut = "Вырезать", + edit = "Редактировать", + editInPhotoshop = "Редактировать в Photoshop", + rename = "Переименовать", + editShortcut = "Редактировать ярлык", + createShortcut = "Создать ярлык", + addToDock = "Добавить в Dock", + removeFromDock = "Удалить из Dock", + moveRight = "Передвинуть правее", + moveLeft = "Передвинуть левее", + archive = "Добавить в архив", + delete = "Удалить", + addToFavourites = "Добавить в избранное", + setAsWallpaper = "Установить как обои", + showPackageContent = "Показать содержимое пакета", + showContainingFolder = "Открыть содержащую папку", + flashEEPROM = "Записать на EEPROM", - sortByType = "Сортировать по типу", - sortByName = "Сортировать по имени", - sortByDate = "Сортировать по дате", + sortBy = "Сортировка файлов", + sortByType = "По типу", + sortByName = "По имени", + sortByDate = "По дате", showExtension = "Показывать расширение файлов", hideExtension = "Скрывать расширение файлов", showHiddenFiles = "Показывать скрытые файлы", @@ -87,22 +103,41 @@ mineOSCreatorUsedMasterPassword = "Создатель операционной системы использовал мастер-ключ", loginToSystem = "Вход в систему", - appearance = "Внешний вид", - wallpaperProperties = "Параметры обоев", colorScheme = "Цветовая схема", + wallpaper = "Обои", wallpaperPath = "Путь к обоям", wallpaperModeStretch = "Растянуть", wallpaperModeCenter = "По центру", + wallpaperEnabled = "Использовать обои", + wallpaperSwitchInfo = "Отключение этой опции существенно снизит расход оперативной памяти и увеличит производительность", backgroundColor = "Цвет фона", - interfaceColor = "Цвет интерфейса", + menuColor = "Цвет меню", + dockColor = "Цвет Dock", + transparencyEnabled = "Прозрачность интерфейса", + transparencySwitchInfo = "Отключение этой опции существенно снизит количество прямых обращений к CPU и увеличит производительность", screenResolution = "Разрешение экрана", changePassword = "Изменить пароль", - cancel = "Отмена", - shortcut = "ярлык", - shortcutIsCorrupted = "Файл ярлыка поврежден или имеет неизвестный формат", + shortcutIsCorrupted = "Ярлык ссылается на несуществующий файл", + sortAutomatically = "Привязать к сетке", + onDesktop = "На рабочем столе", + inCurrentDirectory = "В текущей директории", settings = "Настройки", - viewTab = "Вид", + months = { + Jan = "Января", + Feb = "Февраля", + Mar = "Марта", + Apr = "Апреля", + May = "Мая", + Jun = "Июня", + Jul = "Июля", + Aug = "Августа", + Sep = "Сентября", + Oct = "Октября", + Nov = "Ноября", + Dec = "Декабря", + }, + timezone = "Временная зона", errorWhileRunningProgram = "Ошибка при выполнении ", sendedFeedback = "Отчет отправлен", diff --git a/MineOS/OS.lua b/MineOS/OS.lua index 87c4ec25..59872219 100755 --- a/MineOS/OS.lua +++ b/MineOS/OS.lua @@ -1,27 +1,31 @@ ---------------------------------------------- Копирайт, епта ------------------------------------------------------------------------ -local copyright = [[ +local copyright = { - Тут можно было бы написать кучу текста, мол, - вы не имеете прав на использование этой хуйни в - коммерческих целях и прочую чушь, навеянную нам - западной культурой. Но я же не пидор какой-то, верно? + "Тут можно было бы написать кучу текста, мол,", + "вы не имеете прав на использование этой хуйни в", + "коммерческих целях и прочую чушь, навеянную нам", + "западной культурой. Но я же не пидор какой-то, верно?", + "", + "Просто помни, что эту ОСь накодил Тимофеев Игорь,", + "ссылка на ВК: vk.com/id7799889" - Просто помни, что эту ОСь накодил Тимофеев Игорь, - ссылка на ВК: vk.com/id7799889 - -]] +} -- Вычищаем копирайт из оперативки, ибо мы не можем тратить СТОЛЬКО памяти. --- Сколько тут, раз, два, три... 286 UTF-8 символов! --- А это, между прочим, 57 раз по слову "Пидор". Но один раз - не пидорас, поэтому очищаем. -copyright = nil +-- Сколько тут, раз, два, три... 270 UTF-8 символов! +-- А это, между прочим, 54 раза по слову "Пидор". Но один раз - не пидорас, поэтому вычищаем. +-- ... +-- Бля, передумал, не вычищаем, еще пригодится ниже. Вот же костыльная параша! + +-- copyright = nil ---------------------------------------------- Либсы-хуибсы ------------------------------------------------------------------------ -- package.loaded.MineOSCore = nil +local computer = require("computer") local component = require("component") local unicode = require("unicode") local fs = require("filesystem") @@ -30,107 +34,124 @@ local image = require("image") local buffer = require("doubleBuffering") local GUI = require("GUI") local MineOSCore = require("MineOSCore") -local ecs = require("ECSAPI") ---------------------------------------------- Всякая константная залупа ------------------------------------------------------------------------ -local colors = { - background = 0x1B1B1B, - topBarTransparency = 20, - selection = ecs.colors.lightBlue, - interface = 0xCCCCCC, - dockBaseTransparency = 60, - dockTransparencyAdder = 8, - iconsSelectionTransparency = 20, - desktopCounter = 0x999999, - desktopCounterActive = 0xFFFFFF, - desktopPainting = 0xEEEEEE, -} +local menuTransparency = 20 +local dockTransparency = 50 -local sizes = { - heightOfDock = 6, - xSpaceBetweenIcons = 2, - ySpaceBetweenIcons = 1, -} +local computerUptimeOnBoot = computer.uptime() +local computerDateUptime = computerUptimeOnBoot +local realTimestamp +local timezoneCorrection +local screensaversPath = MineOSCore.paths.system .. "Screensavers/" +local screensaverUptime = computerUptimeOnBoot -local screensaversPath, screensaverTimer = MineOSCore.paths.system .. "OS/Screensavers/", 0 -local currentWorkpathHistoryIndex, workpathHistory = 1, {MineOSCore.paths.desktop} -local currentDesktop, countOfDesktops = 1 +local currentWorkpathHistoryIndex = 1 +local workpathHistory = { MineOSCore.paths.desktop } +local currentDesktop = 1 +local countOfDesktops = 1 ---------------------------------------------- Система защиты пекарни ------------------------------------------------------------------------ -local function drawBiometry(backgroundColor, textColor, text) - local width, height = 70, 21 - local fingerWidth, fingerHeight = 24, 14 - local x, y = math.floor(buffer.width / 2 - width / 2), math.floor(buffer.height / 2 - height / 2) +local function biometry(creatingNew) + local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer) + + local fingerImage = container.layout:addChild(GUI.image(1, 1, image.fromString([[180E0000FF 0000FF 0000FF 0000FF 0000FF 00FFFF▄00FFFF▄00FFFF▄00FFFF▄FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀00FFFF▄00FFFF▄00FFFF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFFFF▀FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 00FFFF▄00FFFF▄FFFF00▄FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF 00FFFF▄FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF FFFF00▄0000FF 00FFFF▄FFFF00▄0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF 0000FF 00FFFF▄00FFFF▄FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀FFFFFF▀00FFFF▄0000FF FFFF00▄00FFFF▄0000FF FFFFFF▀FFFF00▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 00FFFF▄00FFFF▄00FFFF▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 00FFFF▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 00FFFF▄FFFF00▄FFFF00▄00FFFF▄0000FF 0000FF FFFF00▄00FFFF▄0000FF FFFFFF▀FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF FFFF00▄FFFFFF▀0000FF FFFF00▄0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF FFFFFF▀FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 00FFFF▄FFFF00▄0000FF 00FFFF▄FFFFFF▀0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 00FFFF▄FFFFFF▀0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄0000FF 0000FF 0000FF FFFFFF▀FFFF00▄00FFFF▄0000FF 0000FF 0000FF 0000FF 00FFFF▄FFFFFF▀0000FF 0000FF 0000FF 00FFFF▄FFFF00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF FFFF00▄00FFFF▄0000FF 0000FF 0000FF FFFFFF▀0000FF 0000FF 0000FF 0000FF FFFFFF▀0000FF 0000FF 00FFFF▄FFFF00▄FFFFFF▀0000FF 0000FF 0000FF 0000FF ]]))) + local text = creatingNew and MineOSCore.localization.putFingerToRegister or MineOSCore.localization.putFingerToVerify + local label = container.layout:addChild(GUI.label(1, 1, container.width, 1, 0xEEEEEE, text):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + + local lineWidth = image.getWidth(fingerImage.image) + 6 + local scanLine = container:addChild(GUI.label(1, 1, container.width, 1, 0xFFFFFF, string.rep("─", lineWidth)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + scanLine.hidden = true - buffer.square(x, y, width, height, backgroundColor, 0x000000, " ", nil) - buffer.image(math.floor(x + width / 2 - fingerWidth / 2), y + 2, image.fromString([[180E0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 000000 000000 000000 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 000000 0000FF 0000FF 0000FF 0000FF 000000 000000 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 000000 000000 000000 0000FF 0000FF 000000 000000 000000 000000 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 000000 000000 000000 000000 000000 0000FF 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 000000 0000FF 0000FF 0000FF 000000 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 000000 000000 0000FF 0000FF 000000 0000FF 000000 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 0000FF 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 000000 0000FF 0000FF 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 0000FF 0000FF 000000 0000FF 0000FF 000000 0000FF 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 0000FF 0000FF 0000FF 000000 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 000000 0000FF 0000FF 0000FF 0000FF 000000 0000FF 000000 0000FF 0000FF 0000FF 000000 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 000000 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 000000 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 000000 0000FF 0000FF 000000 000000 0000FF 0000FF 0000FF 0000FF 0000FF ]])) - buffer.text(math.floor(x + width / 2 - unicode.len(text) / 2), y + height - 3, textColor, text) - buffer.draw() -end + local delay = 0.8 -local function waitForBiometry(username) - drawBiometry(0xDDDDDD, 0x000000, username and MineOSCore.localization.putFingerToVerify or MineOSCore.localization.putFingerToRegister) - while true do - local e = {event.pull("touch")} - local success = false - local touchedHash = require("SHA2").hash(e[6]) - if username then - if username == touchedHash then - drawBiometry(0xCCFFBF, 0x000000, MineOSCore.localization.welcomeBack .. e[6]) - success = true + local function scanLineCycle(reverse, step) + local top = fingerImage.y - 1 + local bottom = fingerImage.y + image.getHeight(fingerImage.image) + + local from = reverse and bottom or top + local to = reverse and top + 1 or bottom + local step = reverse and -step or step + + for i = from, to, step do + scanLine.localPosition.y = i + MineOSCore.OSDraw() + end + end + + fingerImage.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + scanLine.hidden = false + scanLineCycle(true, 1) + scanLineCycle(false, 1) + scanLine.hidden = true + + local touchedHash = require("SHA2").hash(eventData[6]) + + if creatingNew then + label.text = MineOSCore.localization.fingerprintCreated + + MineOSCore.OSDraw() + + MineOSCore.OSSettings.protectionMethod = "biometric" + MineOSCore.OSSettings.biometryHash = touchedHash + MineOSCore.saveOSSettings() + + container:delete() + os.sleep(delay) else - drawBiometry(0x770000, 0xFFFFFF, MineOSCore.localization.accessDenied) - end - else - drawBiometry(0xCCFFBF, 0x000000, MineOSCore.localization.fingerprintCreated) - success = true - end - os.sleep(0.2) - MineOSCore.OSMainContainer:draw() - buffer.draw() - return success, e[6] - end -end + if touchedHash == MineOSCore.OSSettings.biometryHash then + label.text = MineOSCore.localization.welcomeBack .. eventData[6] + + MineOSCore.OSDraw() -local function setBiometry() - while true do - local success, username = waitForBiometry() - if success then - MineOSCore.OSSettings.protectionMethod = "biometric" - MineOSCore.OSSettings.passwordHash = require("SHA2").hash(username) - MineOSCore.saveOSSettings() - break + container:delete() + os.sleep(delay) + else + label.text = MineOSCore.localization.accessDenied + local oldBackground = container.panel.colors.background + container.panel.colors.background = 0x550000 + + MineOSCore.OSDraw() + + os.sleep(delay) + + label.text = text + container.panel.colors.background = oldBackground + end + end + + MineOSCore.OSDraw() end end + label.eventHandler, container.panel.eventHandler = fingerImage.eventHandler, fingerImage.eventHandler + + MineOSCore.OSDraw() end local function checkPassword() local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.inputPassword) local inputField = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, nil, nil, true, "*")) - local label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, " ")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + local label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, MineOSCore.localization.incorrectPassword)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + label.hidden = true inputField.onInputFinished = function() local hash = require("SHA2").hash(inputField.text or "") if hash == MineOSCore.OSSettings.passwordHash then container:delete() - MineOSCore.OSMainContainer:draw() - buffer.draw() elseif hash == "c925be318b0530650b06d7f0f6a51d8289b5925f1b4117a43746bc99f1f81bc1" then GUI.error(MineOSCore.localization.mineOSCreatorUsedMasterPassword) container:delete() - MineOSCore.OSMainContainer:draw() - buffer.draw() else - label.text = MineOSCore.localization.incorrectPassword - MineOSCore.OSMainContainer:draw() - buffer.draw() + label.hidden = false end + + MineOSCore.OSDraw() end - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() inputField:startInput() end @@ -138,10 +159,10 @@ local function setPassword() local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.passwordProtection) local inputField1 = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, nil, MineOSCore.localization.inputPassword, true, "*")) local inputField2 = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, nil, MineOSCore.localization.confirmInputPassword, true, "*")) - local label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, " ")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + local label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, MineOSCore.localization.passwordsAreDifferent)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + label.hidden = true - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() container.panel.eventHandler = function(mainContainer, object, eventData) if eventData[1] == "touch" then @@ -152,11 +173,10 @@ local function setPassword() MineOSCore.OSSettings.passwordHash = require("SHA2").hash(inputField1.text or "") MineOSCore.saveOSSettings() else - label.text = MineOSCore.localization.passwordsAreDifferent + label.hidden = false end - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() end end end @@ -178,11 +198,10 @@ local function setProtectionMethod() container.panel.eventHandler = function(mainContainer, object, eventData) if eventData[1] == "touch" then container:delete() - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() if comboBox.selectedItem == 1 then - setBiometry() + biometry(true) elseif comboBox.selectedItem == 2 then setPassword() elseif comboBox.selectedItem == 3 then @@ -193,29 +212,26 @@ local function setProtectionMethod() end local function login() - event.interuptingEnabled = false + event.interruptingEnabled = false + if not MineOSCore.OSSettings.protectionMethod then setProtectionMethod() elseif MineOSCore.OSSettings.protectionMethod == "password" then checkPassword() elseif MineOSCore.OSSettings.protectionMethod == "biometric" then - while true do - local success, username = waitForBiometry(MineOSCore.OSSettings.passwordHash) - if success then break end - end + biometry() end - event.interuptingEnabled = true - MineOSCore.OSMainContainer:draw() - buffer.draw() + event.interruptingEnabled = true + MineOSCore.OSDraw() end ---------------------------------------------- Основные функции ------------------------------------------------------------------------ local function changeWallpaper() - if MineOSCore.OSSettings.wallpaper and fs.exists(MineOSCore.OSSettings.wallpaper) then - MineOSCore.OSMainContainer.background.wallpaper = nil - + MineOSCore.OSMainContainer.background.wallpaper = nil + + if MineOSCore.OSSettings.wallpaperEnabled and MineOSCore.OSSettings.wallpaper and fs.exists(MineOSCore.OSSettings.wallpaper) then if MineOSCore.OSSettings.wallpaperMode == 1 then MineOSCore.OSMainContainer.background.wallpaper = image.transform(image.load(MineOSCore.OSSettings.wallpaper), MineOSCore.OSMainContainer.width, MineOSCore.OSMainContainer.height) MineOSCore.OSMainContainer.background.wallpaperPosition.x, MineOSCore.OSMainContainer.background.wallpaperPosition.y = 1, 1 @@ -224,8 +240,6 @@ local function changeWallpaper() MineOSCore.OSMainContainer.background.wallpaperPosition.x = math.floor(MineOSCore.OSMainContainer.width / 2 - image.getWidth(MineOSCore.OSMainContainer.background.wallpaper) / 2) MineOSCore.OSMainContainer.background.wallpaperPosition.y = math.floor(MineOSCore.OSMainContainer.height / 2 - image.getHeight(MineOSCore.OSMainContainer.background.wallpaper) / 2) end - else - MineOSCore.OSMainContainer.background.wallpaper = nil end end @@ -243,21 +257,21 @@ local function updateDesktopCounters() MineOSCore.OSMainContainer.desktopCounters:addChild(GUI.button(x, 1, 1, 1, nil, 0xEEEEEE, nil, 0x888888, "<")).onTouch = function() table.remove(workpathHistory, #workpathHistory) changeWorkpath(#workpathHistory) - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end; x = x + 3 end if workpathHistory[currentWorkpathHistoryIndex] ~= "/" then MineOSCore.OSMainContainer.desktopCounters:addChild(GUI.button(x, 1, 4, 1, nil, 0xEEEEEE, nil, 0x888888, "Root")).onTouch = function() table.insert(workpathHistory, "/") changeWorkpath(#workpathHistory) - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end; x = x + 6 end if workpathHistory[currentWorkpathHistoryIndex] ~= MineOSCore.paths.desktop then MineOSCore.OSMainContainer.desktopCounters:addChild(GUI.button(x, 1, 7, 1, nil, 0xEEEEEE, nil, 0x888888, "Desktop")).onTouch = function() table.insert(workpathHistory, MineOSCore.paths.desktop) changeWorkpath(#workpathHistory) - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end; x = x + 9 end if countOfDesktops > 1 then @@ -265,7 +279,7 @@ local function updateDesktopCounters() MineOSCore.OSMainContainer.desktopCounters:addChild(GUI.button(x, 1, 1, 1, nil, i == currentDesktop and 0xEEEEEE or 0xBBBBBB, nil, 0x888888, "●")).onTouch = function() if currentDesktop ~= i then currentDesktop = i - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end end; x = x + 3 end @@ -273,7 +287,7 @@ local function updateDesktopCounters() MineOSCore.OSMainContainer.desktopCounters.width = x - 3 MineOSCore.OSMainContainer.desktopCounters.localPosition.x = math.floor(MineOSCore.OSMainContainer.width / 2 - MineOSCore.OSMainContainer.desktopCounters.width / 2) - MineOSCore.OSMainContainer.desktopCounters.localPosition.y = MineOSCore.OSMainContainer.height - sizes.heightOfDock - 2 + MineOSCore.OSMainContainer.desktopCounters.localPosition.y = MineOSCore.OSMainContainer.height - MineOSCore.OSMainContainer.dockContainer.height - 2 end ---------------------------------------------- Всякая параша для ОС-контейнера ------------------------------------------------------------------------ @@ -284,12 +298,20 @@ local function changeResolution() MineOSCore.OSMainContainer.width, MineOSCore.OSMainContainer.height = buffer.width, buffer.height - MineOSCore.OSMainContainer.iconField.width, MineOSCore.OSMainContainer.iconField.height = MineOSCore.OSMainContainer.width, MineOSCore.OSMainContainer.height - sizes.heightOfDock - 5 - MineOSCore.OSMainContainer.iconField.iconCount.width, MineOSCore.OSMainContainer.iconField.iconCount.height, MineOSCore.OSMainContainer.iconField.iconCount.total = MineOSCore.getParametersForDrawingIcons(MineOSCore.OSMainContainer.iconField.width, MineOSCore.OSMainContainer.iconField.height, sizes.xSpaceBetweenIcons, sizes.ySpaceBetweenIcons) - MineOSCore.OSMainContainer.iconField.localPosition.x = math.floor(MineOSCore.OSMainContainer.width / 2 - (MineOSCore.OSMainContainer.iconField.iconCount.width * (MineOSCore.iconWidth + sizes.xSpaceBetweenIcons) - sizes.xSpaceBetweenIcons) / 2) + MineOSCore.OSMainContainer.iconField.width, MineOSCore.OSMainContainer.iconField.height = MineOSCore.OSMainContainer.width, MineOSCore.OSMainContainer.height - MineOSCore.OSMainContainer.dockContainer.height - 5 + MineOSCore.OSMainContainer.iconField:update() + MineOSCore.OSMainContainer.iconField.localPosition.x = math.floor( + MineOSCore.OSMainContainer.width / 2 - + ( + MineOSCore.OSMainContainer.iconField.iconCount.horizontal * + (MineOSCore.iconWidth + MineOSCore.OSMainContainer.iconField.spaceBetweenIcons.horizontal) - + MineOSCore.OSMainContainer.iconField.spaceBetweenIcons.horizontal + ) / 2 + ) MineOSCore.OSMainContainer.iconField.localPosition.y = 3 - MineOSCore.OSMainContainer.dockContainer.localPosition.y = MineOSCore.OSMainContainer.height - sizes.heightOfDock + 1 + MineOSCore.OSMainContainer.dockContainer.localPosition.x = math.floor(MineOSCore.OSMainContainer.width / 2 - MineOSCore.OSMainContainer.dockContainer.width / 2) + MineOSCore.OSMainContainer.dockContainer.localPosition.y = MineOSCore.OSMainContainer.height - MineOSCore.OSMainContainer.dockContainer.height + 1 MineOSCore.OSMainContainer.menu.width = MineOSCore.OSMainContainer.width MineOSCore.OSMainContainer.background.width, MineOSCore.OSMainContainer.background.height = MineOSCore.OSMainContainer.width, MineOSCore.OSMainContainer.height @@ -301,8 +323,11 @@ local function moveDockIcon(index, direction) MineOSCore.OSMainContainer.dockContainer.children[index], MineOSCore.OSMainContainer.dockContainer.children[index + direction] = MineOSCore.OSMainContainer.dockContainer.children[index + direction], MineOSCore.OSMainContainer.dockContainer.children[index] MineOSCore.OSMainContainer.dockContainer.sort() MineOSCore.OSMainContainer.dockContainer.saveToOSSettings() - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() +end + +local function getTimezoneText(timezone) + return "GMT" .. (timezone >= 0 and "+" or "") .. timezone end local function createOSWindow() @@ -311,37 +336,28 @@ local function createOSWindow() MineOSCore.OSMainContainer.background = MineOSCore.OSMainContainer:addChild(GUI.object(1, 1, 1, 1)) MineOSCore.OSMainContainer.background.wallpaperPosition = {x = 1, y = 1} MineOSCore.OSMainContainer.background.draw = function(object) - buffer.square(object.x, object.y, object.width, object.height, MineOSCore.OSSettings.backgroundColor or colors.background, 0x0, " ") + buffer.square(object.x, object.y, object.width, object.height, MineOSCore.OSSettings.backgroundColor or 0x0F0F0F, 0x0, " ") if object.wallpaper then buffer.image(object.wallpaperPosition.x, object.wallpaperPosition.y, object.wallpaper) end end - MineOSCore.OSMainContainer.background.eventHandler = function(mainContainer, object, eventData) - if eventData[1] == "touch" then - if eventData[5] == 1 then - MineOSCore.emptyZoneClick(eventData, MineOSCore.OSMainContainer, MineOSCore.OSMainContainer.iconField.workpath) - end - end - end MineOSCore.OSMainContainer.desktopCounters = MineOSCore.OSMainContainer:addChild(GUI.container(1, 1, 1, 1)) MineOSCore.OSMainContainer.iconField = MineOSCore.OSMainContainer:addChild( - MineOSCore.createIconField( - 1, 1, 1, 1, 1, 1, 1, - sizes.xSpaceBetweenIcons, - sizes.ySpaceBetweenIcons, + MineOSCore.iconField( + 1, 1, 1, 1, 2, 1, + 0xFFFFFF, 0xFFFFFF, MineOSCore.OSSettings.showExtension, MineOSCore.OSSettings.showHiddenFiles, MineOSCore.OSSettings.sortingMethod or "type", - "/", - 0xFFFFFF + "/" ) ) -- Dock - MineOSCore.OSMainContainer.dockContainer = MineOSCore.OSMainContainer:addChild(GUI.container(1, 1, MineOSCore.OSMainContainer.width, sizes.heightOfDock)) + MineOSCore.OSMainContainer.dockContainer = MineOSCore.OSMainContainer:addChild(GUI.container(1, 1, MineOSCore.OSMainContainer.width, 6)) MineOSCore.OSMainContainer.dockContainer.saveToOSSettings = function() MineOSCore.OSSettings.dockShortcuts = {} for i = 1, #MineOSCore.OSMainContainer.dockContainer.children do @@ -355,15 +371,14 @@ local function createOSWindow() local x = 1 for i = 1, #MineOSCore.OSMainContainer.dockContainer.children do MineOSCore.OSMainContainer.dockContainer.children[i].localPosition.x = x - x = x + MineOSCore.iconWidth + sizes.xSpaceBetweenIcons + x = x + MineOSCore.iconWidth + MineOSCore.OSMainContainer.iconField.spaceBetweenIcons.horizontal end - MineOSCore.OSMainContainer.dockContainer.width = (#MineOSCore.OSMainContainer.dockContainer.children) * (MineOSCore.iconWidth + sizes.xSpaceBetweenIcons) - sizes.xSpaceBetweenIcons - MineOSCore.OSMainContainer.dockContainer.localPosition.x = math.floor(MineOSCore.OSMainContainer.width / 2 - MineOSCore.OSMainContainer.dockContainer.width / 2) + MineOSCore.OSMainContainer.dockContainer.width = (#MineOSCore.OSMainContainer.dockContainer.children) * (MineOSCore.iconWidth + MineOSCore.OSMainContainer.iconField.spaceBetweenIcons.horizontal) - MineOSCore.OSMainContainer.iconField.spaceBetweenIcons.horizontal end MineOSCore.OSMainContainer.dockContainer.addIcon = function(path, window) - local icon = MineOSCore.OSMainContainer.dockContainer:addChild(MineOSCore.createIcon(1, 1, path, 0x262626, MineOSCore.OSSettings.showExtension, 0xFFFFFF)) + local icon = MineOSCore.OSMainContainer.dockContainer:addChild(MineOSCore.icon(1, 1, path, 0x262626, 0xFFFFFF, MineOSCore.OSSettings.showExtension)) icon:moveBackward() icon.window = window @@ -372,30 +387,31 @@ local function createOSWindow() icon.window.hidden = false icon.window:moveToFront() else - MineOSCore.iconLeftClick(icon, eventData) + MineOSCore.iconDoubleClick(icon, eventData) end + icon.selected = false end icon.onRightClick = function(icon, eventData) local indexOf = icon:indexOf() - local menu = GUI.contextMenu(eventData[3], eventData[4]) - menu:addItem(MineOSCore.localization.contextMenuShowContainingFolder).onTouch = function() + local menu = MineOSCore.contextMenu(eventData[3], eventData[4]) + menu:addItem(MineOSCore.localization.showContainingFolder).onTouch = function() table.insert(workpathHistory, fs.path(icon.path)) changeWorkpath(#workpathHistory) - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end menu:addSeparator() - menu:addItem(MineOSCore.localization.contextMenuMoveRight, indexOf >= #MineOSCore.OSMainContainer.dockContainer.children - 1).onTouch = function() + menu:addItem(MineOSCore.localization.moveRight, indexOf >= #MineOSCore.OSMainContainer.dockContainer.children - 1).onTouch = function() moveDockIcon(indexOf, 1) end - menu:addItem(MineOSCore.localization.contextMenuMoveLeft, indexOf <= 1).onTouch = function() + menu:addItem(MineOSCore.localization.moveLeft, indexOf <= 1).onTouch = function() moveDockIcon(indexOf, -1) end menu:addSeparator() if icon.keepInDock then if #MineOSCore.OSMainContainer.dockContainer.children > 1 then - menu:addItem(MineOSCore.localization.contextMenuRemoveFromDock).onTouch = function() + menu:addItem(MineOSCore.localization.removeFromDock).onTouch = function() if icon.window then icon.keepInDock = nil else @@ -403,8 +419,7 @@ local function createOSWindow() MineOSCore.OSMainContainer.dockContainer.sort() end MineOSCore.OSMainContainer.dockContainer.saveToOSSettings() - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() end end else @@ -428,26 +443,24 @@ local function createOSWindow() local icon = MineOSCore.OSMainContainer.dockContainer.addIcon(MineOSCore.paths.trash) icon.image = MineOSCore.icons.trash icon.onRightClick = function(icon, eventData) - local menu = GUI.contextMenu(eventData[3], eventData[4]) + local menu = MineOSCore.contextMenu(eventData[3], eventData[4]) menu:addItem(MineOSCore.localization.emptyTrash).onTouch = function() local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.areYouSure) - container.layout:addChild(GUI.button(1, 1, 30, 3, 0xEEEEEE, 0x262626, 0xA, 0x262626, "OK")).onTouch = function() + container.layout:addChild(GUI.button(1, 1, 30, 1, 0xEEEEEE, 0x262626, 0xA, 0x262626, "OK")).onTouch = function() for file in fs.list(MineOSCore.paths.trash) do fs.remove(MineOSCore.paths.trash .. file) end container:delete() - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end container.panel.onTouch = function() container:delete() - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() end - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() end menu:show() end @@ -457,183 +470,70 @@ local function createOSWindow() end MineOSCore.OSMainContainer.dockContainer.draw = function(dockContainer) - local color, currentDockTransparency, currentDockWidth, xPos, yPos = MineOSCore.OSSettings.interfaceColor or colors.interface, colors.dockBaseTransparency, dockContainer.width, dockContainer.x, dockContainer.y + 2 + local color, currentDockTransparency, currentDockWidth, xPos, yPos = MineOSCore.OSSettings.dockColor or 0xFFFFFF, dockTransparency, dockContainer.width + 6, dockContainer.x - 3, dockContainer.y + dockContainer.height - 1 - for i = 1, dockContainer.height do - buffer.text(xPos, yPos, color, "◢", currentDockTransparency) - buffer.square(xPos + 1, yPos, currentDockWidth - 2, 1, color, 0xFFFFFF, " ", currentDockTransparency) - buffer.text(xPos + currentDockWidth - 1, yPos, color, "◣", currentDockTransparency) + for i = 1, dockContainer.height - 2 do + buffer.text(xPos, yPos, color, "◢", MineOSCore.OSSettings.transparencyEnabled and currentDockTransparency) + buffer.square(xPos + 1, yPos, currentDockWidth - 2, 1, color, 0xFFFFFF, " ", MineOSCore.OSSettings.transparencyEnabled and currentDockTransparency) + buffer.text(xPos + currentDockWidth - 1, yPos, color, "◣", MineOSCore.OSSettings.transparencyEnabled and currentDockTransparency) - currentDockTransparency, currentDockWidth, xPos, yPos = currentDockTransparency - colors.dockTransparencyAdder, currentDockWidth + 2, xPos - 1, yPos + 1 + currentDockTransparency, currentDockWidth, xPos, yPos = currentDockTransparency + 8, currentDockWidth - 2, xPos + 1, yPos - 1 + if currentDockTransparency > 100 then + currentDockTransparency = 100 + end end GUI.drawContainerContent(dockContainer) end - -- Windows + -- Custom windows support MineOSCore.OSMainContainer.windowsContainer = MineOSCore.OSMainContainer:addChild(GUI.container(1, 2, 1, 1)) - -- Menu - MineOSCore.OSMainContainer.menu = MineOSCore.OSMainContainer:addChild(GUI.menu(1, 1, MineOSCore.OSMainContainer.width, MineOSCore.OSSettings.interfaceColor or colors.interface, 0x444444, 0x3366CC, 0xFFFFFF, colors.topBarTransparency)) + -- Main menu + MineOSCore.OSMainContainer.menu = MineOSCore.OSMainContainer:addChild(GUI.menu(1, 1, MineOSCore.OSMainContainer.width, MineOSCore.OSSettings.menuColor or 0xFFFFFF, 0x444444, 0x3366CC, 0xFFFFFF, MineOSCore.OSSettings.transparencyEnabled and menuTransparency)) local item1 = MineOSCore.OSMainContainer.menu:addItem("MineOS", 0x000000) item1.onTouch = function() - local menu = GUI.contextMenu(item1.x, item1.y + 1) + local menu = MineOSCore.contextMenu(item1.x, item1.y + 1) + + menu:addItem(MineOSCore.localization.aboutSystem).onTouch = function() + local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.aboutSystem) + container.layout:addChild(GUI.textBox(1, 1, 53, #copyright, nil, 0xBBBBBB, copyright, 1, 0, 0)) + end + menu:addItem(MineOSCore.localization.updates).onTouch = function() MineOSCore.safeLaunch("/MineOS/Applications/AppMarket.app/Main.lua", "updates") end + menu:addSeparator() + menu:addItem(MineOSCore.localization.logout, MineOSCore.OSSettings.protectionMethod == "withoutProtection").onTouch = function() login() end + menu:addItem(MineOSCore.localization.reboot).onTouch = function() - -- ecs.TV(0) require("computer").shutdown(true) dofile("/bin/reboot.lua") end + menu:addItem(MineOSCore.localization.shutdown).onTouch = function() - -- ecs.TV(0) require("computer").shutdown() end + menu:addSeparator() + menu:addItem(MineOSCore.localization.returnToShell).onTouch = function() MineOSCore.OSMainContainer:stopEventHandling() - ecs.prepareToExit() + MineOSCore.clearTerminal() os.exit() end + menu:show() end - local item2 = MineOSCore.OSMainContainer.menu:addItem(MineOSCore.localization.viewTab) + local item2 = MineOSCore.OSMainContainer.menu:addItem(MineOSCore.localization.settings) item2.onTouch = function() - local menu = GUI.contextMenu(item2.x, item2.y + 1) - menu:addItem(MineOSCore.OSMainContainer.iconField.showExtension and MineOSCore.localization.hideExtension or MineOSCore.localization.showExtension).onTouch = function() - MineOSCore.OSMainContainer.iconField.showExtension = not MineOSCore.OSMainContainer.iconField.showExtension - MineOSCore.OSSettings.showExtension = MineOSCore.OSMainContainer.iconField.showExtension - MineOSCore.saveOSSettings() - MineOSCore.OSMainContainer.updateAndDraw() - end - menu:addItem(MineOSCore.OSMainContainer.iconField.showHiddenFiles and MineOSCore.localization.hideHiddenFiles or MineOSCore.localization.showHiddenFiles).onTouch = function() - MineOSCore.OSMainContainer.iconField.showHiddenFiles = not MineOSCore.OSMainContainer.iconField.showHiddenFiles - MineOSCore.OSSettings.showHiddenFiles = MineOSCore.OSMainContainer.iconField.showHiddenFiles - MineOSCore.saveOSSettings() - MineOSCore.OSMainContainer.updateAndDraw() - end - menu:addItem(MineOSCore.showApplicationIcons and MineOSCore.localization.hideApplicationIcons or MineOSCore.localization.showApplicationIcons).onTouch = function() - MineOSCore.showApplicationIcons = not MineOSCore.showApplicationIcons - MineOSCore.OSMainContainer.updateAndDraw() - end - menu:addSeparator() - menu:addItem(MineOSCore.localization.sortByName).onTouch = function() - MineOSCore.OSSettings.sortingMethod = "name" - MineOSCore.saveOSSettings() - MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod - MineOSCore.OSMainContainer.updateAndDraw() - end - menu:addItem(MineOSCore.localization.sortByDate).onTouch = function() - MineOSCore.OSSettings.sortingMethod = "date" - MineOSCore.saveOSSettings() - MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod - MineOSCore.OSMainContainer.updateAndDraw() - end - menu:addItem(MineOSCore.localization.sortByType).onTouch = function() - MineOSCore.OSSettings.sortingMethod = "type" - MineOSCore.saveOSSettings() - MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod - MineOSCore.OSMainContainer.updateAndDraw() - end - menu:addSeparator() - menu:addItem(MineOSCore.localization.screensaver).onTouch = function() - local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.screensaver) - - local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xEEEEEE, 0x262626, 0x666666, 0xEEEEEE)) - comboBox:addItem(MineOSCore.localization.screensaverDisabled) - for file in fs.list(screensaversPath) do - comboBox:addItem(fs.hideExtension(file)) - end - local slider = container.layout:addChild(GUI.slider(1, 1, 36, 0xFFDB40, 0xEEEEEE, 0xFFDB80, 0xBBBBBB, 1, 100, MineOSCore.OSSettings.screensaverDelay or 20, false, MineOSCore.localization.screensaverDelay .. ": ", "")) - - MineOSCore.OSMainContainer:draw() - buffer.draw() - - container.panel.eventHandler = function(mainContainer, object, eventData) - if eventData[1] == "touch" then - container:delete() - if comboBox.selectedItem == 1 then - MineOSCore.OSSettings.screensaver = nil - else - MineOSCore.OSSettings.screensaver, MineOSCore.OSSettings.screensaverDelay = comboBox.items[comboBox.selectedItem].text, slider.value - end - MineOSCore.saveOSSettings() - - MineOSCore.OSMainContainer:draw() - buffer.draw() - end - end - end - menu:addItem(MineOSCore.localization.appearance).onTouch = function() - local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.wallpaperProperties) - - local inputField = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x999999, 0xEEEEEE, 0x262626, MineOSCore.OSSettings.wallpaper, MineOSCore.localization.wallpaperPath, true)) - local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xEEEEEE, 0x262626, 0x666666, 0xEEEEEE)) - comboBox.selectedItem = MineOSCore.OSSettings.wallpaperMode or 1 - comboBox:addItem(MineOSCore.localization.wallpaperModeStretch) - comboBox:addItem(MineOSCore.localization.wallpaperModeCenter) - - container.layout:addChild(GUI.label(1, 1, 36, 1, 0xEEEEEE, MineOSCore.localization.colorScheme)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) - local backgroundColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.OSSettings.backgroundColor or colors.background, MineOSCore.localization.backgroundColor)) - local interfaceColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.OSSettings.interfaceColor or colors.interface, MineOSCore.localization.interfaceColor)) - - comboBox.onItemSelected = function() - MineOSCore.OSSettings.wallpaperMode = comboBox.selectedItem - MineOSCore.saveOSSettings() - changeWallpaper() - - MineOSCore.OSMainContainer:draw() - buffer.draw() - end - - inputField.onInputFinished = function() - MineOSCore.OSSettings.wallpaper = inputField.text - MineOSCore.saveOSSettings() - changeWallpaper() - - MineOSCore.OSMainContainer:draw() - buffer.draw() - end - - backgroundColorSelector.onTouch = function() - MineOSCore.OSSettings.backgroundColor, MineOSCore.OSSettings.interfaceColor = backgroundColorSelector.color, interfaceColorSelector.color - MineOSCore.OSMainContainer.menu.colors.default.background = MineOSCore.OSSettings.interfaceColor - MineOSCore.saveOSSettings() - - MineOSCore.OSMainContainer:draw() - buffer.draw() - end - interfaceColorSelector.onTouch = backgroundColorSelector.onTouch - - container.panel.eventHandler = function(mainContainer, object, eventData) - if eventData[1] == "touch" then - container:delete() - MineOSCore.OSMainContainer:draw() - buffer.draw() - end - end - - MineOSCore.OSMainContainer:draw() - buffer.draw() - end - - menu:addItem(MineOSCore.localization.contextMenuRemoveWallpaper, not MineOSCore.OSMainContainer.background.wallpaper).onTouch = function() - MineOSCore.OSSettings.wallpaper = nil - MineOSCore.saveOSSettings() - changeWallpaper() - end - menu:show() - end - - local item3 = MineOSCore.OSMainContainer.menu:addItem(MineOSCore.localization.settings) - item3.onTouch = function() - local menu = GUI.contextMenu(item3.x, item3.y + 1) + local menu = MineOSCore.contextMenu(item2.x, item2.y + 1) + menu:addItem(MineOSCore.localization.screenResolution).onTouch = function() local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.screenResolution) @@ -656,27 +556,192 @@ local function createOSWindow() MineOSCore.saveOSSettings() changeResolution() changeWallpaper() - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end end end + menu:addSeparator() + + menu:addItem(MineOSCore.localization.wallpaper).onTouch = function() + local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.wallpaper) + + local inputField = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x999999, 0xEEEEEE, 0x262626, MineOSCore.OSSettings.wallpaper, MineOSCore.localization.wallpaperPath, false)) + + local label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, MineOSCore.localization.file .. " " .. MineOSCore.localization.notExists)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + label.hidden = fs.exists(inputField.text) + + local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xEEEEEE, 0x262626, 0x666666, 0xEEEEEE)) + comboBox.selectedItem = MineOSCore.OSSettings.wallpaperMode or 1 + comboBox:addItem(MineOSCore.localization.wallpaperModeStretch) + comboBox:addItem(MineOSCore.localization.wallpaperModeCenter) + + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xEEEEEE, 0xBBBBBB, MineOSCore.localization.wallpaperEnabled .. ":", MineOSCore.OSSettings.wallpaperEnabled)).switch + container.layout:addChild(GUI.textBox(1, 1, 36, 1, nil, 0x555555, {MineOSCore.localization.wallpaperSwitchInfo}, 1, 0, 0, true, true)) + + switch.onStateChanged = function() + MineOSCore.OSSettings.wallpaperEnabled = switch.state + MineOSCore.saveOSSettings() + changeWallpaper() + + MineOSCore.OSDraw() + end + inputField.onInputFinished = function() + MineOSCore.OSSettings.wallpaper = inputField.text + MineOSCore.saveOSSettings() + changeWallpaper() + + label.hidden = fs.exists(inputField.text) + + MineOSCore.OSDraw() + end + comboBox.onItemSelected = function() + MineOSCore.OSSettings.wallpaperMode = comboBox.selectedItem + MineOSCore.saveOSSettings() + changeWallpaper() + + MineOSCore.OSDraw() + end + end + menu:addItem(MineOSCore.localization.screensaver).onTouch = function() + local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.screensaver) + + local comboBox = container.layout:addChild(GUI.comboBox(1, 1, 36, 3, 0xEEEEEE, 0x262626, 0x666666, 0xEEEEEE)) + local fileList = fs.sortedList(screensaversPath, "name", false) + for i = 1, #fileList do + comboBox:addItem(fs.hideExtension(fileList[i])) + if MineOSCore.OSSettings.screensaver == fileList[i] then + comboBox.selectedItem = i + end + end + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xEEEEEE, 0xBBBBBB, MineOSCore.localization.screensaverEnabled .. ":", MineOSCore.OSSettings.screensaverEnabled)).switch + local slider = container.layout:addChild(GUI.slider(1, 1, 36, 0x66DB80, 0x2D2D2D, 0xEEEEEE, 0xBBBBBB, 1, 100, MineOSCore.OSSettings.screensaverDelay or 20, false, MineOSCore.localization.screensaverDelay .. ": ", "")) + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + container:delete() + MineOSCore.OSDraw() + + MineOSCore.OSSettings.screensaverEnabled = switch.state + MineOSCore.OSSettings.screensaver = fileList[comboBox.selectedItem] + MineOSCore.OSSettings.screensaverDelay = slider.value + + MineOSCore.saveOSSettings() + end + end + + MineOSCore.OSDraw() + end + + menu:addItem(MineOSCore.localization.colorScheme).onTouch = function() + local container = MineOSCore.addUniversalContainer(MineOSCore.OSMainContainer, MineOSCore.localization.colorScheme) + + local backgroundColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.OSSettings.backgroundColor or 0x0F0F0F, MineOSCore.localization.backgroundColor)) + local menuColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.OSSettings.menuColor or 0xFFFFFF, MineOSCore.localization.menuColor)) + local dockColorSelector = container.layout:addChild(GUI.colorSelector(1, 1, 36, 3, MineOSCore.OSSettings.dockColor or 0xFFFFFF, MineOSCore.localization.dockColor)) + + local switch = container.layout:addChild(GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0x2D2D2D, 0xEEEEEE, 0xEEEEEE, MineOSCore.localization.transparencyEnabled .. ":", MineOSCore.OSSettings.transparencyEnabled)).switch + switch.onStateChanged = function() + MineOSCore.OSSettings.transparencyEnabled = switch.state + MineOSCore.saveOSSettings() + MineOSCore.OSMainContainer.menu.colors.transparency = MineOSCore.OSSettings.transparencyEnabled and menuTransparency + container.panel.colors.background = switch.state and 0x0 or (MineOSCore.OSSettings.backgroundColor or 0x0F0F0F) + container.panel.colors.transparency = switch.state and 20 + + MineOSCore.OSDraw() + end + container.layout:addChild(GUI.textBox(1, 1, 36, 1, nil, 0x555555, {MineOSCore.localization.transparencySwitchInfo}, 1, 0, 0, true, true)) + + -- Шоб рисовалось в реальном времени + backgroundColorSelector.onTouch = function() + MineOSCore.OSSettings.backgroundColor = backgroundColorSelector.color + MineOSCore.OSSettings.menuColor = menuColorSelector.color + MineOSCore.OSSettings.dockColor = dockColorSelector.color + MineOSCore.OSMainContainer.menu.colors.default.background = MineOSCore.OSSettings.menuColor + + MineOSCore.OSDraw() + end + menuColorSelector.onTouch = backgroundColorSelector.onTouch + dockColorSelector.onTouch = backgroundColorSelector.onTouch + + container.panel.eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + container:delete() + MineOSCore.OSDraw() + + MineOSCore.saveOSSettings() + end + end + end + + menu:addSeparator() + menu:addItem(MineOSCore.localization.setProtectionMethod).onTouch = function() setProtectionMethod() end + + menu:show() + end + + local dateLabel = MineOSCore.OSMainContainer:addChild(GUI.label(1, 1, 1, 1, 0x444444, " ")) + local dateButton = MineOSCore.OSMainContainer:addChild(GUI.button(1, 1, 1, 1, nil, 0x888888, 0x3366CC, 0xFFFFFF, " ")) + + dateButton.onTouch = function() + local menu = GUI.contextMenu(dateButton.x, dateButton.y + 1) + for i = -12, 12 do + menu:addItem(getTimezoneText(i)).onTouch = function() + MineOSCore.OSSettings.timezone = i + MineOSCore.saveOSSettings() + + MineOSCore.OSUpdateTimezone() + MineOSCore.OSUpdateDate() + MineOSCore.OSDraw() + end + end menu:show() end - MineOSCore.OSMainContainer.update = function() + MineOSCore.OSUpdateTimezone = function() + local timezone = MineOSCore.OSSettings.timezone or 0 + timezoneCorrection = timezone * 3600 + dateButton.text = getTimezoneText(timezone) + end + + MineOSCore.OSUpdateDate = function() + if not realTimestamp then + local name = MineOSCore.paths.system .. "/Timestamp.tmp" + local file = io.open(name, "w") + file:close() + realTimestamp = math.floor(fs.lastModified(name) / 1000) + fs.remove(name) + end + + local firstPart, month, secondPart = os.date( + "%d %b %Y %T", + realTimestamp + computerDateUptime - computerUptimeOnBoot + timezoneCorrection + ):match("(%d+%s)(%a+)(.+)") + + dateLabel.text = firstPart .. (MineOSCore.localization.months[month] or "monthNotAvailable:" .. month) .. secondPart + dateLabel.width = unicode.len(dateLabel.text) + dateButton.width = unicode.len(dateButton.text) + 2 + dateLabel.localPosition.x = MineOSCore.OSMainContainer.width - dateLabel.width + dateButton.localPosition.x = dateLabel.localPosition.x - dateButton.width - 1 + end + + MineOSCore.OSMainContainer.updateFileList = function() MineOSCore.OSMainContainer.iconField.fromFile = (currentDesktop - 1) * MineOSCore.OSMainContainer.iconField.iconCount.total + 1 MineOSCore.OSMainContainer.iconField:updateFileList() updateDesktopCounters() end - MineOSCore.OSMainContainer.updateAndDraw = function(forceRedraw) - MineOSCore.OSMainContainer.update() + MineOSCore.OSDraw = function(force) MineOSCore.OSMainContainer:draw() - buffer.draw(forceRedraw) + buffer.draw(force) + end + + MineOSCore.OSMainContainer.updateFileListAndDraw = function(forceRedraw) + MineOSCore.OSMainContainer.updateFileList() + MineOSCore.OSDraw(forceRedraw) end MineOSCore.OSMainContainer.eventHandler = function(mainContainer, object, eventData) @@ -684,26 +749,25 @@ local function createOSWindow() if eventData[5] == 1 then if currentDesktop < countOfDesktops then currentDesktop = currentDesktop + 1 - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end else if currentDesktop > 1 then currentDesktop = currentDesktop - 1 - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() end end elseif eventData[1] == "MineOSCore" then if eventData[2] == "updateFileList" then - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() elseif eventData[2] == "updateFileListAndBufferTrueRedraw" then - MineOSCore.OSMainContainer.updateAndDraw(true) + MineOSCore.OSMainContainer.updateFileListAndDraw(true) elseif eventData[2] == "changeWorkpath" then table.insert(workpathHistory, eventData[3]) changeWorkpath(#workpathHistory) elseif eventData[2] == "updateWallpaper" then changeWallpaper() - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() elseif eventData[2] == "newApplication" then MineOSCore.newApplication(MineOSCore.OSMainContainer, MineOSCore.OSMainContainer.iconField.workpath) elseif eventData[2] == "newFile" then @@ -715,16 +779,29 @@ local function createOSWindow() elseif eventData[2] == "applicationHelp" then MineOSCore.applicationHelp(MineOSCore.OSMainContainer, eventData[3]) end - elseif not eventData[1] then - screensaverTimer = screensaverTimer + 0.5 - if MineOSCore.OSSettings.screensaver and screensaverTimer > MineOSCore.OSSettings.screensaverDelay and fs.exists(screensaversPath .. MineOSCore.OSSettings.screensaver .. ".lua") then - MineOSCore.safeLaunch(screensaversPath .. MineOSCore.OSSettings.screensaver .. ".lua") - screensaverTimer = 0 - MineOSCore.OSMainContainer:draw() - buffer.draw(true) + end + + local computerUptime = computer.uptime() + + if computerUptime - computerDateUptime >= 1 then + MineOSCore.OSUpdateDate() + MineOSCore.OSDraw() + computerDateUptime = computerUptime + end + + if MineOSCore.OSSettings.screensaverEnabled then + if eventData[1] then + screensaverUptime = computer.uptime() + end + + if computerUptime - screensaverUptime >= MineOSCore.OSSettings.screensaverDelay then + if fs.exists(screensaversPath .. MineOSCore.OSSettings.screensaver) then + MineOSCore.safeLaunch(screensaversPath .. MineOSCore.OSSettings.screensaver) + MineOSCore.OSDraw(true) + end + + screensaverUptime = computer.uptime() end - else - screensaverTimer = 0 end end end @@ -735,11 +812,17 @@ createOSWindow() changeResolution() changeWorkpath(1) changeWallpaper() -MineOSCore.OSMainContainer.update() +MineOSCore.OSMainContainer.updateFileList() +MineOSCore.OSUpdateTimezone() +MineOSCore.OSUpdateDate() login() while true do - local success, path, line, traceback = MineOSCore.call(MineOSCore.OSMainContainer.startEventHandling, MineOSCore.OSMainContainer, 1) + local success, path, line, traceback = MineOSCore.call( + MineOSCore.OSMainContainer.startEventHandling, + MineOSCore.OSMainContainer, + 1 + ) if success then break else @@ -747,11 +830,10 @@ while true do changeResolution() changeWorkpath(1) changeWallpaper() - MineOSCore.OSMainContainer.updateAndDraw() + MineOSCore.OSMainContainer.updateFileListAndDraw() MineOSCore.showErrorWindow(path, line, traceback) - MineOSCore.OSMainContainer:draw() - buffer.draw() + MineOSCore.OSDraw() end end diff --git a/lib/GUI.lua b/lib/GUI.lua index e9590ffa..57cdf8f5 100755 --- a/lib/GUI.lua +++ b/lib/GUI.lua @@ -4,11 +4,12 @@ require("advancedLua") local computer = require("computer") local keyboard = require("keyboard") -local buffer = require("doubleBuffering") local unicode = require("unicode") local event = require("event") local fs = require("filesystem") +local color = require("color") local image = require("image") +local buffer = require("doubleBuffering") ----------------------------------------- Constants ----------------------------------------- @@ -48,21 +49,19 @@ GUI.colors = { text = 0xAAAAAA }, contextMenu = { - separator = 0xAAAAAA, + separator = 0x888888, default = { background = 0xFFFFFF, text = 0x2D2D2D }, - disabled = { - text = 0xAAAAAA - }, + disabled = 0x888888, pressed = { background = 0x3366CC, text = 0xFFFFFF }, transparency = { - background = 20, - shadow = 50 + background = 30, + shadow = 40 } }, windows = { @@ -109,10 +108,16 @@ local function isObjectClicked(object, x, y) not object.hidden end +local function objectDraw(object) + return object +end + -- Main reactangle object to use in everything function GUI.object(x, y, width, height) local rectangle = GUI.rectangle(x, y, width, height) rectangle.isClicked = isObjectClicked + rectangle.draw = objectDraw + return rectangle end @@ -221,7 +226,7 @@ local function containerObjectMoveToBack(object) return object end -local function containerGetFirstParent(object) +local function containerObjectGetFirstParent(object) if object.parent then local currentParent = object.parent while currentParent.parent do @@ -233,21 +238,60 @@ local function containerGetFirstParent(object) end end -local function selfDelete(object) +local function containerObjectSelfDelete(object) table.remove(object.parent.children, containerObjectIndexOf(object)) end +-------------------------------------------------------------------------------------------------------------------------------- + +local function containerObjectAnimationStart(animation, duration) + animation.position = 0 + animation.duration = duration + animation.started = true + animation.startUptime = computer.uptime() + computer.pushSignal("GUIAnimationStart") +end + +local function containerObjectAnimationStop(animation) + animation.position = 0 + animation.started = false +end + +local function containerObjectAnimationDelete(animation) + animation.deleteLater = true +end + +function containerObjectAddAnimation(object, frameHandler, onFinish) + local firstParent = object:getFirstParent() + firstParent.animations = firstParent.animations or {} + table.insert(firstParent.animations, { + object = object, + position = 0, + start = containerObjectAnimationStart, + stop = containerObjectAnimationStop, + delete = containerObjectAnimationDelete, + frameHandler = frameHandler, + onFinish = onFinish, + }) + + return firstParent.animations[#firstParent.animations] +end + -- Add any object as children to parent container function GUI.addChildToContainer(container, object, atIndex) + object.localPosition = { + x = object.x, + y = object.y + } object.indexOf = containerObjectIndexOf object.moveToFront = containerObjectMoveToFront object.moveToBack = containerObjectMoveToBack object.moveForward = containerObjectMoveForward object.moveBackward = containerObjectMoveBackward - object.getFirstParent = containerGetFirstParent - object.delete = selfDelete - object.localPosition = {x = object.x, y = object.y} + object.getFirstParent = containerObjectGetFirstParent + object.delete = containerObjectSelfDelete object.parent = container + object.addAnimation = containerObjectAddAnimation table.insert(container.children, object) @@ -272,6 +316,10 @@ local function getRectangleIntersection(R1X1, R1Y1, R1X2, R1Y2, R2X1, R2Y1, R2X2 end end +function GUI.calculateChildAbsolutePosition(object) + object.x, object.y = object.parent.x + object.localPosition.x - 1, object.parent.y + object.localPosition.y - 1 +end + -- Recursively draw container's content including all children container's content function GUI.drawContainerContent(container) local R1X1, R1Y1, R1X2, R1Y2 = buffer.getDrawLimit() @@ -282,7 +330,7 @@ function GUI.drawContainerContent(container) for objectIndex = 1, #container.children do if not container.children[objectIndex].hidden then - container.children[objectIndex].x, container.children[objectIndex].y = container.children[objectIndex].localPosition.x + container.x - 1, container.children[objectIndex].localPosition.y + container.y - 1 + GUI.calculateChildAbsolutePosition(container.children[objectIndex]) container.children[objectIndex]:draw() end end @@ -293,20 +341,21 @@ function GUI.drawContainerContent(container) return container end -local function handleContainer(isScreenEvent, mainContainer, currentContainer, eventData, x1, y1, x2, y2) +local function containerHandler(isScreenEvent, mainContainer, currentContainer, eventData, x1, y1, x2, y2) local breakRecursion = false if not isScreenEvent or x1 and eventData[3] >= x1 and eventData[4] >= y1 and eventData[3] <= x2 and eventData[4] <= y2 then for i = #currentContainer.children, 1, -1 do if not currentContainer.children[i].hidden then if currentContainer.children[i].children then - if handleContainer(isScreenEvent, mainContainer, currentContainer.children[i], eventData, getRectangleIntersection( - x1, y1, x2, y2, - currentContainer.children[i].x, - currentContainer.children[i].y, - currentContainer.children[i].x + currentContainer.children[i].width - 1, - currentContainer.children[i].y + currentContainer.children[i].height - 1 - )) then + if containerHandler(isScreenEvent, mainContainer, currentContainer.children[i], eventData, getRectangleIntersection( + x1, y1, x2, y2, + currentContainer.children[i].x, + currentContainer.children[i].y, + currentContainer.children[i].x + currentContainer.children[i].width - 1, + currentContainer.children[i].y + currentContainer.children[i].height - 1 + )) + then breakRecursion = true break end @@ -339,15 +388,72 @@ local function handleContainer(isScreenEvent, mainContainer, currentContainer, e end end -local function containerHandleEventData(mainContainer, eventData) - handleContainer(eventData[1] == "touch" or eventData[1] == "drag" or eventData[1] == "drop" or eventData[1] == "scroll", mainContainer, mainContainer, eventData, mainContainer.x, mainContainer.y, mainContainer.x + mainContainer.width - 1, mainContainer.y + mainContainer.height - 1) -end +local function containerStartEventHandling(container, eventHandlingDelay) + container.eventHandlingDelay = eventHandlingDelay -local function containerStartEventHandling(container, pullTime) + local eventData, animationIndex, needDraw while true do - containerHandleEventData(container, {event.pull(pullTime)}) + eventData = {event.pull(container.animations and 0 or container.eventHandlingDelay)} + containerHandler( + eventData[1] == "touch" or + eventData[1] == "drag" or + eventData[1] == "drop" or + eventData[1] == "scroll", + container, + container, + eventData, + container.x, + container.y, + container.x + container.width - 1, + container.y + container.height - 1 + ) + + if container.animations then + animationIndex = 1 + while animationIndex <= #container.animations do + if container.animations[animationIndex].started then + needDraw = true + container.animations[animationIndex].position = (computer.uptime() - container.animations[animationIndex].startUptime) / container.animations[animationIndex].duration + + if container.animations[animationIndex].position <= 1 then + container.animations[animationIndex].frameHandler(container, container.animations[animationIndex].object, container.animations[animationIndex]) + else + container.animations[animationIndex].position = 1 + container.animations[animationIndex].started = false + container.animations[animationIndex].frameHandler(container, container.animations[animationIndex].object, container.animations[animationIndex]) + + if container.animations[animationIndex].onFinish then + needDraw = false + container:draw() + buffer.draw() + container.animations[animationIndex].onFinish(container, container.animations[animationIndex].object, container.animations[animationIndex]) + end + + if container.animations[animationIndex].deleteLater then + table.remove(container.animations, animationIndex) + animationIndex = animationIndex - 1 + end + end + end + + animationIndex = animationIndex + 1 + end + + if needDraw then + container:draw() + buffer.draw() + end + + if #container.animations == 0 then + container.animations = nil + end + end + if container.dataToReturn then - return table.unpack(container.dataToReturn) + local dataToReturn = container.dataToReturn + container.dataToReturn = nil + + return table.unpack(dataToReturn) end end end @@ -383,18 +489,25 @@ end ----------------------------------------- Buttons ----------------------------------------- -local function drawButton(object) +local function buttonDraw(object) local xText, yText = GUI.getAlignmentCoordinates(object, {width = unicode.len(object.text), height = 1}) - local buttonColor = object.disabled and object.colors.disabled.background or (object.pressed and object.colors.pressed.background or object.colors.default.background) - local textColor = object.disabled and object.colors.disabled.text or (object.pressed and object.colors.pressed.text or object.colors.default.text) + + local buttonColor, textColor, transparency = object.colors.default.background, object.colors.default.text, object.colors.default.transparency + if object.disabled then + buttonColor, textColor, transparency = object.colors.disabled.background, object.colors.disabled.text, object.colors.disabled.transparency + else + if object.pressed then + buttonColor, textColor, transparency = object.colors.pressed.background, object.colors.pressed.text, object.colors.pressed.transparency + end + end if buttonColor then if object.buttonType == 1 then - buffer.square(object.x, object.y, object.width, object.height, buttonColor, textColor, " ") + buffer.square(object.x, object.y, object.width, object.height, buttonColor, textColor, " ", transparency) elseif object.buttonType == 2 then - buffer.text(object.x + 1, object.y, buttonColor, string.rep("▄", object.width - 2)) - buffer.square(object.x, object.y + 1, object.width, object.height - 2, buttonColor, textColor, " ") - buffer.text(object.x + 1, object.y + object.height - 1, buttonColor, string.rep("▀", object.width - 2)) + buffer.text(object.x + 1, object.y, buttonColor, string.rep("▄", object.width - 2), transparency) + buffer.square(object.x, object.y + 1, object.width, object.height - 2, buttonColor, textColor, " ", transparency) + buffer.text(object.x + 1, object.y + object.height - 1, buttonColor, string.rep("▀", object.width - 2), transparency) else buffer.frame(object.x, object.y, object.width, object.height, buttonColor) end @@ -405,21 +518,21 @@ local function drawButton(object) return object end -local function pressButton(object) +local function buttonPress(object) object.pressed = true - drawButton(object) + buttonDraw(object) end -local function releaseButton(object) +local function buttonRelease(object) object.pressed = nil - drawButton(object) + buttonDraw(object) end -local function pressAndReleaseButton(object, pressTime) - pressButton(object) +local function buttonPressAndRelease(object, pressTime) + buttonPress(object) buffer.draw() os.sleep(pressTime or 0.2) - releaseButton(object) + buttonRelease(object) buffer.draw() end @@ -443,8 +556,7 @@ local function buttonEventHandler(mainContainer, object, eventData) end end --- Создание таблицы кнопки со всеми необходимыми параметрами -local function createButtonObject(buttonType, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) +local function buttonCreate(buttonType, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) local object = GUI.object(x, y, width, height) object.colors = { @@ -466,10 +578,10 @@ local function createButtonObject(buttonType, x, y, width, height, buttonColor, object.buttonType = buttonType object.disabled = disabledState object.text = text - object.press = pressButton - object.release = releaseButton - object.pressAndRelease = pressAndReleaseButton - object.draw = drawButton + object.press = buttonPress + object.release = buttonRelease + object.pressAndRelease = buttonPressAndRelease + object.draw = buttonDraw object.setAlignment = GUI.setAlignment object:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.center) @@ -479,30 +591,30 @@ end -- Кнопка фиксированных размеров function GUI.button(...) - return createButtonObject(1, ...) + return buttonCreate(1, ...) end -- Кнопка, подстраивающаяся под размер текста function GUI.adaptiveButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) - return createButtonObject(1, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) + return buttonCreate(1, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) end -- Rounded button function GUI.roundedButton(...) - return createButtonObject(2, ...) + return buttonCreate(2, ...) end function GUI.adaptiveRoundedButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) - return createButtonObject(2, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) + return buttonCreate(2, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) end -- Кнопка в рамке function GUI.framedButton(...) - return createButtonObject(3, ...) + return buttonCreate(3, ...) end function GUI.adaptiveFramedButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) - return createButtonObject(3, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) + return buttonCreate(3, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, ...) end ----------------------------------------- TabBar ----------------------------------------- @@ -635,177 +747,6 @@ function GUI.actionButtons(x, y, fatSymbol) return container end ------------------------------------------ Dropdown Menu ----------------------------------------- - -local function drawDropDownMenuElement(object, itemIndex, isPressed) - local y = object.y + (itemIndex - 1) * object.elementHeight - local yText = y + math.floor(object.elementHeight / 2) - if object.items[itemIndex].type == GUI.dropDownMenuElementTypes.default then - local textColor = object.items[itemIndex].disabled and object.colors.disabled.text or (object.items[itemIndex].color or object.colors.default.text) - - -- Нажатие - if isPressed then - buffer.square(object.x, y, object.width, object.elementHeight, object.colors.pressed.background, object.colors.pressed.text, " ") - textColor = object.colors.pressed.text - end - - -- Основной текст - buffer.text(object.x + object.sidesOffset, yText, textColor, string.limit(object.items[itemIndex].text, object.width - object.sidesOffset * 2, "right")) - -- Шурткатикус - if object.items[itemIndex].shortcut then - buffer.text(object.x + object.width - unicode.len(object.items[itemIndex].shortcut) - object.sidesOffset, yText, textColor, object.items[itemIndex].shortcut) - end - else - -- Сепаратор - buffer.text(object.x, yText, object.colors.separator, string.rep("─", object.width)) - end -end - -local function drawDropDownMenu(object) - buffer.square(object.x, object.y, object.width, object.height, object.colors.default.background, object.colors.default.text, " ", object.colors.transparency) - - if object.drawShadow then - GUI.windowShadow(object.x, object.y, object.width, object.height, GUI.colors.contextMenu.transparency.shadow, true) - end - - for itemIndex = 1, #object.items do - drawDropDownMenuElement(object, itemIndex, false) - end -end - -local function showDropDownMenu(object) - object.height = #object.items * object.elementHeight - - local oldPixels = buffer.copy(object.x, object.y, object.width + 1, object.height + 1) - local function quit() - buffer.paste(object.x, object.y, oldPixels) - buffer.draw() - end - - drawDropDownMenu(object) - buffer.draw() - - while true do - local e = {event.pull()} - if e[1] == "touch" then - local objectFound = false - for itemIndex = 1, #object.items do - if - e[3] >= object.x and - e[3] <= object.x + object.width - 1 and - e[4] >= object.y + itemIndex * object.elementHeight - object.elementHeight and - e[4] <= object.y + itemIndex * object.elementHeight - 1 - then - objectFound = true - if not object.items[itemIndex].disabled and object.items[itemIndex].type == GUI.dropDownMenuElementTypes.default then - drawDropDownMenuElement(object, itemIndex, true) - buffer.draw() - os.sleep(0.2) - quit() - if object.items[itemIndex].onTouch then object.items[itemIndex].onTouch() end - return object.items[itemIndex].text, itemIndex - end - break - end - end - - if not objectFound then quit(); return end - end - end -end - -local function addDropDownMenuItem(object, text, disabled, shortcut, color) - local item = {} - item.type = GUI.dropDownMenuElementTypes.default - item.text = text - item.disabled = disabled - item.shortcut = shortcut - item.color = color - - table.insert(object.items, item) - return item -end - -local function addDropDownMenuSeparator(object) - local item = {type = GUI.dropDownMenuElementTypes.separator} - table.insert(object.items, item) - return item -end - -function GUI.dropDownMenu(x, y, width, elementHeight, backgroundColor, textColor, backgroundPressedColor, textPressedColor, disabledColor, separatorColor, transparency, items) - local object = GUI.object(x, y, width, 1) - object.colors = { - default = { - background = backgroundColor, - text = textColor - }, - pressed = { - background = backgroundPressedColor, - text = textPressedColor - }, - disabled = { - text = disabledColor - }, - separator = separatorColor, - transparency = transparency - } - object.sidesOffset = 2 - object.elementHeight = elementHeight - object.addSeparator = addDropDownMenuSeparator - object.addItem = addDropDownMenuItem - object.items = {} - if items then - for i = 1, #items do - object:addItem(items[i]) - end - end - object.drawShadow = true - object.draw = drawDropDownMenu - object.show = showDropDownMenu - return object -end - ------------------------------------------ Context Menu ----------------------------------------- - -local function showContextMenu(object) - -- Расчет ширины окна меню - local longestItem, longestShortcut = 0, 0 - for itemIndex = 1, #object.items do - if object.items[itemIndex].type == GUI.dropDownMenuElementTypes.default then - longestItem = math.max(longestItem, unicode.len(object.items[itemIndex].text)) - if object.items[itemIndex].shortcut then longestShortcut = math.max(longestShortcut, unicode.len(object.items[itemIndex].shortcut)) end - end - end - object.width = object.sidesOffset + longestItem + (longestShortcut > 0 and 3 + longestShortcut or 0) + object.sidesOffset - object.height = #object.items * object.elementHeight - - -- А это чтоб за края экрана не лезло - if object.y + object.height >= buffer.height then object.y = buffer.height - object.height end - if object.x + object.width + 1 >= buffer.width then object.x = buffer.width - object.width - 1 end - - return object:reimplementedShow() -end - -function GUI.contextMenu(x, y, ...) - local argumentItems = {...} - local object = GUI.dropDownMenu(x, y, 1, 1, GUI.colors.contextMenu.default.background, GUI.colors.contextMenu.default.text, GUI.colors.contextMenu.pressed.background, GUI.colors.contextMenu.pressed.text, GUI.colors.contextMenu.disabled.text, GUI.colors.contextMenu.separator, GUI.colors.contextMenu.transparency.background) - - -- Заполняем менюшку парашей - for itemIndex = 1, #argumentItems do - if argumentItems[itemIndex] == "-" then - object:addSeparator() - else - object:addItem(argumentItems[itemIndex][1], argumentItems[itemIndex][2], argumentItems[itemIndex][3], argumentItems[itemIndex][4]) - end - end - - object.reimplementedShow = object.show - object.show = showContextMenu - object.selectedElement = nil - - return object -end - ----------------------------------------- Menu ----------------------------------------- local function menuDraw(menu) @@ -953,256 +894,6 @@ function GUI.error(...) mainContainer:startEventHandling() end ------------------------------------------ Text Box object ----------------------------------------- - -local function drawTextBox(object) - if object.colors.background then buffer.square(object.x, object.y, object.width, object.height, object.colors.background, object.colors.text, " ", object.colors.transparency) end - local xPos, yPos = GUI.getAlignmentCoordinates(object, {width = 1, height = object.height - object.offset.vertical * 2}) - local lineLimit = object.width - object.offset.horizontal * 2 - for line = object.currentLine, object.currentLine + object.height - 1 do - if object.lines[line] then - local lineType, text, textColor = type(object.lines[line]) - if lineType == "table" then - text, textColor = string.limit(object.lines[line].text, lineLimit), object.lines[line].color - elseif lineType == "string" then - text, textColor = string.limit(object.lines[line], lineLimit), object.colors.text - else - error("Unknown TextBox line type: " .. tostring(lineType)) - end - - xPos = GUI.getAlignmentCoordinates( - { - x = object.x + object.offset.horizontal, - y = object.y + object.offset.vertical, - width = object.width - object.offset.horizontal * 2, - height = object.height - object.offset.vertical * 2, - alignment = object.alignment - }, - {width = unicode.len(text), height = object.height} - ) - buffer.text(xPos, yPos, textColor, text) - yPos = yPos + 1 - else - break - end - end - - return object -end - -local function scrollDownTextBox(object, count) - count = count or 1 - local maxCountAvailableToScroll = #object.lines - object.height - object.currentLine + 1 - count = math.min(count, maxCountAvailableToScroll) - if #object.lines >= object.height and object.currentLine < #object.lines - count then - object.currentLine = object.currentLine + count - end - return object -end - -local function scrollUpTextBox(object, count) - count = count or 1 - if object.currentLine > count and object.currentLine >= 1 then object.currentLine = object.currentLine - count end - return object -end - -local function scrollToStartTextBox(object) - object.currentLine = 1 - return object -end - -local function scrollToEndTextBox(object) - object.currentLine = #lines - return object -end - -local function textBoxScrollEventHandler(mainContainer, object, eventData) - if eventData[1] == "scroll" then - if eventData[5] == 1 then - object:scrollUp() - mainContainer:draw() - buffer.draw() - else - object:scrollDown() - mainContainer:draw() - buffer.draw() - end - end -end - -function GUI.textBox(x, y, width, height, backgroundColor, textColor, lines, currentLine, horizontalOffset, verticalOffset) - local object = GUI.object(x, y, width, height) - - object.eventHandler = textBoxScrollEventHandler - object.colors = { text = textColor, background = backgroundColor } - object.setAlignment = GUI.setAlignment - object:setAlignment(GUI.alignment.horizontal.left, GUI.alignment.vertical.top) - object.lines = lines - object.currentLine = currentLine or 1 - object.draw = drawTextBox - object.scrollUp = scrollUpTextBox - object.scrollDown = scrollDownTextBox - object.scrollToStart = scrollToStartTextBox - object.scrollToEnd = scrollToEndTextBox - object.offset = {horizontal = horizontalOffset or 0, vertical = verticalOffset or 0} - - return object -end - ------------------------------------------ Horizontal Slider Object ----------------------------------------- - -local function drawHorizontalSlider(object) - -- На всякий случай делаем значение не меньше минимального и не больше максимального - object.value = math.min(math.max(object.value, object.minimumValue), object.maximumValue) - - if object.showMaximumAndMinimumValues then - local stringMaximumValue, stringMinimumValue = tostring(object.roundValues and math.floor(object.maximumValue) or math.roundToDecimalPlaces(object.maximumValue, 2)), tostring(object.roundValues and math.floor(object.minimumValue) or math.roundToDecimalPlaces(object.minimumValue, 2)) - buffer.text(object.x - unicode.len(stringMinimumValue) - 1, object.y, object.colors.value, stringMinimumValue) - buffer.text(object.x + object.width + 1, object.y, object.colors.value, stringMaximumValue) - end - - if object.currentValuePrefix or object.currentValuePostfix then - local stringCurrentValue = (object.currentValuePrefix or "") .. (object.roundValues and math.floor(object.value) or math.roundToDecimalPlaces(object.value, 2)) .. (object.currentValuePostfix or "") - buffer.text(math.floor(object.x + object.width / 2 - unicode.len(stringCurrentValue) / 2), object.y + 1, object.colors.value, stringCurrentValue) - end - - local activeWidth = math.floor(object.width - ((object.maximumValue - object.value) * object.width / (object.maximumValue - object.minimumValue))) - buffer.text(object.x, object.y, object.colors.passive, string.rep("━", object.width)) - buffer.text(object.x, object.y, object.colors.active, string.rep("━", activeWidth)) - buffer.text(object.x + activeWidth - 1, object.y, object.colors.pipe, "⬤") - - return object -end - -local function sliderEventHandler(mainContainer, object, eventData) - if eventData[1] == "touch" or eventData[1] == "drag" then - local clickPosition = eventData[3] - object.x + 1 - object.value = object.minimumValue + (clickPosition * (object.maximumValue - object.minimumValue) / object.width) - mainContainer:draw() - buffer.draw() - callMethod(object.onValueChanged, object.value, eventData) - end -end - -function GUI.slider(x, y, width, activeColor, passiveColor, pipeColor, valueColor, minimumValue, maximumValue, value, showMaximumAndMinimumValues, currentValuePrefix, currentValuePostfix) - local object = GUI.object(x, y, width, 1) - - object.eventHandler = sliderEventHandler - object.colors = {active = activeColor, passive = passiveColor, pipe = pipeColor, value = valueColor} - object.draw = drawHorizontalSlider - object.minimumValue = minimumValue - object.maximumValue = maximumValue - object.value = value - object.showMaximumAndMinimumValues = showMaximumAndMinimumValues - object.currentValuePrefix = currentValuePrefix - object.currentValuePostfix = currentValuePostfix - object.roundValues = false - - return object -end - ------------------------------------------ Switch object ----------------------------------------- - -local function switchDraw(switch) - local pipePosition, backgroundColor - if switch.state then - pipePosition, backgroundColor = switch.x + switch.width - 2, switch.colors.active - else - pipePosition, backgroundColor = switch.x, switch.colors.passive - end - - buffer.text(switch.x - 1, switch.y, backgroundColor, "⠰") - buffer.square(switch.x, switch.y, switch.width, 1, backgroundColor, 0x000000, " ") - buffer.text(switch.x + switch.width, switch.y, backgroundColor, "⠆") - - - buffer.text(pipePosition - 1, switch.y, switch.colors.pipe, "⠰") - buffer.square(pipePosition, switch.y, 2, 1, switch.colors.pipe, 0x000000, " ") - buffer.text(pipePosition + 2, switch.y, switch.colors.pipe, "⠆") - - return switch -end - -local function switchEventHandler(mainContainer, object, eventData) - if eventData[1] == "touch" then - object.state = not object.state - mainContainer:draw() - buffer.draw() - callMethod(object.onStateChanged, object.state, eventData) - end -end - -function GUI.switch(x, y, width, activeColor, passiveColor, pipeColor, state) - local switch = GUI.object(x, y, width, 1) - - switch.eventHandler = switchEventHandler - switch.colors = {active = activeColor, passive = passiveColor, pipe = pipeColor, value = valueColor} - switch.draw = switchDraw - switch.state = state or false - - return switch -end - ------------------------------------------ Combo Box Object ----------------------------------------- - -local function drawComboBox(object) - buffer.square(object.x, object.y, object.width, object.height, object.colors.default.background) - local x, y, limit, arrowSize = object.x + 1, math.floor(object.y + object.height / 2), object.width - 5, object.height - buffer.text(x, y, object.colors.default.text, string.limit(object.items[object.selectedItem].text, limit, "right")) - GUI.button(object.x + object.width - arrowSize * 2 + 1, object.y, arrowSize * 2 - 1, arrowSize, object.colors.arrow.background, object.colors.arrow.text, 0x0, 0x0, object.state and "▲" or "▼"):draw() -end - -local function selectComboBoxItem(object) - object.state = true - object:draw() - - local dropDownMenu = GUI.dropDownMenu(object.x, object.y + object.height, object.width, object.height, object.colors.default.background, object.colors.default.text, object.colors.pressed.background, object.colors.pressed.text, GUI.colors.contextMenu.disabled.text, GUI.colors.contextMenu.separator, GUI.colors.contextMenu.transparency.background, object.items) - dropDownMenu.items = object.items - dropDownMenu.sidesOffset = 1 - local _, itemIndex = dropDownMenu:show() - - object.selectedItem = itemIndex or object.selectedItem - object.state = false - object:draw() - buffer.draw() -end - -local function comboBoxEventHandler(mainContainer, object, eventData) - if eventData[1] == "touch" then - object:selectItem() - callMethod(object.onItemSelected, object.items[object.selectedItem], eventData) - end -end - -function GUI.comboBox(x, y, width, elementHeight, backgroundColor, textColor, arrowBackgroundColor, arrowTextColor) - local object = GUI.object(x, y, width, elementHeight) - - object.eventHandler = comboBoxEventHandler - object.colors = { - default = { - background = backgroundColor, - text = textColor - }, - pressed = { - background = GUI.colors.contextMenu.pressed.background, - text = GUI.colors.contextMenu.pressed.text - }, - arrow = { - background = arrowBackgroundColor, - text = arrowTextColor - } - } - object.items = {} - object.selectedItem = 1 - object.addItem = addDropDownMenuItem - object.addSeparator = addDropDownMenuSeparator - object.draw = drawComboBox - object.selectItem = selectComboBoxItem - object.state = false - - return object -end - ----------------------------------------- Scrollbar object ----------------------------------------- local function scrollBarDraw(scrollBar) @@ -2109,18 +1800,20 @@ local function layoutCalculate(layout) end for i = 1, #layout.children do - layout.children[i].layoutGridPosition = layout.children[i].layoutGridPosition or {column = 1, row = 1} + if not layout.children[i].hidden then + layout.children[i].layoutGridPosition = layout.children[i].layoutGridPosition or {column = 1, row = 1} - if layout.children[i].layoutGridPosition.row >= 1 and layout.children[i].layoutGridPosition.row <= #layout.grid.rowSizes and layout.children[i].layoutGridPosition.column >= 1 and layout.children[i].layoutGridPosition.column <= #layout.grid.columnSizes then - if layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].direction == GUI.directions.horizontal then - layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth + layout.children[i].width + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing - layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight = math.max(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight, layout.children[i].height) + if layout.children[i].layoutGridPosition.row >= 1 and layout.children[i].layoutGridPosition.row <= #layout.grid.rowSizes and layout.children[i].layoutGridPosition.column >= 1 and layout.children[i].layoutGridPosition.column <= #layout.grid.columnSizes then + if layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].direction == GUI.directions.horizontal then + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth + layout.children[i].width + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight = math.max(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight, layout.children[i].height) + else + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth = math.max(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth, layout.children[i].width) + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight + layout.children[i].height + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing + end else - layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth = math.max(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth, layout.children[i].width) - layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight + layout.children[i].height + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing + error("Layout child with index " .. i .. " has been assigned to cell (" .. layout.children[i].layoutGridPosition.column .. "x" .. layout.children[i].layoutGridPosition.row .. ") out of layout grid range") end - else - error("Layout child with index " .. i .. " has been assigned to cell (" .. layout.children[i].layoutGridPosition.column .. "x" .. layout.children[i].layoutGridPosition.row .. ") out of layout grid range") end end @@ -2156,16 +1849,18 @@ local function layoutCalculate(layout) end for i = 1, #layout.children do - layout.children[i].layoutGridPosition = layout.children[i].layoutGridPosition or {column = 1, row = 1} - - if layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].direction == GUI.directions.horizontal then - layout.children[i].localPosition.x = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x) - layout.children[i].localPosition.y = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight / 2 - layout.children[i].height / 2) - layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x + layout.children[i].width + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing - else - layout.children[i].localPosition.x = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth / 2 - layout.children[i].width / 2) - layout.children[i].localPosition.y = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y) - layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y + layout.children[i].height + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing + if not layout.children[i].hidden then + layout.children[i].layoutGridPosition = layout.children[i].layoutGridPosition or {column = 1, row = 1} + + if layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].direction == GUI.directions.horizontal then + layout.children[i].localPosition.x = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x) + layout.children[i].localPosition.y = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalHeight / 2 - layout.children[i].height / 2) + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x + layout.children[i].width + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing + else + layout.children[i].localPosition.x = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].x + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].totalWidth / 2 - layout.children[i].width / 2) + layout.children[i].localPosition.y = math.floor(layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y) + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y = layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].y + layout.children[i].height + layout.grid[layout.children[i].layoutGridPosition.row][layout.children[i].layoutGridPosition.column].spacing + end end end end @@ -2357,6 +2052,30 @@ local function layoutDraw(layout) end end +local function layoutFitToChildrenSize(layout, column, row) + layout.width, layout.height = 0, 0 + + for i = 1, #layout.children do + if not layout.children[i].hidden then + if layout.grid[row][column].direction == GUI.directions.horizontal then + layout.width = layout.width + layout.children[i].width + layout.grid[row][column].spacing + layout.height = math.max(layout.height, layout.children[i].height) + else + layout.width = math.max(layout.width, layout.children[i].width) + layout.height = layout.height + layout.children[i].height + layout.grid[row][column].spacing + end + end + end + + if layout.grid[row][column].direction == GUI.directions.horizontal then + layout.width = layout.width - layout.grid[row][column].spacing + else + layout.height = layout.height - layout.grid[row][column].spacing + end + + return layout +end + function GUI.layout(x, y, width, height, columnCount, rowCount) local layout = GUI.container(x, y, width, height) @@ -2374,6 +2093,7 @@ function GUI.layout(x, y, width, height, columnCount, rowCount) layout.setCellSpacing = layoutSetCellSpacing layout.setCellAlignment = layoutSetCellAlignment layout.setCellMargin = layoutSetCellMargin + layout.fitToChildrenSize = layoutFitToChildrenSize layout.draw = layoutDraw @@ -2382,40 +2102,685 @@ function GUI.layout(x, y, width, height, columnCount, rowCount) return layout end +----------------------------------------- Dropdown Menu ----------------------------------------- + +local function dropDownMenuItemDraw(item) + local yText = item.y + math.floor(item.height / 2) + + if item.type == GUI.dropDownMenuElementTypes.default then + local textColor = item.color or item.parent.parent.colors.default.text + + if item.pressed then + textColor = item.parent.parent.colors.pressed.text + buffer.square(item.x, item.y, item.width, item.height, item.parent.parent.colors.pressed.background, textColor, " ") + elseif item.disabled then + textColor = item.parent.parent.colors.disabled.text + end + + buffer.text(item.x + 1, yText, textColor, item.text) + if item.shortcut then + buffer.text(item.x + item.width - unicode.len(item.shortcut) - 1, yText, textColor, item.shortcut) + end + else + buffer.text(item.x, yText, item.parent.parent.colors.separator, string.rep("─", item.width)) + end + + return item +end + +local function dropDownMenuItemEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + if object.type == GUI.dropDownMenuElementTypes.default then + object.pressed = true + mainContainer:draw() + buffer.draw() + + if object.subMenu then + object.subMenu.y = object.parent.y + object.localPosition.y - 1 + object.subMenu.x = object.parent.x + object.parent.width + if buffer.width - object.parent.x - object.parent.width + 1 < object.subMenu.width then + object.subMenu.x = object.parent.x - object.subMenu.width + end + + object.subMenu:show() + else + os.sleep(0.2) + end + + object.pressed = false + mainContainer:draw() + buffer.draw() + mainContainer.selectedItem = object:indexOf() + + callMethod(object.onTouch) + end + + mainContainer:stopEventHandling() + end +end + +local function dropDownMenuCalculateSizes(menu) + local totalHeight = 0 + for i = 1, #menu.itemsContainer.children do + totalHeight = totalHeight + (menu.itemsContainer.children[i].type == GUI.dropDownMenuElementTypes.separator and 1 or menu.itemHeight) + menu.itemsContainer.children[i].width = menu.width + end + menu.height = math.min(totalHeight, menu.maximumHeight) + menu.itemsContainer.width, menu.itemsContainer.height = menu.width, menu.height + + menu.nextButton.localPosition.y = menu.height + menu.prevButton.width, menu.nextButton.width = menu.width, menu.width + menu.prevButton.hidden = menu.itemsContainer.children[1].localPosition.y >= 1 + menu.nextButton.hidden = menu.itemsContainer.children[#menu.itemsContainer.children].localPosition.y + menu.itemsContainer.children[#menu.itemsContainer.children].height - 1 <= menu.height +end + +local function dropDownMenuAddItem(menu, text, disabled, shortcut, color) + local item = menu.itemsContainer:addChild(GUI.object(1, #menu.itemsContainer.children == 0 and 1 or menu.itemsContainer.children[#menu.itemsContainer.children].localPosition.y + menu.itemsContainer.children[#menu.itemsContainer.children].height, menu.width, menu.itemHeight)) + + item.type = GUI.dropDownMenuElementTypes.default + item.text = text + item.disabled = disabled + item.shortcut = shortcut + item.color = color + item.draw = dropDownMenuItemDraw + item.eventHandler = dropDownMenuItemEventHandler + + dropDownMenuCalculateSizes(menu) + + return item +end + +local function dropDownMenuAddSeparator(menu) + local item = dropDownMenuAddItem(menu) + item.type = GUI.dropDownMenuElementTypes.separator + item.height = 1 + + return item +end + +local function dropDownMenuScrollDown(menu) + if menu.itemsContainer.children[1].localPosition.y < 1 then + for i = 1, #menu.itemsContainer.children do + menu.itemsContainer.children[i].localPosition.y = menu.itemsContainer.children[i].localPosition.y + 1 + end + end + menu:draw() + buffer.draw() +end + +local function dropDownMenuScrollUp(menu) + if menu.itemsContainer.children[#menu.itemsContainer.children].localPosition.y + menu.itemsContainer.children[#menu.itemsContainer.children].height - 1 > menu.height then + for i = 1, #menu.itemsContainer.children do + menu.itemsContainer.children[i].localPosition.y = menu.itemsContainer.children[i].localPosition.y - 1 + end + end + menu:draw() + buffer.draw() +end + +local function dropDownMenuEventHandler(mainContainer, object, eventData) + if eventData[1] == "scroll" then + if eventData[5] == 1 then + dropDownMenuScrollDown(object) + else + dropDownMenuScrollUp(object) + end + end +end + +local function dropDownMenuDraw(menu) + dropDownMenuCalculateSizes(menu) + + if menu.oldPixels then + buffer.paste(menu.x, menu.y, menu.oldPixels) + else + menu.oldPixels = buffer.copy(menu.x, menu.y, menu.width + 1, menu.height + 1) + end + + buffer.square(menu.x, menu.y, menu.width, menu.height, menu.colors.default.background, menu.colors.default.text, " ", menu.colors.transparency.background) + GUI.drawContainerContent(menu) + GUI.windowShadow(menu.x, menu.y, menu.width, menu.height, menu.colors.transparency.shadow, true) + + return menu +end + +local function dropDownMenuShow(menu) + local mainContainer = GUI.fullScreenContainer() + mainContainer:addChild(GUI.object(1, 1, mainContainer.width, mainContainer.height)).eventHandler = function(mainContainer, object, eventData) + if eventData[1] == "touch" then + mainContainer:stopEventHandling() + end + end + mainContainer:addChild(menu) + + menu:draw() + buffer.draw() + mainContainer:startEventHandling() + + buffer.paste(menu.x, menu.y, menu.oldPixels) + buffer.draw() + if mainContainer.selectedItem then + return menu.itemsContainer.children[mainContainer.selectedItem].text, mainContainer.selectedItem + end +end + +function GUI.dropDownMenu(x, y, width, maximumHeight, itemHeight, backgroundColor, textColor, backgroundPressedColor, textPressedColor, disabledColor, separatorColor, backgroundTransparency, shadowTransparency) + local menu = GUI.container(x, y, width, 1) + + menu.colors = { + default = { + background = backgroundColor, + text = textColor + }, + pressed = { + background = backgroundPressedColor, + text = textPressedColor + }, + disabled = { + text = disabledColor + }, + separator = separatorColor, + transparency = { + background = backgroundTransparency, + shadow = shadowTransparency + } + } + + menu.itemsContainer = menu:addChild(GUI.container(1, 1, menu.width, menu.height)) + menu.prevButton = menu:addChild(GUI.button(1, 1, menu.width, 1, backgroundColor, textColor, backgroundPressedColor, textPressedColor, "▲")) + menu.nextButton = menu:addChild(GUI.button(1, 1, menu.width, 1, backgroundColor, textColor, backgroundPressedColor, textPressedColor, "▼")) + menu.prevButton.colors.default.transparency, menu.nextButton.colors.default.transparency = backgroundTransparency, backgroundTransparency + menu.prevButton.onTouch = function() + dropDownMenuScrollDown(menu) + end + menu.nextButton.onTouch = function() + dropDownMenuScrollUp(menu) + end + + menu.itemHeight = itemHeight + menu.addSeparator = dropDownMenuAddSeparator + menu.addItem = dropDownMenuAddItem + menu.draw = dropDownMenuDraw + menu.show = dropDownMenuShow + menu.maximumHeight = maximumHeight + menu.eventHandler = dropDownMenuEventHandler + + return menu +end + +----------------------------------------- Context Menu ----------------------------------------- + +local function contextMenuCalculate(menu) + local widestItem, widestShortcut = 0, 0 + for i = 1, #menu.itemsContainer.children do + if menu.itemsContainer.children[i].type == GUI.dropDownMenuElementTypes.default then + widestItem = math.max(widestItem, unicode.len(menu.itemsContainer.children[i].text)) + if menu.itemsContainer.children[i].shortcut then + widestShortcut = math.max(widestShortcut, unicode.len(menu.itemsContainer.children[i].shortcut)) + end + end + end + menu.width = 2 + widestItem + (widestShortcut > 0 and 3 + widestShortcut or 0) +end + +local function contextMenuShow(menu) + contextMenuCalculate(menu) + if menu.y + menu.height >= buffer.height then menu.y = buffer.height - menu.height end + if menu.x + menu.width + 1 >= buffer.width then menu.x = buffer.width - menu.width - 1 end + + return dropDownMenuShow(menu) +end + +local function contextMenuAddItem(menu, ...) + contextMenuCalculate(menu) + return dropDownMenuAddItem(menu, ...) +end + +local function contextMenuAddSeparator(menu, ...) + contextMenuCalculate(menu) + return dropDownMenuAddSeparator(menu, ...) +end + +local function contextMenuAddSubMenu(menu, text) + local item = menu:addItem(text, false, "►") + item.subMenu = GUI.contextMenu(1, 1) + item.subMenu.colors = menu.colors + + return item.subMenu +end + +function GUI.contextMenu(x, y, backgroundColor, textColor, backgroundPressedColor, textPressedColor, disabledColor, separatorColor, backgroundTransparency, shadowTransparency) + local menu = GUI.dropDownMenu(x, y, 1, math.ceil(buffer.height * 0.5), 1, + backgroundColor or GUI.colors.contextMenu.default.background, + textColor or GUI.colors.contextMenu.default.text, + backgroundPressedColor or GUI.colors.contextMenu.pressed.background, + textPressedColor or GUI.colors.contextMenu.pressed.text, + disabledColor or GUI.colors.contextMenu.disabled, + separatorColor or GUI.colors.contextMenu.separator, + backgroundTransparency or GUI.colors.contextMenu.transparency.background, + shadowTransparency or GUI.colors.contextMenu.transparency.shadow + ) + + menu.colors.transparency.background = menu.colors.transparency.background or GUI.colors.contextMenu.transparency.background + menu.colors.transparency.shadow = menu.colors.transparency.shadow or GUI.colors.contextMenu.transparency.shadow + + menu.show = contextMenuShow + menu.addSubMenu = contextMenuAddSubMenu + menu.addItem = contextMenuAddItem + menu.addSeparator = contextMenuAddSeparator + + return menu +end + +----------------------------------------- Combo Box Object ----------------------------------------- + +local function drawComboBox(object) + buffer.square(object.x, object.y, object.width, object.height, object.colors.default.background) + local x, y, limit, arrowSize = object.x + 1, math.floor(object.y + object.height / 2), object.width - 5, object.height + buffer.text(x, y, object.colors.default.text, string.limit(object.dropDownMenu.itemsContainer.children[object.selectedItem].text, limit, "right")) + GUI.button(object.x + object.width - arrowSize * 2 + 1, object.y, arrowSize * 2 - 1, arrowSize, object.colors.arrow.background, object.colors.arrow.text, 0x0, 0x0, object.pressed and "▲" or "▼"):draw() + + return object +end + +local function selectComboBoxItem(object) + object.pressed = true + object:draw() + + object.dropDownMenu.x, object.dropDownMenu.y = object.x, object.y + object.height + object.dropDownMenu.width = object.width + local _, selectedItem = object.dropDownMenu:show() + + object.selectedItem = selectedItem or object.selectedItem + object.pressed = false + object:draw() + buffer.draw() + + return object +end + +local function comboBoxEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + object:selectItem() + callMethod(object.onItemSelected, object.dropDownMenu.itemsContainer.children[object.selectedItem], eventData) + end +end + +local function comboBoxAddItem(object, ...) + return object.dropDownMenu:addItem(...) +end + +local function comboBoxAddSeparator(object, ...) + return object.dropDownMenu:addItem(...) +end + +function GUI.comboBox(x, y, width, elementHeight, backgroundColor, textColor, arrowBackgroundColor, arrowTextColor) + local object = GUI.object(x, y, width, elementHeight) + + object.eventHandler = comboBoxEventHandler + object.colors = { + default = { + background = backgroundColor, + text = textColor + }, + pressed = { + background = GUI.colors.contextMenu.pressed.background, + text = GUI.colors.contextMenu.pressed.text + }, + arrow = { + background = arrowBackgroundColor, + text = arrowTextColor + } + } + + object.dropDownMenu = GUI.dropDownMenu(1, 1, 1, math.ceil(buffer.height * 0.5), elementHeight, object.colors.default.background, object.colors.default.text, object.colors.pressed.background, object.colors.pressed.text, GUI.colors.contextMenu.disabled, GUI.colors.contextMenu.separator, GUI.colors.contextMenu.transparency.background, GUI.colors.contextMenu.transparency.shadow) + object.selectedItem = 1 + object.addItem = comboBoxAddItem + object.addSeparator = comboBoxAddSeparator + object.draw = drawComboBox + object.selectItem = selectComboBoxItem + + return object +end + +----------------------------------------- Switch and label object ----------------------------------------- + +local function switchAndLabelDraw(switchAndLabel) + switchAndLabel.label.width = switchAndLabel.width + switchAndLabel.switch.localPosition.x = switchAndLabel.width - switchAndLabel.switch.width + GUI.calculateChildAbsolutePosition(switchAndLabel.label) + GUI.calculateChildAbsolutePosition(switchAndLabel.switch) + switchAndLabel.label:draw() + switchAndLabel.switch:draw() + + return switchAndLabel +end + +function GUI.switchAndLabel(x, y, width, switchWidth, activeColor, passiveColor, pipeColor, textColor, text, switchState) + local switchAndLabel = GUI.container(x, y, width, 1) + + switchAndLabel.label = switchAndLabel:addChild(GUI.label(1, 1, width, 1, textColor, text)) + switchAndLabel.switch = switchAndLabel:addChild(GUI.switch(1, 1, switchWidth, activeColor, passiveColor, pipeColor, switchState)) + switchAndLabel.draw = switchAndLabelDraw + + return switchAndLabel +end + +----------------------------------------- Text Box object ----------------------------------------- + +local function textBoxCalculate(object) + object.textWidth = object.width - object.offset.horizontal * 2 + + object.linesCopy = {} + for i = 1, #object.lines do + table.insert(object.linesCopy, object.lines[i]) + end + + if object.autoWrap then + object.linesCopy = string.wrap(object.linesCopy, object.textWidth) + end + + if object.autoHeight then + object.height = #object.linesCopy + end + + object.textHeight = object.height - object.offset.vertical * 2 +end + +local function textBoxDraw(object) + textBoxCalculate(object) + + if object.colors.background then + buffer.square(object.x, object.y, object.width, object.height, object.colors.background, object.colors.text, " ", object.colors.transparency) + end + + local x, y = nil, object.y + object.offset.vertical + local lineType, text, textColor + for i = object.currentLine, object.currentLine + object.textHeight - 1 do + if object.linesCopy[i] then + lineType = type(object.linesCopy[i]) + if lineType == "string" then + text, textColor = string.limit(object.linesCopy[i], object.textWidth), object.colors.text + elseif lineType == "table" then + text, textColor = string.limit(object.linesCopy[i].text, object.textWidth), object.linesCopy[i].color + else + error("Unknown TextBox line type: " .. tostring(lineType)) + end + + x = GUI.getAlignmentCoordinates( + { + x = object.x + object.offset.horizontal, + y = 1, + width = object.textWidth, + height = 1, + alignment = object.alignment + }, + { + width = unicode.len(text), + height = 1 + } + ) + buffer.text(x, y, textColor, text) + y = y + 1 + else + break + end + end + + return object +end + +local function scrollDownTextBox(object, count) + count = count or 1 + local maxCountAvailableToScroll = #object.lines - object.height - object.currentLine + 1 + count = math.min(count, maxCountAvailableToScroll) + if #object.lines >= object.height and object.currentLine < #object.lines - count then + object.currentLine = object.currentLine + count + end + + return object +end + +local function scrollUpTextBox(object, count) + count = count or 1 + if object.currentLine > count and object.currentLine >= 1 then object.currentLine = object.currentLine - count end + return object +end + +local function scrollToStartTextBox(object) + object.currentLine = 1 + return object +end + +local function scrollToEndTextBox(object) + object.currentLine = #lines + return object +end + +local function textBoxScrollEventHandler(mainContainer, object, eventData) + if eventData[1] == "scroll" then + if eventData[5] == 1 then + object:scrollUp() + mainContainer:draw() + buffer.draw() + else + object:scrollDown() + mainContainer:draw() + buffer.draw() + end + end +end + +function GUI.textBox(x, y, width, height, backgroundColor, textColor, lines, currentLine, horizontalOffset, verticalOffset, autoWrap, autoHeight) + local object = GUI.object(x, y, width, height) + + object.eventHandler = textBoxScrollEventHandler + object.colors = { + text = textColor, + background = backgroundColor + } + object.setAlignment = GUI.setAlignment + object:setAlignment(GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + object.lines = lines + object.currentLine = currentLine or 1 + object.draw = textBoxDraw + object.scrollUp = scrollUpTextBox + object.scrollDown = scrollDownTextBox + object.scrollToStart = scrollToStartTextBox + object.scrollToEnd = scrollToEndTextBox + object.offset = {horizontal = horizontalOffset or 0, vertical = verticalOffset or 0} + object.autoWrap = autoWrap + object.autoHeight = autoHeight + + textBoxCalculate(object) + + return object +end + +----------------------------------------- Horizontal Slider Object ----------------------------------------- + +local function sliderDraw(object) + -- На всякий случай делаем значение не меньше минимального и не больше максимального + object.value = math.min(math.max(object.value, object.minimumValue), object.maximumValue) + + if object.showMaximumAndMinimumValues then + local stringMaximumValue, stringMinimumValue = tostring(object.roundValues and math.floor(object.maximumValue) or math.roundToDecimalPlaces(object.maximumValue, 2)), tostring(object.roundValues and math.floor(object.minimumValue) or math.roundToDecimalPlaces(object.minimumValue, 2)) + buffer.text(object.x - unicode.len(stringMinimumValue) - 1, object.y, object.colors.value, stringMinimumValue) + buffer.text(object.x + object.width + 1, object.y, object.colors.value, stringMaximumValue) + end + + if object.currentValuePrefix or object.currentValuePostfix then + local stringCurrentValue = (object.currentValuePrefix or "") .. (object.roundValues and math.floor(object.value) or math.roundToDecimalPlaces(object.value, 2)) .. (object.currentValuePostfix or "") + buffer.text(math.floor(object.x + object.width / 2 - unicode.len(stringCurrentValue) / 2), object.y + 1, object.colors.value, stringCurrentValue) + end + + local activeWidth = math.floor(object.width - ((object.maximumValue - object.value) * object.width / (object.maximumValue - object.minimumValue))) + buffer.text(object.x, object.y, object.colors.passive, string.rep("━", object.width)) + buffer.text(object.x, object.y, object.colors.active, string.rep("━", activeWidth)) + buffer.text(object.x + activeWidth - 1, object.y, object.colors.pipe, "⬤") + + return object +end + +local function sliderEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + local clickPosition = eventData[3] - object.x + 1 + object.value = object.minimumValue + (clickPosition * (object.maximumValue - object.minimumValue) / object.width) + mainContainer:draw() + buffer.draw() + callMethod(object.onValueChanged, object.value, eventData) + end +end + +function GUI.slider(x, y, width, activeColor, passiveColor, pipeColor, valueColor, minimumValue, maximumValue, value, showMaximumAndMinimumValues, currentValuePrefix, currentValuePostfix) + local object = GUI.object(x, y, width, 1) + + object.eventHandler = sliderEventHandler + object.colors = {active = activeColor, passive = passiveColor, pipe = pipeColor, value = valueColor} + object.draw = sliderDraw + object.minimumValue = minimumValue + object.maximumValue = maximumValue + object.value = value + object.showMaximumAndMinimumValues = showMaximumAndMinimumValues + object.currentValuePrefix = currentValuePrefix + object.currentValuePostfix = currentValuePostfix + object.roundValues = false + + return object +end + +----------------------------------------- Switch object ----------------------------------------- + +local function switchDraw(switch) + buffer.text(switch.x - 1, switch.y, switch.colors.passive, "⠰") + buffer.square(switch.x, switch.y, switch.width, 1, switch.colors.passive, 0x000000, " ") + buffer.text(switch.x + switch.width, switch.y, switch.colors.passive, "⠆") + + buffer.text(switch.x - 1, switch.y, switch.colors.active, "⠰") + buffer.square(switch.x, switch.y, switch.pipePosition - 1, 1, switch.colors.active, 0x000000, " ") + + buffer.text(switch.x + switch.pipePosition - 2, switch.y, switch.colors.pipe, "⠰") + buffer.square(switch.x + switch.pipePosition - 1, switch.y, 2, 1, switch.colors.pipe, 0x000000, " ") + buffer.text(switch.x + switch.pipePosition + 1, switch.y, switch.colors.pipe, "⠆") + + return switch +end + +local function switchUpdate(switch) + switch.pipePosition = switch.state and switch.width - 1 or 1 +end + +local function switchEventHandler(mainContainer, switch, eventData) + if eventData[1] == "touch" then + switch.state = not switch.state + switch:addAnimation( + function(mainContainer, switch, animation) + if switch.state then + switch.pipePosition = math.round(1 + animation.position * (switch.width - 2)) + else + switch.pipePosition = math.round(1 + (1 - animation.position) * (switch.width - 2)) + end + end, + function(mainContainer, switch, animation) + animation:delete() + callMethod(switch.onStateChanged) + end + ):start(switch.animationDuration) + end +end + +function GUI.switch(x, y, width, activeColor, passiveColor, pipeColor, state) + local switch = GUI.object(x, y, width, 1) + + switch.pipePosition = 1 + switch.eventHandler = switchEventHandler + switch.colors = { + active = activeColor, + passive = passiveColor, + pipe = pipeColor, + } + switch.draw = switchDraw + switch.state = state or false + switch.update = switchUpdate + switch.animated = true + switch.animationDuration = 0.3 + + switch:update() + + return switch +end + -------------------------------------------------------------------------------------------------------------------------------- --- buffer.setResolution(160, 50) +local function brailleCanvasDraw(brailleCanvas) + local index, background, foreground, symbol + for y = 1, brailleCanvas.height do + for x = 1, brailleCanvas.width do + index = buffer.getIndexByCoordinates(x, y) + background, foreground, symbol = buffer.rawGet(index) + buffer.rawSet(index, background, brailleCanvas.pixels[y][x][9], brailleCanvas.pixels[y][x][10]) + end + end + + return brailleCanvas +end + +local function brailleCanvasSet(brailleCanvas, x, y, state, color) + local xReal, yReal = math.ceil(x / 2), math.ceil(y / 4) + if xReal <= brailleCanvas.width and yReal <= brailleCanvas.height then + brailleCanvas.pixels[yReal][xReal][(y - (yReal - 1) * 4 - 1) * 2 + x - (xReal - 1) * 2] = state and 1 or 0 + brailleCanvas.pixels[yReal][xReal][9] = color + brailleCanvas.pixels[yReal][xReal][10] = unicode.char( + 10240 + + 128 * brailleCanvas.pixels[yReal][xReal][8] + + 64 * brailleCanvas.pixels[yReal][xReal][7] + + 32 * brailleCanvas.pixels[yReal][xReal][6] + + 16 * brailleCanvas.pixels[yReal][xReal][4] + + 8 * brailleCanvas.pixels[yReal][xReal][2] + + 4 * brailleCanvas.pixels[yReal][xReal][5] + + 2 * brailleCanvas.pixels[yReal][xReal][3] + + brailleCanvas.pixels[yReal][xReal][1] + ) + end + + return brailleCanvas +end + +function GUI.brailleCanvas(x, y, width, height) + local brailleCanvas = GUI.object(x, y, width, height) + + brailleCanvas.pixels = {} + brailleCanvas.set = brailleCanvasSet + brailleCanvas.draw = brailleCanvasDraw + + for j = 1, height * 4 do + brailleCanvas.pixels[j] = {} + for i = 1, width * 2 do + brailleCanvas.pixels[j][i] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x0, " " } + end + end + + return brailleCanvas +end + +-------------------------------------------------------------------------------------------------------------------------------- + +-- require("component").screen.setPrecise(true) +-- buffer.setResolution(80, 25) -- local mainContainer = GUI.fullScreenContainer() --- mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0xFF8888)) +-- mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, mainContainer.height, 0x262626)) - --- mainContainer:addChild(GUI.switch(2, 2, 8, 0xFFDB40, 0xBBBBBB, 0xFFFFFF, true)) --- mainContainer:addChild(GUI.slider(2, 4, 36, 0xFFDB40, 0xBBBBBB, 0xFFFFFF, 0xBBBBBB, 0, 100, 50, true, "", "%")) - --- local layout = mainContainer:addChild(GUI.layout(2, 2, 157, 48, 4, 4)) --- mainContainer:addChild(GUI.panel(layout.localPosition.x, layout.localPosition.y, layout.width, layout.height, 0xFFFFFF)):moveBackward() - --- for i = 1, 4 do --- layout:setCellPosition(2, 2, layout:addChild(GUI.button(1, 1, 30, 3, 0x0, 0xFFFFFF, 0x555555, 0x888888, "Button 1"))) +-- local brailleCanvas = mainContainer:addChild(GUI.brailleCanvas(2, 2, 30, 15)) +-- for i = 1, brailleCanvas.width do +-- brailleCanvas:set(i, i, true, 0xFFFFFF) +-- brailleCanvas:set(brailleCanvas.width - i + 1, i, true, 0xFF0000) -- end --- layout:setCellAlignment(2, 2, GUI.alignment.horizontal.right, GUI.alignment.vertical.bottom) --- layout:setCellMargin(2, 2, 2, 1) - --- layout:setCellPosition(3, 3, layout:addChild(GUI.button(1, 1, 30, 3, 0x0, 0xFFFFFF, 0x555555, 0x888888, "Button 2"))) --- layout:setColumnWidth(1, GUI.sizePolicies.absolute, 4) --- layout:setColumnWidth(2, GUI.sizePolicies.percentage, 0.5) --- layout:setColumnWidth(3, GUI.sizePolicies.percentage, 0.1) --- layout:setRowHeight(3, GUI.sizePolicies.percentage, 0.4) - --- layout.showGrid = true - --- mainContainer:draw(true) --- buffer.draw() +-- mainContainer:draw() +-- buffer.draw(true) -- mainContainer:startEventHandling() - -------------------------------------------------------------------------------------------------------------------------------- return GUI diff --git a/lib/ImageFormatModules/JPEG.lua b/lib/ImageFormatModules/JPEG.lua deleted file mode 100644 index 4fa194c4..00000000 --- a/lib/ImageFormatModules/JPEG.lua +++ /dev/null @@ -1,263 +0,0 @@ -local cmp = require("component") -local com = require("computer") -local gpu = cmp.gpu -local trm = require("term") -local shl = require("shell") -local args = shl.parse(...) - -HEX = "0123456789ABCDEF" ---[[ MARKER ]] - -function R(ind) - return STR:byte(ind) % 16 -end - -function L(ind) - return math.floor( STR:byte(ind) / 16 ) -end - -function getB(ind) local right, left = R(ind) + 1, L(ind) + 1 - return HEX:sub(left, left)..HEX:sub(right, right) -end - -function Common() - i = len -end - -function DB() local IDI, x, y = R(i) + 1, 1, 1 - i = i + 1 - while i < len do - while y > 1 and x < 8 do - masDB[IDI][y][x] = STR:byte(i) i = i + 1 - y, x = y - 1, x + 1 - end - if y <= 8 and x <= 8 then - masDB[IDI][y][x] = STR:byte(i) i = i + 1 - end - if x == 8 then y = y + 1 - else x = x + 1 end - while y < 8 and x > 1 do - masDB[IDI][y][x] = STR:byte(i) i = i + 1 - y, x = y + 1, x - 1 - end - if y <= 8 and x <= 8 then - masDB[IDI][y][x] = STR:byte(i) i = i + 1 - end - if y == 8 then x = x + 1 - else y = y + 1 end - end -end - -function DA() local YCbCr, BYTECODE, BYTEpos, comp = {}, "", 1, STR:byte(i) - local function DrawFrame(coordX, coordY) local Y, Cb_avr, Cr_avr, value - local function getTable(INDEX) local DC_ind, AC_ind, x, y, TABLE = YCbCr[INDEX][1], YCbCr[INDEX][2], 1, 1, {{}, {}, {}, {}, {}, {}, {}, {}} - local CODE - local function getKEY(ACDC_TABLE) local key = "" - while ACDC_TABLE[key] == nil do - key = key..BYTECODE:sub(BYTEpos, BYTEpos) - BYTEpos = BYTEpos + 1 - end - return ACDC_TABLE[key] - end - - local function getCOEF(VALUE) local COEF = 0 - - CODE = BYTECODE:sub(BYTEpos, BYTEpos + VALUE - 1) - BYTEpos = BYTEpos + VALUE - for j=1, #CODE do - COEF = COEF * 2 + tonumber(CODE:sub(j, j)) - end - if #CODE ~= 0 and CODE:sub(1, 1) == "0" then - COEF = COEF - 2 ^ #CODE + 1 - end - return COEF - end - - local function step(n) - TABLE[y][x] = n * masDB[QUAT[INDEX] + 1][y][x] - if (x + y) % 2 == 1 then - if y == 8 then x = x + 1 - elseif x == 1 then y = y + 1 - else x, y = x - 1, y + 1 - end - else - if x == 8 then y = y + 1 - elseif y == 1 then x = x + 1 - else x, y = x + 1, y - 1 - end - end - end - --[[ DC Coeficient ]] - value = getKEY(AC_DC[0][DC_ind]) - step(getCOEF(value) + YCbCr[INDEX][3]) - YCbCr[INDEX][3] = TABLE[1][1] / masDB[QUAT[INDEX] + 1][1][1] - --[[ AC Coeficient ]] - if AC_DC[1][AC_ind] ~= nil then - while TABLE[8][8] == nil do - value = getKEY(AC_DC[1][AC_ind]) - if value == 0 then break - end - for j=1, math.floor(value / 16) do - step(0) - end - step(getCOEF(value % 16) or 0) - end - end - while TABLE[8][8] == nil do - step(0) - end - return TABLE - end - - local function getPIXEL(l, j) - local function RGB(Yval, Cbval, Crval) - local function SSS(val) - local ost - val, ost = math.modf(val) - if ost > 0.5 then - val = val + 1 - end - return math.max(0, math.min(255, val)) - end - return SSS(Yval + 1.402 * Crval + 128) * 2 ^ 16 + SSS(Yval - 0.34414 * Cbval - 0.71414 * Crval + 128) * 2 ^ 8 + SSS(Yval + 1.772 * Cbval + 128) - end - return RGB(Y[DCT[1][1] * math.floor((l - 1) / 8) + math.ceil(j / 8)][(l - 1) % 8 + 1][(j - 1) % 8 + 1], Cb_avr[math.ceil(l / DCT[1][2])][math.ceil(j / DCT[1][1])], Cr_avr[math.ceil(l / DCT[1][2])][math.ceil(j / DCT[1][1])]) - end - - local function ODCP(arr) local arr1 = {{}, {}, {}, {}, {}, {}, {}, {}} - local function getC(var) - if var == 0 then return 1 / math.sqrt(2) end - return 1 - end - local function getSyx(x, y) local Syx = 0 - for u = 0, 7 do - local COSU = getC(u) * math.cos(((2 * x + 1) * u * math.pi) / 16) - for v = 0, 7 do - Syx = Syx + COSU * getC(v) * math.cos(((2 * y + 1) * v * math.pi) / 16) * arr[u+1][v+1] - end - end - return Syx / 4 - end - - for l=1, 8 do - for j=1, 8 do - arr1[l][j] = getSyx(l - 1, j - 1) - end - end - return arr1 - end - - Y = {} - for l=1, DCT[1][1] * DCT[1][2] do - Y[l] = ODCP(getTable(1)) - end - Cb_avr = ODCP(getTable(2)) - Cr_avr = ODCP(getTable(3)) - for l=1, 4 * DCT[1][2] do - for j=1, 8 * DCT[1][1] do - gpu.setBackground(getPIXEL(l*2-1, j)) - gpu.setForeground(getPIXEL(l*2, j)) - gpu.set(j + coordX - 1,l + coordY - 1,"▄") - end - end - end - - local function getBITCODE(value) local tmp = "" - for j=1, 8 do - tmp = tostring(value % 2)..tmp - value = math.floor(value / 2) - end - return tmp - end - - i = i + 1 - if comp ~= 3 then - print("ERROR in FF DA") os.exit() - end - YCbCr = {{L(i + 1), R(i + 1), 0}, {L(i + 3), R(i + 3), 0}, {L(i + 5), R(i + 5), 0}} - i = len - local j = i - while j < #STR - 1 do - if STR:byte(j) == 255 then BYTECODE, j = BYTECODE.."11111111", j + 1 - else BYTECODE = BYTECODE..getBITCODE(STR:byte(j)) - end - j = j + 1 - end - for I = 1, math.ceil(HEIGHT / (8 * DCT[1][2])) do - for J = 1, math.ceil(WIDTH / (8 * DCT[1][1])) do - DrawFrame((J - 1) * 8 * DCT[1][1] + 1, (I - 1) * 4 * DCT[1][2] + 1) - end - end -end - -function C0() - QUAT, i = {}, i + 1 - HEIGHT = STR:byte(i) * 256 + STR:byte(i + 1) i = i + 2 - WIDTH = STR:byte(i) * 256 + STR:byte(i + 1) i = i + 3 - -- gpu.setResolution(WIDTH, math.floor(HEIGHT / 2)) - DCT = {} - for j=1, STR:byte(i-1) do - i = i + 3 - DCT[j] = {L(i - 2), R(i - 2)} - QUAT[j] = STR:byte(i-1) - end - i = len -end - -function C4() local TREE, TREEpos, TREElevel, TREEpath, class, index, HAFF = {[0] = -1}, 0, 0, "", L(i), R(i), {} - i, AC_DC[class][index] = i + 1, {} - local function AddTree(VAL) - local function ADD(VALUE) - if TREElevel ~= VAL - 1 then - TREEpath = TREEpath..tostring(VALUE) - TREElevel = TREElevel + 1 - TREEpos = TREEpos * 2 + 1 + VALUE - TREE[TREEpos] = -1 - return AddTree(VAL) - else - TREE[TREEpos * 2 + 1 + VALUE] = 0 - AC_DC[class][index][TREEpath..tostring(VALUE)] = STR:byte(i) - i = i + 1 - end - end - if TREE[TREEpos * 2 + 1] == nil then ADD(0) - elseif TREE[TREEpos * 2 + 2] == nil then ADD(1) - else - TREElevel = TREElevel - 1 - TREEpath = TREEpath:sub(1, -2) - TREEpos = math.floor((TREEpos - 1) / 2) - return AddTree(VAL) - end - end - - for j=1, 16 do - HAFF[j], i = STR:byte(i), i + 1 - end - for j=1, 16 do - for k=1, HAFF[j] do - AddTree(j) - end - end - i = len -end - - -AC_DC = {[0] = {}, [1] = {}} -MF = {["DB"] = DB, ["C0"] = C0, ["C1"] = C0, ["C2"] = C0, ["C3"] = C0, ["C4"] = C4, ["DA"] = DA, ["FE"] = FE} -masDB = {{{}, {}, {}, {}, {}, {}, {}, {}}, {{}, {}, {}, {}, {}, {}, {}, {}}} -i = 3 - -file = io.open(args[1], "rb") -STR = file:read("*a") -file:close() -if getB(1) ~= "FF" or getB(2) ~= "D8" then - print("Error: incorrect contents of the file.") - os.exit() -end -while i < #STR - 1 do - idin = getB(i+1) - i = i + 2 - len = i + STR:byte(i) * 256 + STR:byte(i + 1) - i = i + 2 - (MF[idin] or Common)() -end \ No newline at end of file diff --git a/lib/MeowEngine/Main.lua b/lib/MeowEngine/Main.lua old mode 100644 new mode 100755 diff --git a/lib/MineOSCore.lua b/lib/MineOSCore.lua index 82d0d5cc..5dbf9826 100755 --- a/lib/MineOSCore.lua +++ b/lib/MineOSCore.lua @@ -8,7 +8,6 @@ local advancedLua = require("advancedLua") local image = require("image") local buffer = require("doubleBuffering") local GUI = require("GUI") -local ecs = require("ECSAPI") local fs = require("filesystem") local unicode = require("unicode") local keyboard = require("keyboard") @@ -18,95 +17,30 @@ local gpu = component.gpu ---------------------------------------------------------------------------------------------------------------- local MineOSCore = {} - -MineOSCore.showApplicationIcons = true MineOSCore.iconWidth = 12 MineOSCore.iconHeight = 6 +MineOSCore.selectionIconPart = 0.4 MineOSCore.iconClickDelay = 0.2 +MineOSCore.iconConfigFileName = "/.icons" MineOSCore.paths = {} MineOSCore.paths.OS = "/MineOS/" MineOSCore.paths.system = MineOSCore.paths.OS .. "System/" -MineOSCore.paths.localizationFiles = MineOSCore.paths.system .. "OS/Localization/" -MineOSCore.paths.icons = MineOSCore.paths.system .. "OS/Icons/" +MineOSCore.paths.extensionAssociations = MineOSCore.paths.system .. "Extension associations/" +MineOSCore.paths.localizationFiles = MineOSCore.paths.system .. "Localization/" +MineOSCore.paths.icons = MineOSCore.paths.system .. "Icons/" MineOSCore.paths.applications = MineOSCore.paths.OS .. "Applications/" MineOSCore.paths.pictures = MineOSCore.paths.OS .. "Pictures/" MineOSCore.paths.desktop = MineOSCore.paths.OS .. "Desktop/" -MineOSCore.paths.applicationList = MineOSCore.paths.system .. "OS/Applications.cfg" +MineOSCore.paths.applicationList = MineOSCore.paths.system .. "Applications.cfg" MineOSCore.paths.trash = MineOSCore.paths.OS .. "Trash/" -MineOSCore.paths.OSSettings = MineOSCore.paths.system .. "OS/OSSettings.cfg" +MineOSCore.paths.OSSettings = MineOSCore.paths.system .. "Settings.cfg" +MineOSCore.paths.editor = MineOSCore.paths.applications .. "/MineCode IDE.app/Main.lua" MineOSCore.localization = {} - ----------------------------------------------- Tasks ------------------------------------------------------------------------ - ---[[ -MineOSCore.tasks = {} - -function MineOSCore.showTaskManager() - MineOSCore.tasks.current = 1 - buffer.clear(0x2D2D2D) - for i = 1, #MineOSCore.tasks do - buffer.text(1, i, 0xFFFFFF, i .. ": " .. table.toString(MineOSCore.tasks[i])) - end - buffer.draw() - MineOSCore.rawPullSignal() -end - -local function replacePullSignal() - MineOSCore.rawPullSignal = computer.pullSignal - computer.pullSignal = function(timeout) - local signalData = {MineOSCore.rawPullSignal(timeout)} - - local i = 1 - while i <= #MineOSCore.tasks do - if coroutine.status(MineOSCore.tasks[i].coroutine) == "dead" then - if i > 1 then - MineOSCore.tasks.current = 1 - MineOSCore.tasks[i].coroutine = nil - table.remove(MineOSCore.tasks, i) - else - error("MineOSCore fatal error cyka bitch") - end - else - i = i + 1 - end - end - - if MineOSCore.taskManagerOpen then - MineOSCore.showTaskManager() - else - if keyboard.isKeyDown(0) and keyboard.isKeyDown(28) then - MineOSCore.taskManagerOpen = true - MineOSCore.tasks[MineOSCore.tasks.current].isPaused = true - computer.pushSignal("") - coroutine.yield() - else - return table.unpack(signalData) - end - end - end -end - -function MineOSCore.newTask(func, name) - local task = { - coroutine = coroutine.create(func), - name = name, - isPaused = false - } - table.insert(MineOSCore.tasks, task) - return task -end - -function MineOSCore.newTaskFromFile(path) - local loadSuccess, loadReason = loadfile(path) - MineOSCore.newTask(loadSuccess) -end - -]] - ---------------------------------------------------------------------------------------------------------------- + function MineOSCore.getCurrentScriptDirectory() return fs.path(getCurrentScript()) end @@ -128,41 +62,25 @@ function MineOSCore.getCurrentApplicationLocalization() return MineOSCore.getLocalization(MineOSCore.getCurrentApplicationResourcesDirectory() .. "Localization/") end ----------------------------------------------------------------------------------------------------------------- - -function MineOSCore.getMethodExecutionTime(method) - local oldOSClock = os.clock() - method() - return os.clock() - oldOSClock -end - -function MineOSCore.getAverageMethodExecutionTime(method, countOfTries) - local averageTime = 0 - for i = 1, countOfTries do - averageTime = (averageTime + MineOSCore.getMethodExecutionTime(method)) / 2 - os.sleep(0.1) - end - return averageTime -end - ----------------------------------------------------------------------------------------------------------------------------------- function MineOSCore.createShortcut(where, forWhat) fs.makeDirectory(fs.path(where)) local file = io.open(where, "w") - file:write("return \"" .. forWhat .. "\"") + file:write(forWhat) file:close() end function MineOSCore.readShortcut(path) - local success, filename = pcall(loadfile(path)) - if success then - return filename - else - error("Failed to read shortcut from path \"" .. fs.path(path) .. "\": file is corrupted") - end + local file = io.open(path, "r") + local data = file:read("*a") + file:close() + + return data end +----------------------------------------------------------------------------------------------------------------------------------- + function MineOSCore.saveOSSettings() table.toFile(MineOSCore.paths.OSSettings, MineOSCore.OSSettings, true) end @@ -171,37 +89,55 @@ function MineOSCore.loadOSSettings() MineOSCore.OSSettings = table.fromFile(MineOSCore.paths.OSSettings) end +----------------------------------------------------------------------------------------------------------------------------------- + +function MineOSCore.associateExtensionLauncher(extension, pathToLauncher) + MineOSCore.OSSettings.extensionAssociations[extension] = MineOSCore.OSSettings.extensionAssociations[extension] or {} + MineOSCore.OSSettings.extensionAssociations[extension].launcher = pathToLauncher +end + +function MineOSCore.associateExtensionIcon(extension, pathToIcon) + MineOSCore.OSSettings.extensionAssociations[extension] = MineOSCore.OSSettings.extensionAssociations[extension] or {} + MineOSCore.OSSettings.extensionAssociations[extension].icon = pathToIcon +end + +function MineOSCore.associateExtensionContextMenu(extension, pathToContextMenu) + MineOSCore.OSSettings.extensionAssociations[extension] = MineOSCore.OSSettings.extensionAssociations[extension] or {} + MineOSCore.OSSettings.extensionAssociations[extension].contextMenu = pathToContextMenu +end + +function MineOSCore.associateExtension(extension, pathToLauncher, pathToIcon, pathToContextMenu) + MineOSCore.associateExtensionLauncher(extension, pathToLauncher) + MineOSCore.associateExtensionIcon(extension, pathToIcon) + MineOSCore.associateExtensionContextMenu(extension, pathToContextMenu) +end + +function MineOSCore.associationsExtensionAutomatically() + local path, extension = MineOSCore.paths.extensionAssociations + for file in fs.list(path) do + if fs.isDirectory(path .. file) then + extension = "." .. unicode.sub(file, 1, -2) + + if fs.exists(path .. file .. "Context menu.lua") then + MineOSCore.associateExtensionContextMenu(extension, path .. file .. "Context menu.lua") + end + + if fs.exists(path .. file .. "Launcher.lua") then + MineOSCore.associateExtensionLauncher(extension, path .. file .. "Launcher.lua") + end + end + end +end + +----------------------------------------------------------------------------------------------------------------------------------- + function MineOSCore.loadIcon(name, path) if not MineOSCore.icons[name] then MineOSCore.icons[name] = image.load(path) end return MineOSCore.icons[name] end ---Вся необходимая информация для иконок -function MineOSCore.loadStandartIcons() - MineOSCore.icons = {} - MineOSCore.loadIcon("folder", MineOSCore.paths.icons .. "Folder.pic") - MineOSCore.loadIcon("script", MineOSCore.paths.icons .. "Script.pic") - MineOSCore.loadIcon("text", MineOSCore.paths.icons .. "Text.pic") - MineOSCore.loadIcon("config", MineOSCore.paths.icons .. "Config.pic") - MineOSCore.loadIcon("lua", MineOSCore.paths.icons .. "Lua.pic") - MineOSCore.loadIcon("image", MineOSCore.paths.icons .. "Image.pic") - MineOSCore.loadIcon("pastebin", MineOSCore.paths.icons .. "Pastebin.pic") - MineOSCore.loadIcon("fileNotExists", MineOSCore.paths.icons .. "FileNotExists.pic") - MineOSCore.loadIcon("archive", MineOSCore.paths.icons .. "Archive.pic") - MineOSCore.loadIcon("model3D", MineOSCore.paths.icons .. "3DModel.pic") - MineOSCore.loadIcon("application", MineOSCore.paths.icons .. "Application.pic") - MineOSCore.loadIcon("trash", MineOSCore.paths.icons .. "Trash.pic") -end - ----------------------------------------------------------------------------------------------------------------------------------- -function MineOSCore.init() - fs.makeDirectory(MineOSCore.paths.trash) - MineOSCore.loadOSSettings() - MineOSCore.localization = table.fromFile(MineOSCore.paths.localizationFiles .. MineOSCore.OSSettings.language .. ".lang") - MineOSCore.loadStandartIcons() -end - function MineOSCore.clearTerminal() gpu.setBackground(0x1D1D1D) gpu.setForeground(0xFFFFFF) @@ -221,6 +157,13 @@ function MineOSCore.waitForPressingAnyKey() end end +function MineOSCore.launchScript(path) + MineOSCore.clearTerminal() + if MineOSCore.safeLaunch(path) then + MineOSCore.waitForPressingAnyKey() + end +end + ----------------------------------------------------------------------------------------------------------------------------------- local function launchApp(icon) @@ -231,29 +174,6 @@ local function launchDirectory(icon) computer.pushSignal("MineOSCore", "changeWorkpath", icon.path) end -local function launchEditor(icon) - MineOSCore.safeLaunch(MineOSCore.paths.applications .. "/MineCode IDE.app/Main.lua", "open", icon.path) -end - -local function launchLua(icon) - MineOSCore.clearTerminal() - if MineOSCore.safeLaunch(icon.path) then - MineOSCore.waitForPressingAnyKey() - end -end - -local function launchImage(icon) - MineOSCore.safeLaunch(MineOSCore.paths.applications .. "Photoshop.app/Main.lua", "open", icon.path) -end - -local function launchPackage(icon) - require("compressor").unpack(icon.path, fs.path(icon.path)) -end - -local function launch3DPrint(icon) - MineOSCore.safeLaunch(MineOSCore.paths.applications .. "3DPrint.app/Main.lua", "open", icon.path) -end - local function launchLnk(icon) local oldPath = icon.path icon.path = icon.shortcutPath @@ -265,10 +185,18 @@ local function launchCorrupted(icon) GUI.error("Application is corrupted") end +local function launchExtension(icon) + MineOSCore.safeLaunch(MineOSCore.OSSettings.extensionAssociations[icon.extension].launcher, icon.path, "-o") +end + +local function launchScript(icon) + MineOSCore.launchScript(icon.path) +end + function MineOSCore.analyzeIconExtension(icon) if icon.isDirectory then if icon.extension == ".app" then - if MineOSCore.showApplicationIcons then + if MineOSCore.OSSettings.showApplicationIcons then icon.image = image.load(icon.path .. "/Resources/Icon.pic") else icon.image = MineOSCore.icons.application @@ -298,48 +226,43 @@ function MineOSCore.analyzeIconExtension(icon) icon.launch = launchLnk shortcutIcon = nil - elseif icon.extension == ".cfg" or icon.extension == ".config" then - icon.image = MineOSCore.icons.config - icon.launch = launchEditor - elseif icon.extension == ".txt" or icon.extension == ".rtf" then - icon.image = MineOSCore.icons.text - icon.launch = launchEditor - elseif icon.extension == ".lua" then - icon.image = MineOSCore.icons.lua - icon.launch = launchLua - elseif icon.extension == ".pic" or icon.extension == ".png" then - icon.image = MineOSCore.icons.image - icon.launch = launchImage - elseif icon.extension == ".pkg" then - icon.image = MineOSCore.icons.archive - icon.launch = launchPackage - elseif icon.extension == ".3dm" then - icon.image = MineOSCore.icons.model3D - icon.launch = launch3DPrint elseif not fs.exists(icon.path) then icon.image = MineOSCore.icons.fileNotExists icon.launch = launchCorrupted else - icon.image = MineOSCore.icons.script - icon.launch = launchLua + if MineOSCore.OSSettings.extensionAssociations[icon.extension] then + icon.launch = launchExtension + icon.image = MineOSCore.loadIcon(icon.extension, MineOSCore.OSSettings.extensionAssociations[icon.extension].icon) + else + icon.launch = launchScript + icon.image = MineOSCore.icons.script + end end end return icon end -function MineOSCore.getParametersForDrawingIcons(fieldWidth, fieldHeight, xSpaceBetweenIcons, ySpaceBetweenIcons) - local xCountOfIcons, yCountOfIcons = math.floor(fieldWidth / (MineOSCore.iconWidth + xSpaceBetweenIcons)), math.floor(fieldHeight / (MineOSCore.iconHeight + ySpaceBetweenIcons)) - local totalCountOfIcons = xCountOfIcons * yCountOfIcons - return xCountOfIcons, yCountOfIcons, totalCountOfIcons -end - local function iconDraw(icon) - if icon.isSelected then - buffer.square(icon.x, icon.y, icon.width, icon.height, icon.colors.selection, 0x000000, " ", 50) + if icon.selected then + buffer.square(icon.x, icon.y, icon.width, icon.height, icon.colors.selection, 0x000000, " ", 60) end - buffer.image(icon.x + 2, icon.y, icon.image) + if icon.cut then + if not icon.semiTransparentImage then + icon.semiTransparentImage = image.copy(icon.image) + for i = 3, #icon.semiTransparentImage, 4 do + icon.semiTransparentImage[i + 2] = icon.semiTransparentImage[i + 2] + 0.6 + if icon.semiTransparentImage[i + 2] > 1 then + icon.semiTransparentImage[i + 2] = 1 + end + end + end + + buffer.image(icon.x + 2, icon.y, icon.semiTransparentImage, true) + else + buffer.image(icon.x + 2, icon.y, icon.image) + end local text if icon.showExtension then @@ -359,7 +282,47 @@ local function iconDraw(icon) end end -function MineOSCore.createIcon(x, y, path, textColor, showExtension, selectionColor) +local function iconEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + object.lastTouchPosition = object.lastTouchPosition or {} + object.lastTouchPosition.x, object.lastTouchPosition.y = eventData[3], eventData[4] + object:moveToFront() + + object.selected = true + MineOSCore.OSDraw() + + if eventData[5] == 0 then + object.onLeftClick(object, eventData) + else + object.onRightClick(object, eventData) + object.selected = false + MineOSCore.OSDraw() + end + elseif eventData[1] == "double_touch" and object:isClicked(eventData[3], eventData[4]) and eventData[5] == 0 then + object.onDoubleClick(object, eventData) + elseif eventData[1] == "drag" and object.lastTouchPosition then + object.localPosition.x = object.localPosition.x + eventData[3] - object.lastTouchPosition.x + object.localPosition.y = object.localPosition.y + eventData[4] - object.lastTouchPosition.y + object.lastTouchPosition.x, object.lastTouchPosition.y = eventData[3], eventData[4] + + MineOSCore.OSDraw() + elseif eventData[1] == "drop" then + -- Сейвим позицию иконки на дисочек. Юзаем ручной поиск вместо :indexOf(), ибо + -- иконки из-за перемещения вперед могут иметь отличный от файллиста индекс + for i = 1, #object.parent.parent.fileList do + if object.parent.parent.workpath .. object.parent.parent.fileList[i] == object.path then + object.parent.parent.iconConfig[object.parent.parent.fileList[i]] = { + x = object.localPosition.x, + y = object.localPosition.y + } + object.parent.parent:saveIconConfig() + break + end + end + end +end + +function MineOSCore.icon(x, y, path, textColor, selectionColor, showExtension) local icon = GUI.object(x, y, MineOSCore.iconWidth, MineOSCore.iconHeight) icon.colors = { @@ -367,36 +330,19 @@ function MineOSCore.createIcon(x, y, path, textColor, showExtension, selectionCo selection = selectionColor, } icon.path = path - icon.size = fs.size(icon.path) icon.isDirectory = fs.isDirectory(icon.path) - icon.extension = fs.extension(icon.path) + icon.extension = fs.extension(icon.path) or "script" icon.showExtension = showExtension icon.isShortcut = false - icon.isSelected = false + icon.selected = false icon.draw = iconDraw -- Поддержка изменяемых извне функций правого и левого кликов icon.onLeftClick = MineOSCore.iconLeftClick icon.onRightClick = MineOSCore.iconRightClick - - -- Обработка клика непосредственно на иконку - icon.eventHandler = function(mainContainer, object, eventData) - if eventData[1] == "touch" then - icon.isSelected = true - MineOSCore.OSDraw() - - if eventData[5] == 0 then - os.sleep(MineOSCore.iconClickDelay) - icon.onLeftClick(icon, eventData) - else - icon.onRightClick(icon, eventData) - end - - icon.isSelected = false - MineOSCore.OSDraw() - end - end + icon.onDoubleClick = MineOSCore.iconDoubleClick + icon.eventHandler = iconEventHandler -- Онализ формата и прочего говна иконки для последующего получения изображения иконки и функции-лаунчера MineOSCore.analyzeIconExtension(icon) @@ -404,53 +350,289 @@ function MineOSCore.createIcon(x, y, path, textColor, showExtension, selectionCo return icon end -local function updateIconFieldFileList(iconField) +local function iconFieldUpdate(iconField) + iconField.backgroundObject.width, iconField.backgroundObject.height = iconField.width, iconField.height + iconField.foregroundObject.width, iconField.foregroundObject.height = iconField.width, iconField.height + iconField.iconsContainer.width, iconField.iconsContainer.height = iconField.width, iconField.height + + iconField.iconCount.horizontal = math.floor(iconField.width / (MineOSCore.iconWidth + iconField.spaceBetweenIcons.horizontal)) + iconField.iconCount.vertical = math.floor(iconField.height / (MineOSCore.iconHeight + iconField.spaceBetweenIcons.vertical)) + iconField.iconCount.total = iconField.iconCount.horizontal * iconField.iconCount.vertical + + return iconField +end + +local function iconFieldLoadIconConfig(iconField) + if fs.exists(iconField.workpath .. MineOSCore.iconConfigFileName) then + iconField.iconConfig = table.fromFile(iconField.workpath .. MineOSCore.iconConfigFileName) + + -- Чистим конфиг от файлов, которых более нет в иконфилде + local iconConfigItemExistsInFileList + for key in pairs(iconField.iconConfig) do + local iconConfigItemExistsInFileList = false + for i = 1, #iconField.fileList do + if key == iconField.fileList[i] then + iconConfigItemExistsInFileList = true + break + end + end + + if not iconConfigItemExistsInFileList then + iconField.iconConfig[key] = nil + end + end + + iconField:saveIconConfig() + else + iconField.iconConfig = {} + end +end + +local function iconFieldSaveIconConfig(iconField) + table.toFile(iconField.workpath .. MineOSCore.iconConfigFileName, iconField.iconConfig) +end + +local function iconFieldUpdateFileList(iconField) + -- Обновление файлового списка iconField.fileList = fs.sortedList(iconField.workpath, iconField.sortingMethod, iconField.showHiddenFiles) - iconField.children = {} - - local xPos, yPos, counter = 1, 1, 1 + -- Грузим инфу об иконочках + iconField:loadIconConfig() + -- Подсчет числа влезаемых иконочек + iconField:update() + -- Заполнение дочернего контейнера + iconField.iconsContainer:deleteChildren() + local xPos, yPos, horizontalIconCounter = 1, 1, 1 for i = iconField.fromFile, iconField.fromFile + iconField.iconCount.total - 1 do - if not iconField.fileList[i] then break end + if iconField.fileList[i] then + local xIcon, yIcon = xPos, yPos + if iconField.iconConfig[iconField.fileList[i]] then + xIcon, yIcon = iconField.iconConfig[iconField.fileList[i]].x, iconField.iconConfig[iconField.fileList[i]].y + else + xPos, horizontalIconCounter = xPos + MineOSCore.iconWidth + iconField.spaceBetweenIcons.horizontal, horizontalIconCounter + 1 + if horizontalIconCounter > iconField.iconCount.horizontal then + xPos, horizontalIconCounter = 1, 1 + yPos = yPos + MineOSCore.iconHeight + iconField.spaceBetweenIcons.vertical + end + end - iconField:addChild( - MineOSCore.createIcon( - xPos, - yPos, - iconField.workpath .. iconField.fileList[i], - iconField.colors.iconText, - iconField.showExtension, - iconField.selectionColor + iconField.iconsContainer:addChild( + MineOSCore.icon( + xIcon, yIcon, + iconField.workpath .. iconField.fileList[i], + iconField.colors.text, + iconField.colors.selection, + iconField.showExtension + ) ) - ) - - xPos, counter = xPos + MineOSCore.iconWidth + iconField.spaceBetweenIcons.x, counter + 1 - if counter > iconField.iconCount.width then - xPos, counter = 1, 1 - yPos = yPos + MineOSCore.iconHeight + iconField.spaceBetweenIcons.y + else + break end end return iconField end -function MineOSCore.createIconField(x, y, width, height, xCountOfIcons, yCountOfIcons, totalCountOfIcons, xSpaceBetweenIcons, ySpaceBetweenIcons, iconTextColor, showExtension, showHiddenFiles, sortingMethod, workpath, selectionColor) +local function iconFieldBackgroundObjectEventHandler(mainContainer, object, eventData) + if eventData[1] == "touch" then + if eventData[5] == 0 then + object.parent:deselectAll() + object.parent.selection.firstReady, object.parent.selection.x1, object.parent.selection.y1 = true, eventData[3], eventData[4] + MineOSCore.OSDraw() + else + local menu = MineOSCore.contextMenu(eventData[3], eventData[4]) + + menu:addItem(MineOSCore.localization.newFile).onTouch = function() + computer.pushSignal("MineOSCore", "newFile") + end + + menu:addItem(MineOSCore.localization.newFolder).onTouch = function() + computer.pushSignal("MineOSCore", "newFolder") + end + + menu:addItem(MineOSCore.localization.newApplication).onTouch = function() + computer.pushSignal("MineOSCore", "newApplication") + end + + menu:addSeparator() + + local subMenu = menu:addSubMenu(MineOSCore.localization.view) + + subMenu:addItem(MineOSCore.OSMainContainer.iconField.showExtension and MineOSCore.localization.hideExtension or MineOSCore.localization.showExtension).onTouch = function() + MineOSCore.OSMainContainer.iconField.showExtension = not MineOSCore.OSMainContainer.iconField.showExtension + MineOSCore.OSSettings.showExtension = MineOSCore.OSMainContainer.iconField.showExtension + MineOSCore.saveOSSettings() + computer.pushSignal("MineOSCore", "updateFileList") + end + + subMenu:addItem(MineOSCore.OSMainContainer.iconField.showHiddenFiles and MineOSCore.localization.hideHiddenFiles or MineOSCore.localization.showHiddenFiles).onTouch = function() + MineOSCore.OSMainContainer.iconField.showHiddenFiles = not MineOSCore.OSMainContainer.iconField.showHiddenFiles + MineOSCore.OSSettings.showHiddenFiles = MineOSCore.OSMainContainer.iconField.showHiddenFiles + MineOSCore.saveOSSettings() + computer.pushSignal("MineOSCore", "updateFileList") + end + + subMenu:addItem(MineOSCore.OSSettings.showApplicationIcons and MineOSCore.localization.hideApplicationIcons or MineOSCore.localization.showApplicationIcons).onTouch = function() + MineOSCore.OSSettings.showApplicationIcons = not MineOSCore.OSSettings.showApplicationIcons + MineOSCore.saveOSSettings() + computer.pushSignal("MineOSCore", "updateFileList") + end + + local subMenu = menu:addSubMenu(MineOSCore.localization.sortBy) + subMenu:addItem(MineOSCore.localization.sortByName).onTouch = function() + MineOSCore.OSSettings.sortingMethod = "name" + MineOSCore.saveOSSettings() + MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod + computer.pushSignal("MineOSCore", "updateFileList") + end + + menu:addItem(MineOSCore.localization.sortAutomatically).onTouch = function() + object.parent.iconConfig = {} + object.parent:saveIconConfig() + computer.pushSignal("MineOSCore", "updateFileList") + end + + subMenu:addItem(MineOSCore.localization.sortByDate).onTouch = function() + MineOSCore.OSSettings.sortingMethod = "date" + MineOSCore.saveOSSettings() + MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod + computer.pushSignal("MineOSCore", "updateFileList") + end + + subMenu:addItem(MineOSCore.localization.sortByType).onTouch = function() + MineOSCore.OSSettings.sortingMethod = "type" + MineOSCore.saveOSSettings() + MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod + computer.pushSignal("MineOSCore", "updateFileList") + end + + menu:addSeparator() + + menu:addItem(MineOSCore.localization.paste, not MineOSCore.clipboard).onTouch = function() + local i = 1 + while i <= #MineOSCore.clipboard do + if fs.exists(MineOSCore.clipboard[i]) then + i = i + 1 + else + table.remove(MineOSCore.clipboard, i) + end + end + + MineOSCore.copy(MineOSCore.clipboard, object.parent.workpath) + + if MineOSCore.clipboard.cut then + for i = 1, #MineOSCore.clipboard do + fs.remove(MineOSCore.clipboard[i]) + end + MineOSCore.clipboard = nil + end + + computer.pushSignal("MineOSCore", "updateFileList") + end + + menu:show() + end + elseif eventData[1] == "drag" then + object.parent.foregroundObject.hidden = false + computer.pushSignal(table.unpack(eventData)) + end +end + +local function iconFieldForegroundObjectEventHandler(mainContainer, object, eventData) + if eventData[1] == "drag" then + object.parent.selection.secondReady, object.parent.selection.x2, object.parent.selection.y2 = true, eventData[3], eventData[4] + MineOSCore.OSDraw() + elseif eventData[1] == "touch" or eventData[1] == "drop" then + object.parent.selection.firstReady, object.parent.selection.secondReady = false, false + object.parent.foregroundObject.hidden = true + MineOSCore.OSDraw() + end +end + +local function iconFieldForegroundObjectDraw(object) + if object.parent.selection.firstReady and object.parent.selection.secondReady then + local x1, y1, x2, y2 = object.parent.selection.x1, object.parent.selection.y1, object.parent.selection.x2, object.parent.selection.y2 + + if x2 < x1 then + x1, x2 = x2, x1 + end + + if y2 < y1 then + y1, y2 = y2, y1 + end + + local width, height = x2 - x1 + 1, y2 - y1 + 1 + buffer.square(x1, y1, width, height, 0xFFFFFF, 0x0, " ", 70) + buffer.frame(x1, y1, width, height, 0xFFFFFF) + + local partialWidth, partialHeight = MineOSCore.iconWidth * MineOSCore.selectionIconPart, MineOSCore.iconHeight * MineOSCore.selectionIconPart + for i = 1, #object.parent.iconsContainer.children do + object.parent.iconsContainer.children[i].selected = + object.parent.iconsContainer.children[i].x + partialWidth >= x1 and + object.parent.iconsContainer.children[i].x + object.parent.iconsContainer.children[i].width - 1 - partialWidth <= x2 and + object.parent.iconsContainer.children[i].y + partialHeight >= y1 and + object.parent.iconsContainer.children[i].y + object.parent.iconsContainer.children[i].height - 1 - partialHeight <= y2 + end + end +end + +local function iconFieldDeselectAll(iconField) + for i = 1, #iconField.iconsContainer.children do + iconField.iconsContainer.children[i].selected = false + end +end + +local function iconFieldGetSelectedIcons(iconField) + local selectedIcons = {} + + for i = 1, #iconField.iconsContainer.children do + if iconField.iconsContainer.children[i].selected then + table.insert(selectedIcons, iconField.iconsContainer.children[i]) + end + end + + return selectedIcons +end + +function MineOSCore.iconField(x, y, width, height, xSpaceBetweenIcons, ySpaceBetweenIcons, textColor, selectionColor, showExtension, showHiddenFiles, sortingMethod, workpath) local iconField = GUI.container(x, y, width, height) - iconField.colors = {iconText = iconTextColor} + iconField.colors = { + text = textColor, + selection = selectionColor + } + iconField.spaceBetweenIcons = { + horizontal = xSpaceBetweenIcons, + vertical = ySpaceBetweenIcons + } + + iconField.iconConfig = {} + iconField.selection = {} iconField.iconCount = {} - iconField.spaceBetweenIcons = {x = xSpaceBetweenIcons, y = ySpaceBetweenIcons} - iconField.iconCount.width, iconField.iconCount.height, iconField.iconCount.total = xCountOfIcons, yCountOfIcons, totalCountOfIcons + iconField.fileList = {} + iconField.fromFile = 1 + + iconField.backgroundObject = iconField:addChild(GUI.object(1, 1, width, height)) + iconField.backgroundObject.eventHandler = iconFieldBackgroundObjectEventHandler + + iconField.iconsContainer = iconField:addChild(GUI.container(1, 1, width, height)) + + iconField.foregroundObject = iconField:addChild(GUI.object(1, 1, width, height)) + iconField.foregroundObject.eventHandler = iconFieldForegroundObjectEventHandler + iconField.foregroundObject.hidden = true + iconField.foregroundObject.draw = iconFieldForegroundObjectDraw iconField.workpath = workpath iconField.showExtension = showExtension iconField.showHiddenFiles = showHiddenFiles iconField.sortingMethod = sortingMethod - iconField.fileList = {} - iconField.fromFile = 1 - iconField.selectionColor = selectionColor - - iconField.updateFileList = updateIconFieldFileList + iconField.updateFileList = iconFieldUpdateFileList + iconField.update = iconFieldUpdate + iconField.eventHandler = iconFieldEventHandler + iconField.deselectAll = iconFieldDeselectAll + iconField.loadIconConfig = iconFieldLoadIconConfig + iconField.saveIconConfig = iconFieldSaveIconConfig + iconField.getSelectedIcons = iconFieldGetSelectedIcons return iconField end @@ -615,202 +797,196 @@ end ----------------------------------------------------------------------------------------------------------------------------------- +function MineOSCore.contextMenu(...) + local menu = GUI.contextMenu(...) + + menu.colors.transparency.background = MineOSCore.OSSettings.transparencyEnabled and GUI.colors.contextMenu.transparency.background + menu.colors.transparency.shadow = MineOSCore.OSSettings.transparencyEnabled and GUI.colors.contextMenu.transparency.shadow + + return menu +end + function MineOSCore.iconLeftClick(icon, eventData) - MineOSCore.lastLaunchPath = icon.path + if not keyboard.isKeyDown(29) and not keyboard.isKeyDown(219) then + icon.parent.parent:deselectAll() + end + icon.selected = true + + MineOSCore.OSDraw() +end + +function MineOSCore.iconDoubleClick(icon, eventData) + MineOSCore.lastLaunchPath = icon.path icon:launch() computer.pushSignal("MineOSCore", "updateFileList") end function MineOSCore.iconRightClick(icon, eventData) - local action - -- Разные контекстные меню - if icon.isDirectory then - if icon.extension == ".app" then - action = GUI.contextMenu(eventData[3], eventData[4], - {MineOSCore.localization.contextMenuShowPackageContent}, - "-", - {MineOSCore.localization.contextMenuCut}, - {MineOSCore.localization.contextMenuCopy}, - {MineOSCore.localization.contextMenuRename}, - {MineOSCore.localization.contextMenuDelete}, - {MineOSCore.localization.contextMenuCreateShortcut, icon.extension == ".lnk"}, - {MineOSCore.localization.contextMenuArchive}, - "-", - {MineOSCore.localization.contextMenuAddToDock}, - {MineOSCore.localization.contextMenuProperties} - ):show() - else - action = GUI.contextMenu(eventData[3], eventData[4], - {MineOSCore.localization.contextMenuCut}, - {MineOSCore.localization.contextMenuCopy}, - {MineOSCore.localization.contextMenuRename}, - {MineOSCore.localization.contextMenuDelete}, - {MineOSCore.localization.contextMenuCreateShortcut, icon.extension == ".lnk"}, - {MineOSCore.localization.contextMenuArchive}, - "-", - {MineOSCore.localization.contextMenuAddToDock}, - {MineOSCore.localization.contextMenuProperties} - ):show() - end - else - if icon.isShortcut then - action = GUI.contextMenu(eventData[3], eventData[4], - {MineOSCore.localization.contextMenuEdit}, - {MineOSCore.localization.contextMenuShowContainingFolder}, - "-", - {MineOSCore.localization.contextMenuCut}, - {MineOSCore.localization.contextMenuCopy}, - {MineOSCore.localization.contextMenuRename}, - {MineOSCore.localization.contextMenuDelete}, - "-", - {MineOSCore.localization.contextMenuAddToDock}, - {MineOSCore.localization.contextMenuProperties} - ):show() - elseif icon.extension == ".pic" then - action = GUI.contextMenu(eventData[3], eventData[4], - {MineOSCore.localization.contextMenuSetAsWallpaper}, - "-", - {MineOSCore.localization.contextMenuCut}, - {MineOSCore.localization.contextMenuCopy}, - {MineOSCore.localization.contextMenuRename}, - {MineOSCore.localization.contextMenuDelete}, - {MineOSCore.localization.contextMenuCreateShortcut, icon.extension == ".lnk"}, - "-", - {MineOSCore.localization.contextMenuAddToDock}, - {MineOSCore.localization.contextMenuProperties} - ):show() - elseif icon.extension == ".lua" then - action = GUI.contextMenu(eventData[3], eventData[4], - {MineOSCore.localization.contextMenuEdit}, - {MineOSCore.localization.launchWithArguments}, - {MineOSCore.localization.contextMenuFlashEEPROM, (not component.isAvailable("eeprom") or icon.size > 4096)}, - "-", - {MineOSCore.localization.contextMenuCut}, - {MineOSCore.localization.contextMenuCopy}, - {MineOSCore.localization.contextMenuRename}, - {MineOSCore.localization.contextMenuDelete}, - {MineOSCore.localization.contextMenuCreateShortcut, icon.extension == ".lnk"}, - "-", - {MineOSCore.localization.contextMenuAddToDock}, - {MineOSCore.localization.contextMenuProperties} - ):show() - else - action = GUI.contextMenu(eventData[3], eventData[4], - {MineOSCore.localization.contextMenuEdit}, - "-", - {MineOSCore.localization.contextMenuCut}, - {MineOSCore.localization.contextMenuCopy}, - {MineOSCore.localization.contextMenuRename}, - {MineOSCore.localization.contextMenuDelete}, - {MineOSCore.localization.contextMenuCreateShortcut, icon.extension == ".lnk"}, - "-", - {MineOSCore.localization.contextMenuAddToDock}, - {MineOSCore.localization.contextMenuProperties} - ):show() - end - end + icon.selected = true + MineOSCore.OSDraw() - if action == MineOSCore.localization.contextMenuEdit then - MineOSCore.safeLaunch(MineOSCore.paths.applications .. "/MineCode IDE.app/Main.lua", "open", icon.path) - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == "Свойства" then - MineOSCore.propertiesWindow(eventData[3], eventData[4], 40, icon) - elseif action == MineOSCore.localization.contextMenuShowContainingFolder then - computer.pushSignal("MineOSCore", "changeWorkpath", fs.path(icon.shortcutPath)) - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == MineOSCore.localization.contextMenuAddToFavourites then - computer.pushSignal("finderFavouriteAdded", icon.path) - elseif action == MineOSCore.localization.contextMenuShowPackageContent then - computer.pushSignal("MineOSCore", "changeWorkpath", icon.path) - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == MineOSCore.localization.contextMenuCopy then - _G.clipboard = icon.path - elseif action == MineOSCore.localization.contextMenuCut then - _G.clipboard = icon.path - _G.clipboardCut = true - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == MineOSCore.localization.contextMenuDelete then - if fs.path(icon.path) == MineOSCore.paths.trash then - fs.remove(icon.path) - else - local newName = MineOSCore.paths.trash .. fs.name(icon.path) - local clearName = fs.hideExtension(fs.name(icon.path)) - local repeats = 1 - while fs.exists(newName) do - newName, repeats = MineOSCore.paths.trash .. clearName .. string.rep("-copy", repeats) .. icon.extension, repeats + 1 + local selectedIcons = icon.parent.parent:getSelectedIcons() + + local menu = MineOSCore.contextMenu(eventData[3], eventData[4]) + if #selectedIcons == 1 then + if icon.isDirectory then + if icon.extension == ".app" then + menu:addItem(MineOSCore.localization.showPackageContent).onTouch = function() + computer.pushSignal("MineOSCore", "changeWorkpath", icon.path) + computer.pushSignal("MineOSCore", "updateFileList") + end + menu:addItem(MineOSCore.localization.launchWithArguments).onTouch = function() + MineOSCore.launchWithArguments(MineOSCore.OSMainContainer, icon.path) + end end - fs.rename(icon.path, newName) - end - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == MineOSCore.localization.contextMenuRename then - computer.pushSignal("MineOSCore", "rename", icon.path) - elseif action == MineOSCore.localization.contextMenuCreateShortcut then - MineOSCore.createShortcut(fs.path(icon.path) .. "/" .. fs.hideExtension(fs.name(icon.path)) .. ".lnk", icon.path) - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == MineOSCore.localization.contextMenuArchive then - require("compressor").pack(fs.path(icon.path) .. fs.hideExtension(fs.name(icon.path)) .. ".pkg", icon.path) - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == MineOSCore.localization.contextMenuSetAsWallpaper then - MineOSCore.OSSettings.wallpaper = icon.path - MineOSCore.saveOSSettings() - computer.pushSignal("MineOSCore", "updateWallpaper") - elseif action == MineOSCore.localization.contextMenuFlashEEPROM then - local file = io.open(icon.path, "r") - component.eeprom.set(file:read("*a")) - file:close() - computer.beep(1500, 0.2) - elseif action == MineOSCore.localization.contextMenuAddToDock then - MineOSCore.OSMainContainer.dockContainer.addIcon(icon.path).keepInDock = true - MineOSCore.OSMainContainer.dockContainer.saveToOSSettings() - elseif action == MineOSCore.localization.launchWithArguments then - MineOSCore.launchWithArguments(MineOSCore.OSMainContainer, icon.path) - end -end -function MineOSCore.emptyZoneClick(eventData, mainContainer, workpath) - local action = GUI.contextMenu(eventData[3], eventData[4], - {MineOSCore.localization.contextMenuNewFile}, - {MineOSCore.localization.contextMenuNewFolder}, - {MineOSCore.localization.contextMenuNewApplication}, - "-", - {MineOSCore.localization.contextMenuPaste, (_G.clipboard == nil)} - ):show() + menu:addItem(MineOSCore.localization.archive).onTouch = function() + require("compressor").pack(fs.path(icon.path) .. fs.hideExtension(fs.name(icon.path)) .. ".pkg", icon.path) + computer.pushSignal("MineOSCore", "updateFileList") + end + else + if icon.isShortcut then + menu:addItem(MineOSCore.localization.editShortcut).onTouch = function() + MineOSCore.editShortcut(MineOSCore.OSMainContainer, icon.path) + computer.pushSignal("MineOSCore", "updateFileList") + end - if action == MineOSCore.localization.contextMenuNewFile then - computer.pushSignal("MineOSCore", "newFile") - elseif action == MineOSCore.localization.contextMenuNewFolder then - computer.pushSignal("MineOSCore", "newFolder") - elseif action == MineOSCore.localization.contextMenuPaste then - ecs.copy(_G.clipboard, workpath) - if _G.clipboardCut then - fs.remove(_G.clipboard) - _G.clipboardCut = nil - _G.clipboard = nil + menu:addItem(MineOSCore.localization.showContainingFolder).onTouch = function() + computer.pushSignal("MineOSCore", "changeWorkpath", fs.path(icon.shortcutPath)) + computer.pushSignal("MineOSCore", "updateFileList") + end + else + if MineOSCore.OSSettings.extensionAssociations[icon.extension] and MineOSCore.OSSettings.extensionAssociations[icon.extension].contextMenu then + pcall(loadfile(MineOSCore.OSSettings.extensionAssociations[icon.extension].contextMenu), icon, menu) + end + + -- local subMenu = menu:addSubMenu(MineOSCore.localization.openWith) + -- local fileList = fs.sortedList(MineOSCore.paths.applications, "name") + -- subMenu:addItem(MineOSCore.localization.select) + -- subMenu:addSeparator() + -- for i = 1, #fileList do + -- subMenu:addItem(fs.hideExtension(fileList[i])) + -- end + end end - computer.pushSignal("MineOSCore", "updateFileList") - elseif action == MineOSCore.localization.contextMenuNewApplication then - computer.pushSignal("MineOSCore", "newApplication") + + menu:addSeparator() end + + if #selectedIcons > 1 then + menu:addItem(MineOSCore.localization.newFolderFromChosen .. " (" .. #selectedIcons .. ")").onTouch = function() + MineOSCore.newFolderFromChosen(MineOSCore.OSMainContainer, selectedIcons) + end + menu:addSeparator() + end + + local function cutOrCopy(cut) + for i = 1, #icon.parent.children do + icon.parent.children[i].cut = nil + end + + MineOSCore.clipboard = {cut = cut} + for i = 1, #selectedIcons do + selectedIcons[i].cut = cut + table.insert(MineOSCore.clipboard, selectedIcons[i].path) + end + end + + menu:addItem(MineOSCore.localization.cut).onTouch = function() + cutOrCopy(true) + end + + menu:addItem(MineOSCore.localization.copy).onTouch = function() + cutOrCopy() + end + + if not icon.isShortcut or #selectedIcons > 1 then + local subMenu = menu:addSubMenu(MineOSCore.localization.createShortcut) + + subMenu:addItem(MineOSCore.localization.inCurrentDirectory).onTouch = function() + for i = 1, #selectedIcons do + if not selectedIcons[i].isShortcut then + MineOSCore.createShortcut( + fs.path(selectedIcons[i].path) .. "/" .. fs.hideExtension(fs.name(selectedIcons[i].path)) .. ".lnk", + selectedIcons[i].path + ) + end + end + + computer.pushSignal("MineOSCore", "updateFileList") + end + + subMenu:addItem(MineOSCore.localization.onDesktop).onTouch = function() + for i = 1, #selectedIcons do + if not selectedIcons[i].isShortcut then + MineOSCore.createShortcut( + fs.path(MineOSCore.paths.desktop) .. "/" .. fs.hideExtension(fs.name(selectedIcons[i].path)) .. ".lnk", + selectedIcons[i].path + ) + end + end + + computer.pushSignal("MineOSCore", "updateFileList") + end + end + + if #selectedIcons == 1 then + menu:addItem(MineOSCore.localization.rename).onTouch = function() + computer.pushSignal("MineOSCore", "rename", icon.path) + end + end + + menu:addItem(MineOSCore.localization.delete).onTouch = function() + for i = 1, #selectedIcons do + if fs.path(selectedIcons[i].path) == MineOSCore.paths.trash then + fs.remove(selectedIcons[i].path) + else + local newName = MineOSCore.paths.trash .. fs.name(selectedIcons[i].path) + local clearName = fs.hideExtension(fs.name(selectedIcons[i].path)) + local repeats = 1 + while fs.exists(newName) do + newName, repeats = MineOSCore.paths.trash .. clearName .. string.rep("-copy", repeats) .. selectedIcons[i].extension, repeats + 1 + end + fs.rename(selectedIcons[i].path, newName) + end + end + + computer.pushSignal("MineOSCore", "updateFileList") + end + + menu:addSeparator() + + if #selectedIcons == 1 then + menu:addItem(MineOSCore.localization.addToDock).onTouch = function() + MineOSCore.OSMainContainer.dockContainer.addIcon(icon.path).keepInDock = true + MineOSCore.OSMainContainer.dockContainer.saveToOSSettings() + end + end + + menu:addItem(MineOSCore.localization.properties).onTouch = function() + for i = 1, #selectedIcons do + MineOSCore.propertiesWindow(eventData[3], eventData[4], 40, selectedIcons[i]) + end + end + + menu:show() + + icon.parent.parent:deselectAll() + MineOSCore.OSDraw() end ----------------------------------------------------------------------------------------------------------------------------------- function MineOSCore.addUniversalContainer(parentContainer, title) local container = parentContainer:addChild(GUI.container(1, 1, parentContainer.width, parentContainer.height)) - container.panel = container:addChild(GUI.panel(1, 1, container.width, container.height, 0x0, 30)) + + container.panel = container:addChild(GUI.panel(1, 1, container.width, container.height, MineOSCore.OSSettings.transparencyEnabled and 0x0 or (MineOSCore.OSSettings.backgroundColor or 0x0F0F0F), MineOSCore.OSSettings.transparencyEnabled and 20)) container.layout = container:addChild(GUI.layout(1, 1, container.width, container.height, 1, 1)) - container.layout:addChild(GUI.label(1, 1, unicode.len(title), 1, 0xEEEEEE, title)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) - return container -end + if title then + container.layout:addChild(GUI.label(1, 1, unicode.len(title), 1, 0xEEEEEE, title)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + end ------------------------------------------------------------------------------------------------------------------------------------ - -local function addUniversalContainerWithInputTextBoxes(parentWindow, path, text, title, placeholder) - local container = MineOSCore.addUniversalContainer(parentWindow, title) - - container.inputField = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, text, placeholder, false)) - container.label = container.layout:addChild(GUI.label(1, 1, 36, 3, 0xFF4940, " ")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) container.panel.eventHandler = function(mainContainer, object, eventData) if eventData[1] == "touch" then container:delete() @@ -819,6 +995,17 @@ local function addUniversalContainerWithInputTextBoxes(parentWindow, path, text, end end + return container +end + +----------------------------------------------------------------------------------------------------------------------------------- + +local function addUniversalContainerWithInputTextBox(parentWindow, text, title, placeholder) + local container = MineOSCore.addUniversalContainer(parentWindow, title) + + container.inputField = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, text, placeholder, false)) + container.label = container.layout:addChild(GUI.label(1, 1, 36, 3, 0xFF4940, " ")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + parentWindow:draw() buffer.draw() @@ -827,7 +1014,7 @@ end local function checkFileToExists(container, path) if fs.exists(path) then - container.label.text = MineOSCore.localization.fileAlreadyExists + container.label.text = MineOSCore.localization.file .. " " .. MineOSCore.localization.alreadyExists container.parent:draw() buffer.draw() else @@ -838,7 +1025,7 @@ local function checkFileToExists(container, path) end function MineOSCore.newApplication(parentWindow, path) - local container = addUniversalContainerWithInputTextBoxes(parentWindow, path, nil, MineOSCore.localization.contextMenuNewApplication, MineOSCore.localization.applicationName) + local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newApplication, MineOSCore.localization.applicationName) container.inputField.onInputFinished = function() local finalPath = path .. container.inputField.text .. ".app/" @@ -855,20 +1042,20 @@ function MineOSCore.newApplication(parentWindow, path) end function MineOSCore.newFile(parentWindow, path) - local container = addUniversalContainerWithInputTextBoxes(parentWindow, path, nil, MineOSCore.localization.contextMenuNewFile, MineOSCore.localization.fileName) + local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newFile, MineOSCore.localization.fileName) container.inputField.onInputFinished = function() if checkFileToExists(container, path .. container.inputField.text) then local file = io.open(path .. container.inputField.text, "w") file:close() - MineOSCore.safeLaunch(MineOSCore.paths.applications .. "/MineCode IDE.app/Main.lua", "open", path .. container.inputField.text) + MineOSCore.safeLaunch(MineOSCore.paths.editor, path .. container.inputField.text) computer.pushSignal("MineOSCore", "updateFileList") end end end function MineOSCore.newFolder(parentWindow, path) - local container = addUniversalContainerWithInputTextBoxes(parentWindow, path, nil, MineOSCore.localization.contextMenuNewFolder, MineOSCore.localization.folderName) + local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newFolder, MineOSCore.localization.folderName) container.inputField.onInputFinished = function() if checkFileToExists(container, path .. container.inputField.text) then @@ -876,10 +1063,30 @@ function MineOSCore.newFolder(parentWindow, path) computer.pushSignal("MineOSCore", "updateFileList") end end + + return container +end + +function MineOSCore.newFolderFromChosen(parentWindow, selectedIcons) + local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newFolderFromChosen .. " (" .. #selectedIcons .. ")", MineOSCore.localization.folderName) + + container.inputField.onInputFinished = function() + local path = fs.path(selectedIcons[1].path) .. container.inputField.text + if checkFileToExists(container, path) then + fs.makeDirectory(path) + for i = 1, #selectedIcons do + fs.rename(selectedIcons[i].path, path .. "/" .. fs.name(selectedIcons[i].path)) + end + + computer.pushSignal("MineOSCore", "updateFileList") + end + end + + return container end function MineOSCore.rename(parentWindow, path) - local container = addUniversalContainerWithInputTextBoxes(parentWindow, path, fs.name(path), MineOSCore.localization.contextMenuRename, MineOSCore.localization.newName) + local container = addUniversalContainerWithInputTextBox(parentWindow, fs.name(path), MineOSCore.localization.rename, MineOSCore.localization.newName) container.inputField.onInputFinished = function() if checkFileToExists(container, fs.path(path) .. container.inputField.text) then @@ -887,10 +1094,31 @@ function MineOSCore.rename(parentWindow, path) computer.pushSignal("MineOSCore", "updateFileList") end end + + container.inputField:startInput() +end + +function MineOSCore.editShortcut(parentWindow, path) + local text = MineOSCore.readShortcut(path) + local container = addUniversalContainerWithInputTextBox(parentWindow, text, MineOSCore.localization.editShortcut, MineOSCore.localization.rename) + + container.panel.eventHandler = nil + container.inputField.onInputFinished = function() + if fs.exists(container.inputField.text) then + MineOSCore.createShortcut(path, container.inputField.text) + container:delete() + computer.pushSignal("MineOSCore", "updateFileList") + else + container.label.text = MineOSCore.localization.shortcutIsCorrupted + MineOSCore.OSDraw() + end + end + + container.inputField:startInput() end function MineOSCore.launchWithArguments(parentWindow, path) - local container = addUniversalContainerWithInputTextBoxes(parentWindow, path, nil, MineOSCore.localization.launchWithArguments) + local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.launchWithArguments) container.inputField.onInputFinished = function() local args = {} @@ -919,9 +1147,8 @@ function MineOSCore.applicationHelp(parentWindow, path) for line in io.lines(pathToAboutFile) do table.insert(lines, line) end - lines = string.wrap(lines, 50) - container.layout:addChild(GUI.textBox(1, 1, 50, #lines, nil, 0xcccccc, lines, 1, 0, 0)) + container.layout:addChild(GUI.textBox(1, 1, 50, 1, nil, 0xcccccc, lines, 1, 0, 0, true, true)) local button = container.layout:addChild(GUI.button(1, 1, 30, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.dontShowAnymore)) container.panel.eventHandler = function(mainContainer, object, eventData) @@ -1047,19 +1274,18 @@ local function addKeyAndValue(window, x, y, key, value) end function MineOSCore.propertiesWindow(x, y, width, icon) - local mainContainer, window = MineOSCore.addWindow(GUI.titledWindow(x, y, width, 1, package.loaded.MineOSCore.localization.contextMenuProperties)) + local mainContainer, window = MineOSCore.addWindow(GUI.titledWindow(x, y, width, 1, package.loaded.MineOSCore.localization.properties)) -- window.backgroundPanel.colors.transparency = 25 window:addChild(GUI.image(2, 3, icon.image)) local x, y = 11, 3 addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.type, icon.extension and icon.extension or (icon.isDirectory and package.loaded.MineOSCore.localization.folder or package.loaded.MineOSCore.localization.unknown)); y = y + 1 - local fileSizeLabel = addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.size, icon.isDirectory and package.loaded.MineOSCore.localization.calculatingSize or string.format("%.2f", icon.size / 1024) .. " KB"); y = y + 1 - addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.date, os.date("%d.%m.%y, %H:%M", fs.lastModified(icon.path))); y = y + 1 + local fileSizeLabel = addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.size, icon.isDirectory and package.loaded.MineOSCore.localization.calculatingSize or string.format("%.2f", fs.size(icon.path) / 1024) .. " KB"); y = y + 1 + addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.date, os.date("%d.%m.%y, %H:%M", math.floor(fs.lastModified(icon.path) / 1000))); y = y + 1 addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.path, " ") - local lines = string.wrap(icon.path, window.width - 18) - local textBox = window:addChild(GUI.textBox(17, y, window.width - 18, #lines, nil, 0x555555, lines, 1)) + local textBox = window:addChild(GUI.textBox(17, y, window.width - 18, 1, nil, 0x555555, {icon.path}, 1, 0, 0, true, true)) window:resize(window.width, textBox.y + textBox.height) textBox.eventHandler = nil @@ -1075,15 +1301,145 @@ end ----------------------------------------------------------------------------------------------------------------------------------- -function MineOSCore.OSDraw(force) - MineOSCore.OSMainContainer:draw() - buffer.draw(force) +local function GUICopy(parentContainer, fileList, toPath) + local applyYes, breakRecursion + + local container = MineOSCore.addUniversalContainer(parentContainer, MineOSCore.localization.copying) + local textBox = container.layout:addChild(GUI.textBox(1, 1, container.width, 1, nil, 0x777777, {}, 1, 0, 0, true, true):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)) + local switchAndLabel = container.layout:addChild(GUI.switchAndLabel(1, 1, 37, 8, 0x66DB80, 0x2D2D2D, 0xEEEEEE, 0x777777, MineOSCore.localization.applyToAll .. ":", false)) + container.panel.eventHandler = nil + + local buttonsLayout = container.layout:addChild(GUI.layout(1, 1, 1, 1, 1, 1)) + buttonsLayout:addChild(GUI.button(1, 1, 11, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.yes)).onTouch = function() + applyYes = true + parentContainer:stopEventHandling() + end + buttonsLayout:addChild(GUI.button(1, 1, 11, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.no)).onTouch = function() + parentContainer:stopEventHandling() + end + buttonsLayout:addChild(GUI.button(1, 1, 11, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.cancel)).onTouch = function() + breakRecursion = true + parentContainer:stopEventHandling() + end + buttonsLayout:setCellDirection(1, 1, GUI.directions.horizontal) + buttonsLayout:setCellSpacing(1, 1, 2) + buttonsLayout:fitToChildrenSize(1, 1) + + local function copyOrMove(path, finalPath) + switchAndLabel.hidden = true + buttonsLayout.hidden = true + + textBox.lines = { + MineOSCore.localization.copying .. " " .. MineOSCore.localization.faylaBlyad .. " " .. fs.name(path) .. " " .. MineOSCore.localization.toDirectory .. " " .. string.canonicalPath(toPath), + } + textBox.height = #textBox.lines + + parentContainer:draw() + buffer.draw() + + fs.remove(finalPath) + fs.copy(path, finalPath) + end + + local function recursiveCopy(path, toPath) + local finalPath = toPath .. "/" .. fs.name(path) + + if fs.isDirectory(path) then + fs.makeDirectory(finalPath) + + for file in fs.list(path) do + if breakRecursion then + return + end + recursiveCopy(path .. "/" .. file, finalPath) + end + else + if fs.exists(finalPath) then + if not switchAndLabel.switch.state then + switchAndLabel.hidden = false + buttonsLayout.hidden = false + applyYes = false + + textBox.lines = { + MineOSCore.localization.file .. " " .. fs.name(path) .. " " .. MineOSCore.localization.alreadyExists .. " " .. MineOSCore.localization.inDirectory .. " " .. string.canonicalPath(toPath), + MineOSCore.localization.needReplace, + } + textBox.height = #textBox.lines + + parentContainer:draw() + buffer.draw() + + parentContainer:startEventHandling() + + parentContainer:draw() + buffer.draw() + end + + if applyYes then + copyOrMove(path, finalPath) + end + else + copyOrMove(path, finalPath) + end + end + end + + for i = 1, #fileList do + recursiveCopy(fileList[i], toPath) + end + + container:delete() + parentContainer:draw() + buffer.draw() +end + +function MineOSCore.copy(what, toPath) + if type(what) == "string" then + what = {what} + end + + GUICopy(MineOSCore.OSMainContainer, what, toPath) +end + +----------------------------------------------------------------------------------------------------------------------------------- + +function MineOSCore.init() + MineOSCore.icons = {} + MineOSCore.loadOSSettings() + MineOSCore.localization = table.fromFile(MineOSCore.paths.localizationFiles .. MineOSCore.OSSettings.language .. ".lang") + fs.makeDirectory(MineOSCore.paths.trash) + + MineOSCore.OSSettings.extensionAssociations = MineOSCore.OSSettings.extensionAssociations or {} + MineOSCore.loadIcon("folder", MineOSCore.paths.icons .. "Folder.pic") + MineOSCore.loadIcon("fileNotExists", MineOSCore.paths.icons .. "FileNotExists.pic") + MineOSCore.loadIcon("application", MineOSCore.paths.icons .. "Application.pic") + MineOSCore.loadIcon("trash", MineOSCore.paths.icons .. "Trash.pic") + MineOSCore.loadIcon("script", MineOSCore.paths.icons .. "Script.pic") + + MineOSCore.associateExtension(".pic", MineOSCore.paths.applications .. "/Photoshop.app/Main.lua", MineOSCore.paths.icons .. "/Image.pic", MineOSCore.paths.extensionAssociations .. "Pic/Context menu.lua") + MineOSCore.associateExtension(".txt", MineOSCore.paths.editor, MineOSCore.paths.icons .. "/Text.pic") + MineOSCore.associateExtension(".cfg", MineOSCore.paths.editor, MineOSCore.paths.icons .. "/Config.pic") + MineOSCore.associateExtension(".3dm", MineOSCore.paths.applications .. "/3DPrint.app/Main.lua", MineOSCore.paths.icons .. "/3DModel.pic") + + MineOSCore.associateExtension("script", MineOSCore.paths.extensionAssociations .. "Lua/Launcher.lua", MineOSCore.paths.icons .. "/Script.pic", MineOSCore.paths.extensionAssociations .. "Lua/Context menu.lua") + MineOSCore.associateExtension(".lua", MineOSCore.paths.extensionAssociations .. "Lua/Launcher.lua", MineOSCore.paths.icons .. "/Lua.pic", MineOSCore.paths.extensionAssociations .. "Lua/Context menu.lua") + MineOSCore.associateExtension(".pkg", MineOSCore.paths.extensionAssociations .. "Pkg/Launcher.lua", MineOSCore.paths.icons .. "/Archive.pic") + + MineOSCore.saveOSSettings() end ----------------------------------------------------------------------------------------------------------------------------------- MineOSCore.init() +-- buffer.clear(0x0) +-- buffer.draw(true) + +-- local cykaContainer = GUI.fullScreenContainer() +-- cykaContainer:addChild(GUI.panel(1, 1, cykaContainer.width, cykaContainer.height, 0xFF0000)) + +-- GUICopy(cykaContainer, "/MineOS/papka/", "/MineOS/mamka/", true) + ----------------------------------------------------------------------------------------------------------------------------------- return MineOSCore diff --git a/lib/OpenComputersGL/Main.lua b/lib/OpenComputersGL/Main.lua old mode 100644 new mode 100755 index 1e7b1305..d4febea6 --- a/lib/OpenComputersGL/Main.lua +++ b/lib/OpenComputersGL/Main.lua @@ -49,21 +49,34 @@ OCGL.lines = {} OCGL.floatingTexts = {} OCGL.lights = {} +local sinTable, cosTable = {}, {} + +-------------------------------------------------------- Sin / Cos optimization -------------------------------------------------------- + +function OCGL.sin(angle) + sinTable[angle] = sinTable[angle] or math.sin(angle) + return sinTable[angle] +end + +function OCGL.cos(angle) + cosTable[angle] = cosTable[angle] or math.cos(angle) + return cosTable[angle] +end + -------------------------------------------------------- Vertex field methods -------------------------------------------------------- - function OCGL.rotateVectorRelativeToXAxis(vector, angle) - local sin, cos = math.sin(angle), math.cos(angle) + local sin, cos = OCGL.sin(angle), OCGL.cos(angle) vector[2], vector[3] = cos * vector[2] - sin * vector[3], sin * vector[2] + cos * vector[3] end function OCGL.rotateVectorRelativeToYAxis(vector, angle) - local sin, cos = math.sin(angle), math.cos(angle) + local sin, cos = OCGL.sin(angle), OCGL.cos(angle) vector[1], vector[3] = cos * vector[1] + sin * vector[3], cos * vector[3] - sin * vector[1] end function OCGL.rotateVectorRelativeToZAxis(vector, angle) - local sin, cos = math.sin(angle), math.cos(angle) + local sin, cos = OCGL.sin(angle), OCGL.cos(angle) vector[1], vector[2] = cos * vector[1] - sin * vector[2], sin * vector[1] + cos * vector[2] end diff --git a/lib/OpenComputersGL/Materials.lua b/lib/OpenComputersGL/Materials.lua old mode 100644 new mode 100755 diff --git a/lib/OpenComputersGL/Renderer.lua b/lib/OpenComputersGL/Renderer.lua old mode 100644 new mode 100755 diff --git a/lib/advancedLua.lua b/lib/advancedLua.lua index 4abbdfd4..736459c5 100755 --- a/lib/advancedLua.lua +++ b/lib/advancedLua.lua @@ -1,6 +1,6 @@ --[[ - + Advanced Lua Library v1.1 by ECS This library extends a lot of default Lua methods @@ -70,7 +70,7 @@ end -- Split nubmer to it's own bytes with specified count of bytes (0xAABB, 5 -> {0x00, 0x00, 0x00, 0xAA, 0xBB}) function bit32.numberToFixedSizeByteArray(number, size) local byteArray, counter = {}, 0 - + repeat table.insert(byteArray, 1, bit32.band(number, 0xFF)) number = bit32.rshift(number, 8) @@ -146,31 +146,26 @@ end ---------------------------------------------- Filesystem extensions ------------------------------------------------------------------------ --- function filesystem.path(path) --- return string.match(path, "^(.+%/).") or "" --- end +function filesystem.path(path) + return path:match("^(.+%/).") or "" +end --- function filesystem.name(path) --- return string.match(path, "%/?([^%/]+)%/?$") --- end - -local function getNameAndExtension(path) - local fileName, extension = string.match(path, "^(.+)(%.[^%/]+)%/?$") - return (fileName or path), extension +function filesystem.name(path) + return path:match("%/?([^%/]+)%/?$") end function filesystem.extension(path) - local fileName, extension = getNameAndExtension(path) - return extension + return path:match("[^%/]+(%.[^%/]+)%/?$") end function filesystem.hideExtension(path) - local fileName, extension = getNameAndExtension(path) - return fileName + return path:match("(.+)%..+") or path end function filesystem.isFileHidden(path) - if string.match(path, "^%..+$") then return true end + if path:match("^%..+$") then + return true + end return false end @@ -212,7 +207,7 @@ function filesystem.sortedList(path, sortingMethod, showHiddenFiles) currentExtensionList, currentExtension = {fileList[i][1]}, fileList[i][2] end end - + table.sort(currentExtensionList, function(a, b) return a < b end) for j = 1, #currentExtensionList do table.insert(sortedFileList, currentExtensionList[j]) @@ -256,7 +251,7 @@ function filesystem.directorySize(path) size = size + filesystem.size(path .. file) end end - + return size end @@ -265,7 +260,7 @@ end local function doSerialize(array, prettyLook, indentationSymbol, indentationSymbolAdder, equalsSymbol, currentRecusrionStack, recursionStackLimit) local text, keyType, valueType, stringValue = {"{"} table.insert(text, (prettyLook and "\n" or nil)) - + for key, value in pairs(array) do keyType, valueType, stringValue = type(key), type(value), tostring(value) @@ -275,7 +270,7 @@ local function doSerialize(array, prettyLook, indentationSymbol, indentationSymb table.insert(text, (keyType == "string" and table.concat({"\"", key, "\""}) or key)) table.insert(text, "]") table.insert(text, equalsSymbol) - + if valueType == "number" or valueType == "boolean" or valueType == "nil" then table.insert(text, stringValue) elseif valueType == "string" or valueType == "function" then @@ -290,7 +285,7 @@ local function doSerialize(array, prettyLook, indentationSymbol, indentationSymb table.insert(text, "...") end end - + table.insert(text, ",") table.insert(text, (prettyLook and "\n" or nil)) end @@ -421,7 +416,7 @@ end function table.indexOf(t, object) for i = 1, #t do - if t[i] == object then + if t[i] == object then return i end end @@ -464,7 +459,7 @@ function string.optimizeForURLRequests(code) end) code = string.gsub(code, " ", "+") end - return code + return code end function string.unicodeFind(str, pattern, init, plain) @@ -475,9 +470,9 @@ function string.unicodeFind(str, pattern, init, plain) init = #unicode.sub(str, 1, init - 1) + 1 end end - + a, b = string.find(str, pattern, init, plain) - + if a then local ap, bp = str:sub(1, a - 1), str:sub(a,b) a = unicode.len(ap) + 1 @@ -532,7 +527,7 @@ function string.wrap(strings, limit) strings[currentString + 1] = right .. " " .. strings[currentString + 1] else strings[currentString + 1] = right - end + end end break else @@ -583,3 +578,5 @@ end ------------------------------------------------------------------------------------------------------------------ return {loaded = true} + + diff --git a/lib/color.lua b/lib/color.lua index 384c2bba..5ca54c55 100755 --- a/lib/color.lua +++ b/lib/color.lua @@ -104,6 +104,25 @@ end ----------------------------------------------------------------------------------------------------------------------- +function color.difference(r1, g1, b1, r2, g2, b2) + return r2 - r1, g2 - g1, b2 - b1 +end + +function color.sum(r1, g1, b1, r2, g2, b2) + return r2 + r1, g2 + g1, b2 + b1 +end + +function color.multiply(r, g, b, multiplyer) + r, g, b = r * multiplyer, g * multiplyer, b * multiplyer + if r > 255 then r = 255 end + if g > 255 then g = 255 end + if b > 255 then b = 255 end + + return r, g, b +end + +----------------------------------------------------------------------------------------------------------------------- + local openComputersPalette = { 0x000000, 0x000040, 0x000080, 0x0000BF, 0x0000FF, 0x002400, 0x002440, 0x002480, 0x0024BF, 0x0024FF, 0x004900, 0x004940, 0x004980, 0x0049BF, 0x0049FF, 0x006D00, 0x006D40, 0x006D80, 0x006DBF, 0x006DFF, 0x009200, 0x009240, 0x009280, 0x0092BF, 0x0092FF, 0x00B600, 0x00B640, 0x00B680, 0x00B6BF, 0x00B6FF, 0x00DB00, 0x00DB40, 0x00DB80, 0x00DBBF, 0x00DBFF, 0x00FF00, 0x00FF40, 0x00FF80, 0x00FFBF, 0x00FFFF, 0x0F0F0F, 0x1E1E1E, 0x2D2D2D, 0x330000, 0x330040, 0x330080, 0x3300BF, 0x3300FF, 0x332400, 0x332440, 0x332480, 0x3324BF, 0x3324FF, 0x334900, 0x334940, 0x334980, 0x3349BF, 0x3349FF, 0x336D00, 0x336D40, 0x336D80, 0x336DBF, 0x336DFF, 0x339200, 0x339240, 0x339280, 0x3392BF, 0x3392FF, 0x33B600, 0x33B640, 0x33B680, 0x33B6BF, 0x33B6FF, 0x33DB00, 0x33DB40, 0x33DB80, 0x33DBBF, 0x33DBFF, 0x33FF00, 0x33FF40, 0x33FF80, 0x33FFBF, 0x33FFFF, 0x3C3C3C, 0x4B4B4B, 0x5A5A5A, 0x660000, 0x660040, 0x660080, 0x6600BF, 0x6600FF, 0x662400, 0x662440, 0x662480, 0x6624BF, 0x6624FF, 0x664900, 0x664940, 0x664980, 0x6649BF, 0x6649FF, 0x666D00, 0x666D40, 0x666D80, 0x666DBF, 0x666DFF, 0x669200, 0x669240, 0x669280, 0x6692BF, 0x6692FF, 0x66B600, 0x66B640, 0x66B680, 0x66B6BF, 0x66B6FF, 0x66DB00, 0x66DB40, 0x66DB80, 0x66DBBF, 0x66DBFF, 0x66FF00, 0x66FF40, 0x66FF80, 0x66FFBF, 0x66FFFF, 0x696969, 0x787878, 0x878787, 0x969696, 0x990000, 0x990040, 0x990080, 0x9900BF, 0x9900FF, 0x992400, 0x992440, 0x992480, 0x9924BF, 0x9924FF, 0x994900, 0x994940, 0x994980, 0x9949BF, 0x9949FF, 0x996D00, 0x996D40, 0x996D80, 0x996DBF, 0x996DFF, 0x999200, 0x999240, 0x999280, 0x9992BF, 0x9992FF, 0x99B600, 0x99B640, 0x99B680, 0x99B6BF, 0x99B6FF, 0x99DB00, 0x99DB40, 0x99DB80, 0x99DBBF, 0x99DBFF, 0x99FF00, 0x99FF40, 0x99FF80, 0x99FFBF, 0x99FFFF, 0xA5A5A5, 0xB4B4B4, 0xC3C3C3, 0xCC0000, 0xCC0040, 0xCC0080, 0xCC00BF, 0xCC00FF, 0xCC2400, 0xCC2440, 0xCC2480, 0xCC24BF, 0xCC24FF, 0xCC4900, 0xCC4940, 0xCC4980, 0xCC49BF, 0xCC49FF, 0xCC6D00, 0xCC6D40, 0xCC6D80, 0xCC6DBF, 0xCC6DFF, 0xCC9200, 0xCC9240, 0xCC9280, 0xCC92BF, 0xCC92FF, 0xCCB600, 0xCCB640, 0xCCB680, 0xCCB6BF, 0xCCB6FF, 0xCCDB00, 0xCCDB40, 0xCCDB80, 0xCCDBBF, 0xCCDBFF, 0xCCFF00, 0xCCFF40, 0xCCFF80, 0xCCFFBF, 0xCCFFFF, 0xD2D2D2, 0xE1E1E1, 0xF0F0F0, 0xFF0000, 0xFF0040, 0xFF0080, 0xFF00BF, 0xFF00FF, 0xFF2400, 0xFF2440, 0xFF2480, 0xFF24BF, 0xFF24FF, 0xFF4900, 0xFF4940, 0xFF4980, 0xFF49BF, 0xFF49FF, 0xFF6D00, 0xFF6D40, 0xFF6D80, 0xFF6DBF, 0xFF6DFF, 0xFF9200, 0xFF9240, 0xFF9280, 0xFF92BF, 0xFF92FF, 0xFFB600, 0xFFB640, 0xFFB680, 0xFFB6BF, 0xFFB6FF, 0xFFDB00, 0xFFDB40, 0xFFDB80, 0xFFDBBF, 0xFFDBFF, 0xFFFF00, 0xFFFF40, 0xFFFF80, 0xFFFFBF, 0xFFFFFF } function color.to8Bit(color24Bit) diff --git a/lib/doubleBuffering.lua b/lib/doubleBuffering.lua index 67467a2e..1a758a3c 100755 --- a/lib/doubleBuffering.lua +++ b/lib/doubleBuffering.lua @@ -236,27 +236,31 @@ function buffer.text(x, y, textColor, text, transparency) end -- Отрисовка изображения -function buffer.image(x, y, picture) +function buffer.image(x, y, picture, blendForeground) local xPos, xEnd, bufferIndexStepOnReachOfImageWidth = x, x + picture[1] - 1, (buffer.width - picture[1]) * 3 - local bufferIndex = buffer.getIndexByCoordinates(x, y) - local imageIndexPlus2, imageIndexPlus3 + local bufferIndex, bufferIndexPlus1 = buffer.getIndexByCoordinates(x, y) + local imageIndexPlus1, imageIndexPlus2, imageIndexPlus3 for imageIndex = 3, #picture, 4 do if xPos >= buffer.drawLimit.x1 and y >= buffer.drawLimit.y1 and xPos <= buffer.drawLimit.x2 and y <= buffer.drawLimit.y2 then - imageIndexPlus2, imageIndexPlus3 = imageIndex + 2, imageIndex + 3 + bufferIndexPlus1, imageIndexPlus1, imageIndexPlus2, imageIndexPlus3 = bufferIndex + 1, imageIndex + 1, imageIndex + 2, imageIndex + 3 if picture[imageIndexPlus2] == 0x00 then buffer.newFrame[bufferIndex] = picture[imageIndex] buffer.newFrame[bufferIndex + 1] = picture[imageIndex + 1] - buffer.newFrame[bufferIndex + 2] = picture[imageIndexPlus3] elseif picture[imageIndexPlus2] > 0x00 and picture[imageIndexPlus2] < 0xFF then buffer.newFrame[bufferIndex] = color.blend(buffer.newFrame[bufferIndex], picture[imageIndex], picture[imageIndexPlus2]) - buffer.newFrame[bufferIndex + 1] = picture[imageIndex + 1] - buffer.newFrame[bufferIndex + 2] = picture[imageIndexPlus3] + + if blendForeground then + buffer.newFrame[bufferIndex + 1] = color.blend(buffer.newFrame[bufferIndexPlus1], picture[imageIndexPlus1], picture[imageIndexPlus2]) + else + buffer.newFrame[bufferIndex + 1] = picture[imageIndex + 1] + end elseif picture[imageIndexPlus2] == 0xFF and picture[imageIndexPlus3] ~= " " then buffer.newFrame[bufferIndex + 1] = picture[imageIndex + 1] - buffer.newFrame[bufferIndex + 2] = picture[imageIndexPlus3] end + + buffer.newFrame[bufferIndex + 2] = picture[imageIndexPlus3] end xPos, bufferIndex = xPos + 1, bufferIndex + 3 diff --git a/lib/event.lua b/lib/event.lua index e3293c2c..5ae10b90 100755 --- a/lib/event.lua +++ b/lib/event.lua @@ -7,6 +7,13 @@ local computer = require("computer") local event = { + lastTouch = { + x = 0, + y = 0, + button = 0, + uptime = 0 + }, + doubleTouchInterval = 0.3, push = computer.pushSignal, handlers = {}, interruptingEnabled = true, @@ -166,8 +173,7 @@ local function eventTick(timeout) shouldInterrupt = false end end - - -- Checking interruption delays + if shouldInterrupt and uptime - lastInterrupt > event.interruptingDelay then lastInterrupt = uptime error("interrupted", 0) @@ -188,6 +194,10 @@ local function getNearestHandlerTriggerTime() return nearestTriggerTime end +function event.skip(signalType) + event.skipSignalType = signalType +end + function event.pull(...) local args = {...} @@ -202,11 +212,29 @@ function event.pull(...) while computer.uptime() <= deadline do local eventData = eventTick((getNearestHandlerTriggerTime() or deadline) - computer.uptime()) if eventData[1] and (not signalType or signalType == eventData[1]) then - return table.unpack(eventData) + if eventData[1] == event.skipSignalType then + event.skipSignalType = nil + else + return table.unpack(eventData) + end end end end ------------------------------------------------------------------------------- +event.listen("touch", function(...) + local eventData = {...} + local uptime = computer.uptime() + + if event.lastTouch.x == eventData[3] and event.lastTouch.y == eventData[4] and event.lastTouch.button == eventData[5] and uptime - event.lastTouch.uptime <= event.doubleTouchInterval then + event.skip("touch") + computer.pushSignal("double_touch", table.unpack(eventData, 2)) + end + + event.lastTouch.x, event.lastTouch.y, event.lastTouch.button, event.lastTouch.uptime = eventData[3], eventData[4], eventData[5], uptime +end) + +------------------------------------------------------------------------------- + return event diff --git a/lib/serialization.lua b/lib/serialization.lua index 2e5bf933..5dc54de4 100755 --- a/lib/serialization.lua +++ b/lib/serialization.lua @@ -9,7 +9,7 @@ function serialization.serialize(variable, ...) if variableType == "table" then return table.serialize(variable, ...) else - return tostring(variableType) + return tostring(variable) end end