From 61de202def6036a13d94aeecd3222f239a368b82 Mon Sep 17 00:00:00 2001 From: Igor Timofeev Date: Sun, 28 Aug 2016 17:58:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B8=D0=BD=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=20=D0=BC=D0=B0=D1=81=D1=88=D1=82=D0=B0=D0=B1=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=B0=D0=BF=D0=B4=D0=B5=D0=B9=D1=82=20=D0=9E=D0=A1?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Applications.txt | 59 +- Applications/AppMarket/AppMarket.lua | 26 +- Applications/Finder/Finder.lua | 33 +- Applications/Graph/Graph.lua | 8 +- Applications/HoloClock/HoloClock.lua | 689 ++++------- Applications/HoloClock/Icon.pic | Bin 160 -> 185 bytes Applications/Palette/Icon.pic | Bin 262 -> 319 bytes Applications/Palette/Palette.lua | 2 +- .../Photoshop/Localization/English.lang | 8 + .../Photoshop/Localization/Russian.lang | 8 + Applications/Photoshop/Photoshop.lua | 470 ++++---- Applications/RayWalk/About/English.txt | 2 +- Applications/RayWalk/About/Russian.txt | 2 +- .../RayWalk/Localization/English.lang | 26 + .../RayWalk/Localization/Russian.lang | 25 + Applications/RayWalk/RayEngine.cfg | 49 +- Applications/RayWalk/RayWalk.lua | 154 ++- .../Weapons/CrosshairTextures/Angled.pic | Bin .../Weapons/CrosshairTextures/Default.pic | Bin .../Weapons/CrosshairTextures/Dotted.pic | Bin .../Weapons/CrosshairTextures/Half.pic | Bin .../RayWalk/Weapons/FireTextures/Plasma.pic | Bin .../Weapons/FireTextures/PowderFire.pic | Bin .../RayWalk/Weapons/WeaponTextures/Pistol.pic | Bin .../Weapons/WeaponTextures/Plasmer.pic | Bin .../RayWalk/Weapons/WeaponTextures/Rifle.pic | Bin .../RayWalk/Weapons/WeaponTextures/Sniper.pic | Bin Applications/RayWalk/Weapons/Weapons.cfg | 0 .../RayWalk/Worlds/ExampleWorld/Blocks.cfg | 0 .../RayWalk/Worlds/ExampleWorld/Map.cfg | 0 .../RayWalk/Worlds/ExampleWorld/Player.cfg | 0 .../RayWalk/Worlds/ExampleWorld/World.cfg | 0 .../RayWalk/Worlds/SundownBeams/Blocks.cfg | 0 .../RayWalk/Worlds/SundownBeams/Map.cfg | 0 .../RayWalk/Worlds/SundownBeams/Player.cfg | 0 .../RayWalk/Worlds/SundownBeams/World.cfg | 0 Applications/Stargate/Stargate.lua | 18 +- Installer/Installer.lua | 12 +- MineOS/Icons/Application.pic | Bin 0 -> 156 bytes MineOS/Languages/English.lang | 4 + MineOS/Languages/Russian.lang | 6 +- lib/ECSAPI.lua | 5 +- lib/GUI.lua | 1019 ++++++++++++++--- lib/MineOSCore.lua | 292 ++--- lib/advancedLua.lua | 76 +- lib/colorlib.lua | 22 +- lib/doubleBuffering.lua | 281 +++-- lib/doubleHeight.lua | 110 +- lib/image.lua | 37 +- lib/palette.lua | 566 ++++----- lib/rayEngine.lua | 216 ++-- lib/serialization.lua | 149 +-- lib/syntax.lua | 18 +- lib/windows.lua | 209 ++++ 54 files changed, 2639 insertions(+), 1962 deletions(-) mode change 100644 => 100755 Applications/AppMarket/AppMarket.lua mode change 100644 => 100755 Applications/Finder/Finder.lua mode change 100644 => 100755 Applications/Graph/Graph.lua mode change 100644 => 100755 Applications/HoloClock/HoloClock.lua mode change 100644 => 100755 Applications/HoloClock/Icon.pic mode change 100644 => 100755 Applications/Palette/Icon.pic mode change 100644 => 100755 Applications/Palette/Palette.lua mode change 100644 => 100755 Applications/Photoshop/Localization/English.lang mode change 100644 => 100755 Applications/Photoshop/Localization/Russian.lang mode change 100644 => 100755 Applications/Photoshop/Photoshop.lua mode change 100644 => 100755 Applications/RayWalk/About/Russian.txt create mode 100755 Applications/RayWalk/Localization/English.lang create mode 100755 Applications/RayWalk/Localization/Russian.lang mode change 100644 => 100755 Applications/RayWalk/RayEngine.cfg mode change 100644 => 100755 Applications/RayWalk/RayWalk.lua mode change 100644 => 100755 Applications/RayWalk/Weapons/CrosshairTextures/Angled.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/CrosshairTextures/Default.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/CrosshairTextures/Dotted.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/CrosshairTextures/Half.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/FireTextures/Plasma.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/FireTextures/PowderFire.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/WeaponTextures/Pistol.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/WeaponTextures/Plasmer.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/WeaponTextures/Rifle.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/WeaponTextures/Sniper.pic mode change 100644 => 100755 Applications/RayWalk/Weapons/Weapons.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/ExampleWorld/Blocks.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/ExampleWorld/Map.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/ExampleWorld/Player.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/ExampleWorld/World.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/SundownBeams/Blocks.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/SundownBeams/Map.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/SundownBeams/Player.cfg mode change 100644 => 100755 Applications/RayWalk/Worlds/SundownBeams/World.cfg mode change 100644 => 100755 Applications/Stargate/Stargate.lua create mode 100755 MineOS/Icons/Application.pic mode change 100644 => 100755 MineOS/Languages/English.lang mode change 100644 => 100755 MineOS/Languages/Russian.lang mode change 100644 => 100755 lib/ECSAPI.lua mode change 100644 => 100755 lib/GUI.lua mode change 100644 => 100755 lib/MineOSCore.lua mode change 100644 => 100755 lib/advancedLua.lua mode change 100644 => 100755 lib/colorlib.lua mode change 100644 => 100755 lib/doubleBuffering.lua mode change 100644 => 100755 lib/doubleHeight.lua mode change 100644 => 100755 lib/image.lua mode change 100644 => 100755 lib/palette.lua mode change 100644 => 100755 lib/rayEngine.lua mode change 100644 => 100755 lib/serialization.lua mode change 100644 => 100755 lib/syntax.lua create mode 100755 lib/windows.lua diff --git a/Applications.txt b/Applications.txt index 10a461cb..ea88ffea 100644 --- a/Applications.txt +++ b/Applications.txt @@ -8,7 +8,7 @@ about="IgorTimofeev/OpenComputers/master/MineOS/About/", type="Script", forceDownload=true, - version=3.24, + version=3.27, }, { name="MineOS/Pictures/Raspberry.pic", @@ -99,17 +99,24 @@ url="IgorTimofeev/OpenComputers/master/MineOS/Languages/Russian.lang", type="Script", forceDownload=true, - version=1.12, + version=1.13, }, { name="MineOS/System/OS/Languages/English.lang", url="IgorTimofeev/OpenComputers/master/MineOS/Languages/English.lang", type="Script", forceDownload=true, - version=1.12, + version=1.13, }, ----------------------------------------------------- Системные иконки -------------------------------------------------------------------------- + { + name="MineOS/System/OS/Icons/Application.pic", + url="IgorTimofeev/OpenComputers/master/MineOS/Icons/Application.pic", + type="Icon", + preLoadFile=true, + version=1.0, + }, { name="MineOS/System/OS/Icons/Languages.pic", url="IgorTimofeev/OpenComputers/master/MineOS/Icons/Languages.pic", @@ -271,14 +278,14 @@ name="lib/MineOSCore.lua", url="IgorTimofeev/OpenComputers/master/lib/MineOSCore.lua", type="Library", - version=1.19, + version=1.20, }, { name="lib/advancedLua.lua", url="IgorTimofeev/OpenComputers/master/lib/advancedLua.lua", type="Library", preLoadFile=true, - version=1.01, + version=1.02, }, { name="lib/ECSAPI.lua", @@ -292,14 +299,14 @@ url="IgorTimofeev/OpenComputers/master/lib/colorlib.lua", type="Library", preLoadFile=true, - version=1.02, + version=1.03, }, { name="lib/image.lua", url="IgorTimofeev/OpenComputers/master/lib/image.lua", type="Library", preLoadFile=true, - version=1.22, + version=1.23, }, { name="lib/files.lua", @@ -312,25 +319,31 @@ name="lib/GUI.lua", url="IgorTimofeev/OpenComputers/master/lib/GUI.lua", type="Library", - version=1.13, + version=1.14, + }, + { + name="lib/windows.lua", + url="IgorTimofeev/OpenComputers/master/lib/windows.lua", + type="Library", + version=1.00, }, { name="lib/serialization.lua", url="IgorTimofeev/OpenComputers/master/lib/serialization.lua", type="Library", - version=1.0, + version=1.01, }, { name="lib/rayEngine.lua", url="IgorTimofeev/OpenComputers/master/lib/rayEngine.lua", type="Library", - version=1.33, + version=1.34, }, { name="lib/doubleHeight.lua", url="IgorTimofeev/OpenComputers/master/lib/doubleHeight.lua", type="Library", - version=1.01, + version=1.02, }, { name="lib/json.lua", @@ -396,19 +409,19 @@ name="lib/syntax.lua", url="IgorTimofeev/OpenComputers/master/lib/syntax.lua", type="Library", - version=1.01, + version=1.02, }, { name="lib/palette.lua", url="IgorTimofeev/OpenComputers/master/lib/palette.lua", type="Library", - version=1.0, + version=1.01, }, { name="lib/doubleBuffering.lua", url="IgorTimofeev/OpenComputers/master/lib/doubleBuffering.lua", type="Library", - version=1.12, + version=1.13, }, { name="lib/thread.lua", @@ -598,7 +611,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/RayWalk/Icon.pic", createShortcut="desktop", - version=1.50, + version=1.51, resources={ { name="RayEngine.cfg", @@ -703,7 +716,7 @@ about="IgorTimofeev/OpenComputers/master/Applications/Calendar/About/", type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/Calendar/Icon.pic", - createShortcut="dock", + createShortcut="desktop", version=1.0, }, { @@ -712,7 +725,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/Palette/Icon.pic", createShortcut="desktop", - version=1.0, + version=1.01, }, { name="MineOS/Applications/Stargate", @@ -720,7 +733,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/Stargate/Icon.pic", createShortcut="desktop", - version=1.0, + version=1.01, resources={ { name="Gate.pic", @@ -764,7 +777,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/Graph/Icon.pic", createShortcut="desktop", - version=1.0, + version=1.01, }, { name="MineOS/Applications/FlappyBlock", @@ -853,7 +866,7 @@ icon="IgorTimofeev/OpenComputers/master/Applications/Photoshop/Icon.pic", createShortcut="dock", forceDownload=true, - version=1.01, + version=1.02, resources={ { name="Localization/Russian.lang", @@ -887,7 +900,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/HoloClock/Icon.pic", createShortcut="desktop", - version=1.0, + version=1.01, }, { name="MineOS/Applications/Pastebin", @@ -905,7 +918,7 @@ icon="IgorTimofeev/OpenComputers/master/Applications/Finder/Icon.pic", createShortcut="dock", forceDownload=true, - version=1.11, + version=1.12, }, { name="MineOS/Applications/AppMarket", @@ -915,7 +928,7 @@ icon="IgorTimofeev/OpenComputers/master/Applications/AppMarket/Icon.pic", createShortcut="dock", forceDownload=true, - version=1.45, + version=1.46, resources={ { name="Localization/Russian.lang", diff --git a/Applications/AppMarket/AppMarket.lua b/Applications/AppMarket/AppMarket.lua old mode 100644 new mode 100755 index 5a5f7579..f79f334f --- a/Applications/AppMarket/AppMarket.lua +++ b/Applications/AppMarket/AppMarket.lua @@ -79,12 +79,14 @@ local function calculateSizes() sizes.downloadButtonWidth = 17 sizes.descriptionTruncateSize = sizes.width - 6 - MineOSCore.iconWidth - sizes.downloadButtonWidth sizes.searchFieldWidth = math.floor(sizes.width * 0.3) - obj.searchTextField = GUI.textField(math.floor(sizes.x + sizes.width / 2 - sizes.searchFieldWidth / 2), 1, sizes.searchFieldWidth, 1, 0xEEEEEE, 0x777777, 0xEEEEEE, 0x555555, nil, localization.search, false, true) + obj.searchTextField = GUI.inputTextBox(math.floor(sizes.x + sizes.width / 2 - sizes.searchFieldWidth / 2), 1, sizes.searchFieldWidth, 1, 0xEEEEEE, 0x555555, 0xEEEEEE, 0x262626, nil, localization.search, false, true) end local function drawTopBar() - obj.topBarButtons = GUI.toolbar(sizes.x, sizes.y, sizes.width, sizes.topBarHeight, 2, currentTopBarElement, colors.topBar, colors.topBarText, colors.topBarElement, colors.topBarElementText, table.unpack(topBarElements)) - obj.windowActionButtons = GUI.windowActionButtons(sizes.x + 1, sizes.y) + obj.topBarButtons = GUI.tabBar(sizes.x, sizes.y, sizes.width, sizes.topBarHeight, 2, colors.topBar, colors.topBarText, colors.topBarElement, colors.topBarElementText, table.unpack(topBarElements)) + obj.topBarButtons.selectedTab = currentTopBarElement + obj.topBarButtons:draw() + obj.windowActionButtons = GUI.windowActionButtons(sizes.x + 1, sizes.y):draw() end local function getIcon(url) @@ -161,7 +163,7 @@ local function drawApplication(x, y, i, doNotDrawButton) currentApps[i].buttonObject.x, currentApps[i].buttonObject.y = xButton, yButton currentApps[i].buttonObject:draw() else - currentApps[i].buttonObject = GUI.button(xButton, yButton, sizes.downloadButtonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x555555, 0xFFFFFF, text) + currentApps[i].buttonObject = GUI.button(xButton, yButton, sizes.downloadButtonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x555555, 0xFFFFFF, text):draw() end end @@ -180,11 +182,11 @@ local function drawPageSwitchButtons(y) local buttonWidth = 5 local width = buttonWidth * 2 + textLength + 2 local x = math.floor(sizes.x + sizes.width / 2 - width / 2) - obj.prevPageButton = GUI.button(x, y, buttonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x262626, 0xFFFFFF, "<") + obj.prevPageButton = GUI.button(x, y, buttonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x262626, 0xFFFFFF, "<"):draw() x = x + obj.prevPageButton.width + 1 buffer.text(x, y, colors.version, text) x = x + textLength + 1 - obj.nextPageButton = GUI.button(x, y, buttonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x262626, 0xFFFFFF, ">") + obj.nextPageButton = GUI.button(x, y, buttonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x262626, 0xFFFFFF, ">"):draw() end local function clearMainZone() @@ -253,7 +255,7 @@ local function updates() if #changes > 0 then buffer.setDrawLimit(sizes.x, obj.main.y, sizes.width, obj.main.height) local x, y = sizes.x + 2, fromY - obj.updateAllButton = GUI.button(math.floor(sizes.x + sizes.width / 2 - sizes.downloadButtonWidth / 2), y, 20, 1, colors.downloadButton, colors.downloadButtonText, 0x555555, 0xFFFFFF, "Обновить все") + obj.updateAllButton = GUI.button(math.floor(sizes.x + sizes.width / 2 - sizes.downloadButtonWidth / 2), y, 20, 1, colors.downloadButton, colors.downloadButtonText, 0x555555, 0xFFFFFF, "Обновить все"):draw() y = y + 2 for i = from, (from + limit) do @@ -367,7 +369,7 @@ while true do if currentTopBarElement < 5 then for appIndex, app in pairs(currentApps) do if app.buttonObject:isClicked(e[3], e[4]) then - app.buttonObject:press(0.3) + app.buttonObject:pressAndRelease(0.3) if app.buttonObject.text == localization.update or app.buttonObject.text == localization.download then app.buttonObject.text = localization.downloading app.buttonObject.disabled = true @@ -385,7 +387,7 @@ while true do end else if obj.updateAllButton and obj.updateAllButton:isClicked(e[3], e[4]) then - obj.updateAllButton:press() + obj.updateAllButton:pressAndRelease() updateAll() flush() drawAll() @@ -394,7 +396,7 @@ while true do if obj.nextPageButton then if obj.nextPageButton:isClicked(e[3], e[4]) then - obj.nextPageButton:press() + obj.nextPageButton:pressAndRelease() fromY = obj.main.y + 1 from = from + limit currentApps = {} @@ -412,11 +414,11 @@ while true do if obj.windowActionButtons.close:isClicked(e[3], e[4]) then - obj.windowActionButtons.close:press() + obj.windowActionButtons.close:pressAndRelease() return end - for key, button in pairs(obj.topBarButtons) do + for key, button in pairs(obj.topBarButtons.tabs.children) do if button:isClicked(e[3], e[4]) then currentTopBarElement = key flush() diff --git a/Applications/Finder/Finder.lua b/Applications/Finder/Finder.lua old mode 100644 new mode 100755 index 72dc5e5a..5ea0816f --- a/Applications/Finder/Finder.lua +++ b/Applications/Finder/Finder.lua @@ -12,7 +12,6 @@ local libraries = { event = "event", fs = "filesystem", files = "files", - context = "context", unicode = "unicode", archive = "archive", serialization = "serialization", @@ -149,7 +148,7 @@ end --Рисем цветные кружочки слева вверху local function drawCloses() - obj.windowActionButtons = GUI.windowActionButtons(sizes.xFinder + 1, sizes.yFinder) + obj.windowActionButtons = GUI.windowActionButtons(sizes.xFinder + 1, sizes.yFinder):draw() end local function drawSearchBar(justDrawNotEvent) @@ -164,11 +163,11 @@ local function drawTopBar() buffer.square(sizes.xFinder, sizes.yFinder, sizes.finderWidth, sizes.topBarHeight, _G.OSSettings.interfaceColor or colors.topBar) drawCloses() local x, y = sizes.xFinder + 2, sizes.yFinder + 1 - obj.historyBack = GUI.button(x, y, 3, 1, 0xffffff, 0x262626, 0xAAAAAA, 0x000000, "<"); x = x + obj.historyBack.width + 1 - obj.historyBack.colors.disabled.button, obj.historyBack.colors.disabled.text = 0xFFFFFF, 0xdddddd + obj.historyBack = GUI.button(x, y, 3, 1, 0xffffff, 0x262626, 0xAAAAAA, 0x000000, "<"):draw(); x = x + obj.historyBack.width + 1 + obj.historyBack.colors.disabled.background, obj.historyBack.colors.disabled.text = 0xFFFFFF, 0xdddddd if currentWorkPathHistoryElement == 1 then obj.historyBack.disabled = true; obj.historyBack:draw() end - obj.historyForward = GUI.button(x, y, 3, 1, 0xffffff, 0x262626, 0xAAAAAA, 0x000000, ">"); x = x + obj.historyForward.width + 2 - obj.historyForward.colors.disabled.button, obj.historyForward.colors.disabled.text = 0xFFFFFF, 0xdddddd + obj.historyForward = GUI.button(x, y, 3, 1, 0xffffff, 0x262626, 0xAAAAAA, 0x000000, ">"):draw(); x = x + obj.historyForward.width + 2 + obj.historyForward.colors.disabled.background, obj.historyForward.colors.disabled.text = 0xFFFFFF, 0xdddddd if currentWorkPathHistoryElement == #workPathHistory then obj.historyForward.disabled = true; obj.historyForward:draw() end local cyka = { @@ -177,8 +176,8 @@ local function drawTopBar() {objName = "showHidden", text = MineOSCore.localization.showHiddenFilesShort, active = config.showHiddenFiles}, } for i = 1, #cyka do - obj[cyka[i].objName] = GUI.adaptiveButton(x, y, 1, 0, 0xFFFFFF, 0x262626, 0x262626, 0xFFFFFF, cyka[i].text) - if cyka[i].active then obj[cyka[i].objName]:draw(true) end + obj[cyka[i].objName] = GUI.adaptiveButton(x, y, 1, 0, 0xFFFFFF, 0x262626, 0x262626, 0xFFFFFF, cyka[i].text):draw() + if cyka[i].active then obj[cyka[i].objName]:press() end x = x + obj[cyka[i].objName].width + 1 end @@ -189,7 +188,7 @@ local function drawAndHiglightPath(y, arrayElement) -- GUI.error(workPathHistory[currentWorkPathHistoryElement] .. " - " .. tostring(arrayElement.path)) local pathAreEquals = workPathHistory[currentWorkPathHistoryElement] == arrayElement.path if pathAreEquals then buffer.square(sizes.xFinder, y, sizes.leftBarWidth, 1, colors.leftBarSelection, colors.leftBarSelectionText, " ") end - buffer.text(sizes.xFinder + 2, y, pathAreEquals and colors.leftBarSelectionText or colors.leftBarList, unicode.sub(arrayElement.name, 1, sizes.leftBarWidth - 4)) + buffer.text(sizes.xFinder + 2, y, pathAreEquals and colors.leftBarSelectionText or colors.leftBarList, unicode.sub(arrayElement.name, 1, sizes.leftBarWidth - 3)) local object = GUI.object(sizes.xFinder, y, sizes.leftBarWidth, 1) object.path = arrayElement.path table.insert(obj.leftBarItems, object) @@ -244,8 +243,8 @@ local function drawNetwork() local text = ecs.stringLimit("end", currentNetworkAddress, sizes.mainWidth - 4) buffer.text(math.floor(sizes.xMain + sizes.mainWidth / 2 - unicode.len(text) / 2), y, 0xAAAAAA, text); y = y + 2 x = math.floor(sizes.xMain + sizes.mainWidth / 2 - buttonWidth / 2) - obj.networkFile = GUI.button(x, y, buttonWidth, 1, 0xdddddd, 0x262626, 0x262626, 0xEEEEEE, MineOSCore.localization.sendFile); y = y + 2 - obj.networkMessage = GUI.button(x, y, buttonWidth, 1, 0xdddddd, 0x262626, 0x262626, 0xEEEEEE, MineOSCore.localization.sendMessage); y = y + 2 + obj.networkFile = GUI.button(x, y, buttonWidth, 1, 0xdddddd, 0x262626, 0x262626, 0xEEEEEE, MineOSCore.localization.sendFile):draw(); y = y + 2 + obj.networkMessage = GUI.button(x, y, buttonWidth, 1, 0xdddddd, 0x262626, 0x262626, 0xEEEEEE, MineOSCore.localization.sendMessage):draw(); y = y + 2 end local function drawFiles() @@ -382,12 +381,12 @@ while true do if clickedAtEmptyArea and obj.topBarZone:isClicked(eventData[3], eventData[4]) then if obj.historyBack:isClicked(eventData[3], eventData[4]) then - obj.historyBack:press(0.2) + obj.historyBack:pressAndRelease(0.2) currentWorkPathHistoryElement = currentWorkPathHistoryElement - 1 sizes.yFileList = sizes.yFileListStartPoint getListAndDrawAll() elseif obj.historyForward:isClicked(eventData[3], eventData[4]) then - obj.historyForward:press(0.2) + obj.historyForward:pressAndRelease(0.2) currentWorkPathHistoryElement = currentWorkPathHistoryElement + 1 sizes.yFileList = sizes.yFileListStartPoint getListAndDrawAll() @@ -398,7 +397,7 @@ while true do sizes.yFileList = sizes.yFileListStartPoint getListAndDrawAll() elseif obj.windowActionButtons.close:isClicked(eventData[3], eventData[4]) then - obj.windowActionButtons.close:press(0.2) + obj.windowActionButtons.close:pressAndRelease(0.2) return elseif obj.showFormat:isClicked(eventData[3], eventData[4]) then config.showFileFormat = not config.showFileFormat @@ -409,7 +408,7 @@ while true do saveConfig() getListAndDrawAll() elseif obj.sortingMethod:isClicked(eventData[3], eventData[4]) then - obj.sortingMethod:press(0.2) + obj.sortingMethod:pressAndRelease(0.2) local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, {"EmptyLine"}, {"CenterText", ecs.colors.orange, MineOSCore.localization.sortingMethod}, @@ -430,14 +429,14 @@ while true do if clickedAtEmptyArea then if obj.networkMessage and obj.networkMessage:isClicked(eventData[3], eventData[4]) then - obj.networkMessage:press(0.2) + obj.networkMessage:pressAndRelease(0.2) local data = sendMessageOrFileWindow(MineOSCore.localization.sendMessage, MineOSCore.localization.messageText) if data[2] == "OK" then component.modem.send(currentNetworkAddress, port, "hereIsMessage", data[1]) end clickedAtEmptyArea = false elseif obj.networkFile and obj.networkFile:isClicked(eventData[3], eventData[4]) then - obj.networkFile:press(0.2) + obj.networkFile:pressAndRelease(0.2) local data = sendMessageOrFileWindow(MineOSCore.localization.sendFile, MineOSCore.localization.pathToFile) if data[2] == "OK" then if fs.exists(data[1]) then diff --git a/Applications/Graph/Graph.lua b/Applications/Graph/Graph.lua old mode 100644 new mode 100755 index 54f15545..7973024c --- a/Applications/Graph/Graph.lua +++ b/Applications/Graph/Graph.lua @@ -44,11 +44,11 @@ local function drawButtons() end local function drawHorizontalLine(x, y, x2, color) - for i = x, x2 do doubleHeight.set(i, y, color) end + for i = x, x2 do buffer.semiPixelSet(i, y, color) end end local function drawVerticalLine(x, y, y2, color) - for i = y, y2 do doubleHeight.set(x, i, color) end + for i = y, y2 do buffer.semiPixelSet(x, i, color) end end local function drawAxis() @@ -86,7 +86,7 @@ end local function drawGraph() for i = 1, #keyPoints do doubleHeight.line(xGraph + keyPoints[i].x, yGraph - keyPoints[i].y, xGraph + keyPoints[i].x2, yGraph - keyPoints[i].y2, graphColor) - if showCornerPoints then doubleHeight.set(xGraph + keyPoints[i].x, yGraph - keyPoints[i].y, 0x00A8FF) end + if showCornerPoints then buffer.semiPixelSet(xGraph + keyPoints[i].x, yGraph - keyPoints[i].y, 0x00A8FF) end end end @@ -108,7 +108,7 @@ local function drawSelectedPoint(x, y, pointNumber) if xOnScreen <= xGraph then drawHorizontalLine(xOnScreen, yOnScreen, xGraph - 1, selectionPointLineColor) else drawHorizontalLine(xGraph + 1, yOnScreen, xOnScreen, selectionPointLineColor) end if yOnScreen <= yGraph then drawVerticalLine(xOnScreen, yOnScreen, yGraph - 1, selectionPointLineColor) else drawVerticalLine(xOnScreen, yGraph + 1, yOnScreen, selectionPointLineColor) end - doubleHeight.set(xOnScreen, yOnScreen, selectionPointColor) + buffer.semiPixelSet(xOnScreen, yOnScreen, selectionPointColor) yOnScreen = math.ceil(yOnScreen / 2) diff --git a/Applications/HoloClock/HoloClock.lua b/Applications/HoloClock/HoloClock.lua old mode 100644 new mode 100755 index 923a6870..63e27cdb --- a/Applications/HoloClock/HoloClock.lua +++ b/Applications/HoloClock/HoloClock.lua @@ -1,466 +1,247 @@ -local c = require("component") + +require("advancedLua") +local fs = require("filesystem") +local component = require("component") local unicode = require("unicode") -local term = require("term") -local holo -local gpu = c.gpu +local event = require("event") +local buffer = require("doubleBuffering") +local MineOSCore = require("MineOSCore") ---Проверка на наличие нужных устройств -if not c.isAvailable("hologram") then - ecs.error("Подключите голографический проектор 2-ого уровня") +-------------------------------------------------------------------------------------------- + +if not component.isAvailable("hologram") then + GUI.error("This program needs a Tier 2 holo-projector!", {title = {color = 0xFFDB40, text = "HoloClock"}}) return -else - holo = c.hologram end -local hologram = {} - ---------------------------------------- - -local symbols = { - A = { - {0, 0, 1, 0, 0}, - {0, 1, 0, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - }, - B = { - {1, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 0}, - }, - C = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - D = { - {1, 1, 1, 1, 0}, - {0, 1, 0, 0, 1}, - {0, 1, 0, 0, 1}, - {0, 1, 0, 0, 1}, - {0, 1, 0, 0, 1}, - {0, 1, 0, 0, 1}, - {1, 1, 1, 1, 0}, - }, - E = { - {1, 1, 1, 1, 1}, - {1, 0, 0, 0, 0}, - {1, 1, 1, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - }, - F = { - {1, 1, 1, 1, 1}, - {1, 0, 0, 0, 0}, - {1, 1, 1, 1, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - }, - G = { - {0, 1, 1, 1, 1}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 1, 1, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - H = { - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - }, - I = { - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 1, 1, 1, 0}, - }, - J = { - {0, 0, 0, 0, 01}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - {0, 1, 0, 0, 1}, - {0, 0, 1, 1, 0}, - }, - K = { - {1, 0, 0, 1, 1}, - {1, 0, 1, 0, 0}, - {1, 0, 1, 0, 0}, - {1, 1, 0, 0, 0}, - {1, 0, 1, 0, 0}, - {1, 0, 0, 1, 0}, - {1, 0, 0, 0, 1}, - }, - L = { - {0, 1, 0, 0, 0}, - {0, 1, 0, 0, 0}, - {0, 1, 0, 0, 0}, - {0, 1, 0, 0, 0}, - {0, 1, 0, 0, 0}, - {0, 1, 0, 0, 0}, - {0, 1, 1, 1, 0}, - }, - M = { - {1, 0, 0, 0, 1}, - {1, 1, 0, 1, 1}, - {1, 0, 1, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - }, - N = { - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 0, 0, 1}, - {1, 0, 1, 0, 1}, - {1, 0, 0, 1, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - }, - O = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - P = { - {1, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - }, - Q = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 1, 0, 1}, - {1, 0, 0, 1, 1}, - {0, 1, 1, 1, 0}, - }, - R = { - {1, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 0, 0}, - {1, 0, 0, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - }, - S = { - {0, 1, 1, 1, 1}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {0, 1, 1, 1, 0}, - {0, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - T = { - {1, 1, 1, 1, 1}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - }, - U = { - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - V = { - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 0, 1, 0}, - {0, 0, 1, 0, 0}, - }, - W = { - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 1, 0, 1}, - {1, 1, 0, 1, 1}, - {1, 0, 0, 0, 1}, - }, - X = { - {1, 0, 0, 0, 1}, - {0, 1, 0, 1, 0}, - {0, 1, 0, 1, 0}, - {0, 0, 1, 0, 0}, - {0, 1, 0, 1, 0}, - {0, 1, 0, 1, 0}, - {1, 0, 0, 0, 1}, - }, - Y = { - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 0, 1, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - }, - Z = { - {1, 1, 1, 1, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 1, 0}, - {0, 0, 1, 0, 0}, - {0, 1, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - }, - ["."] = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - }, - [","] = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0}, - {1, 0, 0, 0, 0}, - }, - ["!"] = { - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - }, - [":"] = { - {0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 0, 0, 0}, - }, - ["-"] = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 1, 1, 1, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - }, - ["_"] = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - }, - ["1"] = { - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 1, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 1, 1, 1, 0}, - }, - ["2"] = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - }, - ["3"] = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 1, 1, 0}, - {0, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - ["4"] = { - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - }, - ["5"] = { - {1, 1, 1, 1, 1}, - {1, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 1, 1, 1, 0}, - {0, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - ["6"] = { - {0, 0, 1, 1, 1}, - {0, 1, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {1, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - ["7"] = { - {1, 1, 1, 1, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 1, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - }, - ["8"] = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - ["9"] = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 1, 0}, - {1, 1, 1, 0, 0}, - }, - ["0"] = { - {0, 1, 1, 1, 0}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 0, 0, 1}, - {0, 1, 1, 1, 0}, - }, - [" "] = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - }, - empty = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - }, -} - -local function clear() - holo.clear() -end - -function hologram.drawSymbol(x, y, z, symbol, color) - for j = 1, #symbol do - for i = 1, #symbol[j] do - if symbol[j][i] == 1 then - holo.set(x + i - 1, y - j + 1, z, color) - end - end - end -end - -function hologram.text(x, y, z, text, color) - local length = unicode.len(text) - local smeshenie = 0 - for i = 1, length do - local sym = unicode.sub(text, i, i) - hologram.drawSymbol(x + smeshenie, y, z, symbols[sym], color) - smeshenie = smeshenie + 6 - end -end - - ---------------------------------------- - -local args = {...} -local scale = tonumber(args[1]) or 2 -local height = tonumber(args[2]) or 15 +-------------------------------------------------------------------------------------------- local date +local path = MineOSCore.paths.system .. "/HoloClock/Settings.cfg" +local config = { + dateColor = 0xFFFFFF, + holoScale = 1 +} -holo.setScale(scale) +-------------------------------------------------------------------------------------------- -while true do - holo.clear() - date = string.sub(os.date("%T"), 1, -4) - hologram.text(10, height, 24, date, 2) - - term.clear() - gpu.set(2, 2, "Текущее время: " .. date) - - os.sleep(1) +local symbols = { + ["0"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["1"] = { + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + }, + ["2"] = { + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + }, + ["3"] = { + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["4"] = { + { 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + }, + ["5"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["6"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["7"] = { + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0 }, + }, + ["8"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + ["9"] = { + { 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1 }, + { 0, 1, 1, 1, 0 }, + }, + [":"] = { + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + }, +} + +-------------------------------------------------------------------------------------------- + +local function save() + table.toFile(path, config) end ---------------------------------------- +local function load() + if fs.exists(path) then + config = table.fromFile(path) + else + save() + end +end + +-------------------------------------------------------------------------------------------- + +local function drawSymbolOnScreen(x, y, symbol, color) + local xPos = x + for j = 1, #symbols[symbol] do + for i = 1, #symbols[symbol][j] do + if symbols[symbol][j][i] == 1 then + buffer.square(xPos, y, 2, 1, color, 0x000000, " ") + end + xPos = xPos + 2 + end + xPos = x + y = y + 1 + end +end + + +local function drawSymbolOnProjector(x, y, z, symbol) + local xPos = x + for j = 1, #symbols[symbol] do + for i = 1, #symbols[symbol][j] do + if symbols[symbol][j][i] == 1 then + component.hologram.set(xPos, y, z, 1) + else + component.hologram.set(xPos, y, z, 0) + end + xPos = xPos + 1 + end + xPos = x + y = y - 1 + end +end + +local function drawText(x, y, text, color) + for i = 1, unicode.len(text) do + local symbol = unicode.sub(text, i, i) + drawSymbolOnScreen(x, y, symbol, color) + drawSymbolOnProjector(i * 6 + 4, 16, 24, symbol) + x = x + 12 + end +end + +local function changeHoloColor() + component.hologram.setPaletteColor(1, config.dateColor) +end + +local function getDate() + date = string.sub(os.date("%T"), 1, -4) +end + +local function flashback() + buffer.square(1, 1, buffer.screen.width, buffer.screen.height, 0x000000, 0x000000, " ", 50) +end + +local function drawOnScreen() + local width, height = 58, 7 + local x, y = math.floor(buffer.screen.width / 2 - width / 2), math.floor(buffer.screen.height / 2 - height / 2) + + drawText(x, y, "88:88", 0x000000) + drawText(x, y, date, config.dateColor) + + y = y + 9 + GUI.label(1, y, buffer.screen.width, 1, config.dateColor, "Press R to randomize clock color, scroll to change projection scale,"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top):draw(); y = y + 1 + GUI.label(1, y, buffer.screen.width, 1, config.dateColor, "or press Enter to save and quit"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top):draw() + -- GUI.label(1, y, buffer.screen.width, 1, 0xFFFFFF, ""):draw() + + buffer.draw() +end + +-------------------------------------------------------------------------------------------- + +load() +component.hologram.clear() +changeHoloColor() +component.hologram.setScale(config.holoScale) +flashback() + +while true do + getDate() + drawOnScreen() + + local e = {event.pull(1)} + if e[1] == "scroll" then + if e[5] == 1 then + if config.holoScale < 4 then config.holoScale = config.holoScale + 0.1; component.hologram.setScale(config.holoScale); save() end + else + if config.holoScale > 0.33 then config.holoScale = config.holoScale - 0.1; component.hologram.setScale(config.holoScale); save() end + end + elseif e[1] == "key_down" then + if e[4] == 19 then + config.dateColor = math.random(0x666666, 0xFFFFFF) + changeHoloColor() + save() + elseif e[4] == 28 then + save() + component.hologram.clear() + return + end + end +end + + + -return hologram diff --git a/Applications/HoloClock/Icon.pic b/Applications/HoloClock/Icon.pic old mode 100644 new mode 100755 index 1ad1b671a9212a38c74db7b19877e650f8207b25..3d1903e144f8c936bec7156f988afae9ee0bc514 GIT binary patch literal 185 zcmYMuF$w}f3$L)OqciJfAYB9o4PKr zEpTpFD}fSR0>_3=CEn!;vA}aA=m`f-qcH`pLmIdYN#M{xm4wm(7M+TDGP7k7?DPdp bf$#g(cG32l$T+y#Ne!Ujl{SYXIh>EHhxKP+YQb0p_Euc}#hq+nPp?jxWy za4`J3godSyVwgWg<5&@nz|t~6(IKYXNU+l9qzf=a81vl+KLmJRTpc(b`_3`oXAXZjcy?+Fl6`EUb9|UIEr_}3vgIQWJ_42M@ zmS}K2za5wbGmYW)|FqoyAT#Xk?d9d=K`c{idns8kOUuk&R2s~ZH?rrK1hYi-?776j WEG|uZRuM1@W?Guc|NkluATt2AR+32o literal 262 zcmYMvF%H5o3A091qK$5(Ic=>0TMUhBz#COawvy>5{VVcN_Q1<9_)Ed9*CP diff --git a/Applications/Palette/Palette.lua b/Applications/Palette/Palette.lua old mode 100644 new mode 100755 index b5a5dc1e..ddf9e2a0 --- a/Applications/Palette/Palette.lua +++ b/Applications/Palette/Palette.lua @@ -1 +1 @@ -require("palette").draw("auto", "auto", 0x6600FF) \ No newline at end of file +loadfile("lib/palette.lua")().show("auto", "auto", 0x00DBFF) \ No newline at end of file diff --git a/Applications/Photoshop/Localization/English.lang b/Applications/Photoshop/Localization/English.lang old mode 100644 new mode 100755 index 7016e3e0..e7edc1ca --- a/Applications/Photoshop/Localization/English.lang +++ b/Applications/Photoshop/Localization/English.lang @@ -6,6 +6,13 @@ w = "W", h = "H", + view = "View", + transparencyPad = "Transparency pad", + transparencyColor = "Transparency color", + transparencyGrid = "Transparency grid", + + path = "Path", + string = "String", file = "File", image = "Image", edit = "Edit", @@ -18,6 +25,7 @@ new = "New", open = "Open", + createFromString = "Create from OCIFString", save = "Save", saveAs = "Save as", exit = "Exit", diff --git a/Applications/Photoshop/Localization/Russian.lang b/Applications/Photoshop/Localization/Russian.lang old mode 100644 new mode 100755 index 91edde23..64937958 --- a/Applications/Photoshop/Localization/Russian.lang +++ b/Applications/Photoshop/Localization/Russian.lang @@ -6,6 +6,13 @@ w = "Ш", h = "В", + view = "Вид", + transparencyPad = "Подложка прозрачности", + transparencyColor = "Цвет прозрачности", + transparencyGrid = "Сетка прозрачности", + + path = "Путь", + string = "Строка", file = "Файл", image = "Изображение", edit = "Редактировать", @@ -18,6 +25,7 @@ new = "Новый", open = "Открыть", + createFromString = "Создать из OCIFString", save = "Сохранить", saveAs = "Сохранить как", exit = "Выход", diff --git a/Applications/Photoshop/Photoshop.lua b/Applications/Photoshop/Photoshop.lua old mode 100644 new mode 100755 index e898c5d9..89fbeae3 --- a/Applications/Photoshop/Photoshop.lua +++ b/Applications/Photoshop/Photoshop.lua @@ -1,24 +1,33 @@ ------------------------------------------------ Информешйн, епта -------------------------------------------------------------- +local photoshopVersion = "Photoshop v6.5" + local copyright = [[ - Photoshop v6.3 для OpenComputers + Photoshop v6.5 для OpenComputers Автор: ECS Контактый адрес: https://vk.com/id7799889 Соавтор: Pornogion Контактый адрес: https://vk.com/id88323331 + Что нового в версии 6.5: + - Палитра заменена на более быструю и стильную, работающую на тройном буфере + - Добавлена возможность загрузки изображения из строки, созданной методом сохранения OCIFString + + Что нового в версии 6.4: + - Добавлена возможность выбора цвета сетки прозрачности во вкладке "Вид" + Что нового в версии 6.3: - Добавлена поддержка языковых пакетов Что нового в версии 6.2: - - Добавлен суб-инструмент localization.polygon + - Добавлен суб-инструмент "Полигон" - Улучшен инструмент "Выделение", теперь можно выделять области с шириной или высотой, равными 1 Что нового в версии 6.1: - - Добавлен суб-инструмент localization.ellipse + - Добавлен суб-инструмент "Эллипс" Что нового в версии 6.0: - Добавлен иструмент "Фигура", включающий в себя линию, прямоугольник и рамку @@ -33,7 +42,7 @@ local copyright = [[ Что нового в версии 5.0: - Добавлен инструмент "выделение" и несколько функций для работы с ним - - Добавлено меню localization.hotkeys, подсказывающее, как можно удобнее работать с программой + - Добавлено меню "Горячие клавиши", подсказывающее, как можно удобнее работать с программой Что нового в версии 4.0: - Программа переведена на библиотеку тройного буфера, скорость работы увеличена в десятки раз @@ -48,9 +57,9 @@ copyright = nil local libraries = { ecs = "ECSAPI", + MineOSCore = "MineOSCore", fs = "filesystem", unicode = "unicode", - context = "context", image = "image", component = "component", keyboard = "keyboard", @@ -68,7 +77,7 @@ for library in pairs(libraries) do if not _G[library] then _G[library] = require buffer.start() --Массив локалиации -local localization = files.loadTableFromFile("/MineOS/Applications/Photoshop.app/Resources/Localization/" .. _G.OSSettings.language .. ".lang") +local localization = MineOSCore.getCurrentApplicationLocalization() --Массив инфы о выделении local selection @@ -104,10 +113,9 @@ local colors = { local sizes = { widthOfLeftBar = 6, } -sizes.heightOfTopBar = 3 sizes.xStartOfDrawingArea = sizes.widthOfLeftBar + 1 sizes.xEndOfDrawingArea = buffer.screen.width -sizes.yStartOfDrawingArea = sizes.heightOfTopBar + 2 +sizes.yStartOfDrawingArea = 2 sizes.yEndOfDrawingArea = buffer.screen.height - 1 sizes.widthOfDrawingArea = sizes.xEndOfDrawingArea - sizes.xStartOfDrawingArea + 1 sizes.heightOfDrawingArea = sizes.yEndOfDrawingArea - sizes.yStartOfDrawingArea + 1 @@ -133,7 +141,7 @@ local instruments = { "S", } sizes.heightOfInstrument = 3 -sizes.yStartOfInstruments = sizes.heightOfTopBar + 2 +sizes.yStartOfInstruments = 2 local currentInstrument = 2 local currentBackground = 0x000000 local currentForeground = 0xFFFFFF @@ -143,9 +151,7 @@ local currentBrushSize = 1 local savePath local currentShape local currentPolygonCountOfEdges - ---Верхний тулбар -local topToolbar = {{"PS", ecs.colors.blue}, {localization.file}, {localization.image}, {localization.edit}, {localization.hotkeys}, {localization.about}} +local showTransparencyGrid = true ------------------------------------------------ Функции отрисовки -------------------------------------------------------------- @@ -174,26 +180,30 @@ end --Отрисовка "прозрачной зоны", этакая сеточка чередующаяся local function drawTransparentZone(x, y) - y = y - 1 + if showTransparencyGrid then + y = y - 1 - local stro4ka1 = "" - local stro4ka2 = "" - if masterPixels.width % 2 == 0 then - stro4ka1 = string.rep("▒ ", masterPixels.width / 2) - stro4ka2 = stro4ka1 - else - stro4ka1 = string.rep("▒ ", masterPixels.width / 2) - stro4ka2 = stro4ka1 .. "▒" - end - - for i = 1, masterPixels.height do - if i % 2 == 0 then - buffer.square(x, y + i, masterPixels.width, 1, colors.transparencyWhite, colors.transparencyGray, " ") - buffer.text(x + 1, y + i, colors.transparencyGray, stro4ka1) + local stro4ka1 = "" + local stro4ka2 = "" + if masterPixels.width % 2 == 0 then + stro4ka1 = string.rep("▒ ", masterPixels.width / 2) + stro4ka2 = stro4ka1 else - buffer.square(x, y + i, masterPixels.width, 1, colors.transparencyWhite, colors.transparencyGray) - buffer.text(x, y + i, colors.transparencyGray, stro4ka2) + stro4ka1 = string.rep("▒ ", masterPixels.width / 2) + stro4ka2 = stro4ka1 .. "▒" end + + for i = 1, masterPixels.height do + if i % 2 == 0 then + buffer.square(x, y + i, masterPixels.width, 1, colors.transparencyWhite, colors.transparencyGray, " ") + buffer.text(x + 1, y + i, colors.transparencyGray, stro4ka1) + else + buffer.square(x, y + i, masterPixels.width, 1, colors.transparencyWhite, colors.transparencyGray) + buffer.text(x, y + i, colors.transparencyGray, stro4ka2) + end + end + else + buffer.square(x, y, masterPixels.width, masterPixels.height, colors.transparencyWhite, 0x000000, " ") end end @@ -240,39 +250,7 @@ end --Отрисовка верхнего меню local function drawTopMenu() - buffer.square(1, 1, buffer.screen.width, 1, colors.topMenu, 0xFFFFFF, " ") - local xPos = 3 - - for i = 1, #topToolbar do - buffer.text(xPos, 1, topToolbar[i][2] or colors.topMenuText, topToolbar[i][1]) - if i > 1 then - newObj("TopMenu", topToolbar[i][1], xPos, 1, xPos + unicode.len(topToolbar[i][1]) - 1, 1) - end - xPos = xPos + unicode.len(topToolbar[i][1]) + 2 - end -end - ---Отрисовка верхней панели инструментов, пока что она не шибко-то полезна -local function drawTopBar() - local topBarInputs = { {localization.brushSize, currentBrushSize}, {localization.transparency, math.floor(currentAlpha)}} - - buffer.square(1, 2, buffer.screen.width, sizes.heightOfTopBar, colors.topToolbar, 0xFFFFFF, " ") - local xPos, yPos = 3, 3 - local limit = 8 - - for i = 1, #topBarInputs do - buffer.text(xPos, yPos, 0xeeeeee, topBarInputs[i][1]) - - xPos = xPos + unicode.len(topBarInputs[i][1]) + 1 - ecs.inputText(xPos, yPos, limit, tostring(topBarInputs[i][2]), 0xffffff, 0x262626, true) - - newObj("TopBarInputs", i, xPos, yPos, xPos + limit - 1, yPos, limit) - - if i == 2 then xPos = xPos + 3 end - - xPos = xPos + limit + 2 - end - + obj.menu = GUI.menu(1, 1, buffer.screen.width, colors.topMenu, colors.topMenuText, 0x3366CC, 0xFFFFFF, 0, {"PS", ecs.colors.blue}, {localization.file}, {localization.image}, {localization.edit}, {localization.view}, {localization.hotkeys}, {localization.about}):draw() end --Функция, создающая пустой массив изображения на основе указанных ранее длины и ширины @@ -653,7 +631,6 @@ end local function drawAll() drawBackground() drawLeftBar() - drawTopBar() drawTopMenu() drawBackgroundAndImage() @@ -820,7 +797,7 @@ end --Функция, спрашивающая юзверя, какого размера пикчу он хочет создать - ну, и создает ее local function new() selection = nil - local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.newDocument}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.width}, {"Input", 0x262626, 0x880000, localization.height}, {"EmptyLine"}, {"Button", {0xbbbbbb, 0xffffff, "OK"}}) + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.newDocument}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.width}, {"Input", 0x262626, 0x880000, localization.height}, {"EmptyLine"}, {"Button", {0x999999, 0xffffff, "OK"}}) data[1] = tonumber(data[1]) or 51 data[2] = tonumber(data[2]) or 19 @@ -885,7 +862,7 @@ local function brush(x, y, background, foreground, alpha, symbol) --А если прозрачный, то смешиваем прозрачности --Пиздануться вообще, сук else - --Если его прозоачность максимальная + --Если его прозрачность максимальная if masterPixels[newIterator + 2] == 0xFF then setPixel(newIterator, background, foreground, alpha, symbol) --Если не максимальная @@ -1070,8 +1047,9 @@ while true do --Если нажата клавиша альт if keyboard.isKeyDown(56) then - local _, _, gettedBackground = component.gpu.get(e[3], e[4]) + local _, gettedForeground, gettedBackground = component.gpu.get(e[3], e[4]) currentBackground = gettedBackground + currentForeground = gettedForeground drawColors() buffer.draw() @@ -1112,13 +1090,11 @@ while true do for key in pairs(obj["Colors"]) do if ecs.clickedAtArea(e[3], e[4], obj["Colors"][key][1], obj["Colors"][key][2], obj["Colors"][key][3], obj["Colors"][key][4]) then if key == 1 then - currentBackground = palette.draw("auto", "auto", currentBackground) or currentBackground - drawColors() - buffer.draw() + currentBackground = palette.show("auto", "auto", currentBackground) or currentBackground + drawAll() elseif key == 2 or key == 3 then - currentForeground = palette.draw("auto", "auto", currentForeground) or currentForeground - drawColors() - buffer.draw() + currentForeground = palette.show("auto", "auto", currentForeground) or currentForeground + drawAll() elseif key == 4 then buffer.text(obj["Colors"][key][1], obj["Colors"][key][2], 0xFF0000, "←→") os.sleep(0.2) @@ -1136,7 +1112,7 @@ while true do currentInstrument = key drawLeftBar(); buffer.draw() if instruments[currentInstrument] == "S" then - local action = context.menu(obj["Instruments"][key][3] + 1, obj["Instruments"][key][2], {localization.line}, {localization.ellipse}, {localization.rectangle}, {localization.polygon}, {localization.border}) + 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 if currentShape == localization.polygon then @@ -1157,192 +1133,203 @@ while true do end --Верхний меню-бар - for key in pairs(obj["TopMenu"]) do - if ecs.clickedAtArea(e[3], e[4], obj["TopMenu"][key][1], obj["TopMenu"][key][2], obj["TopMenu"][key][3], obj["TopMenu"][key][4]) then - buffer.square(obj["TopMenu"][key][1] - 1, obj["TopMenu"][key][2], unicode.len(key) + 2, 1, ecs.colors.blue, 0xFFFFFF, " ") - buffer.text(obj["TopMenu"][key][1], obj["TopMenu"][key][2], 0xffffff, key) - buffer.draw() + local object = obj.menu:getClickedObject(e[3], e[4]) + if object then + object:press() + 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() + 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() + elseif object.text == localization.edit then + action = GUI.contextMenu(object.x, object.y + 1, {localization.hueSaturation}, {localization.colorBalance}, {localization.photoFilter}, "-", {localization.invertColors}, {localization.blackWhite}, "-", {localization.gaussianBlur}):show() + elseif object.text == localization.view then + action = GUI.contextMenu(object.x, object.y + 1, {localization.transparencyPad}):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 + ecs.universalWindow( "auto", "auto", 42, 0xeeeeee, true, + table.unpack(localization.hotkeysLines) + ) + end - local action - - if key == localization.file then - action = context.menu(obj["TopMenu"][key][1] - 1, obj["TopMenu"][key][2] + 1, {localization.new}, {localization.open}, "-", {localization.save, (savePath == nil)}, {localization.saveAs}, "-", {localization.exit}) - elseif key == localization.image then - action = context.menu(obj["TopMenu"][key][1] - 1, obj["TopMenu"][key][2] + 1, {localization.crop}, {localization.expand}, "-", {localization.rotateBy90}, {localization.rotateBy180}, "-", {localization.flipHorizontal}, {localization.flipVertical}) - elseif key == localization.edit then - action = context.menu(obj["TopMenu"][key][1] - 1, obj["TopMenu"][key][2] + 1, {localization.hueSaturation}, {localization.colorBalance}, {localization.photoFilter}, "-", {localization.invertColors}, {localization.blackWhite}, "-", {localization.gaussianBlur}) - elseif key == localization.about then - ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, "Photoshop v6.3"}, {"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 key == localization.hotkeys then - - ecs.universalWindow( "auto", "auto", 42, 0xeeeeee, true, - table.unpack(localization.hotkeysLines) - ) + if action == localization.exit then + ecs.prepareToExit() + return + elseif action == localization.hueSaturation then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.hueSaturation}, + {"EmptyLine"}, + {"Slider", 0x262626, 0x880000, 0, 100, 50, localization.hue .. ": ", ""}, + {"Slider", 0x262626, ecs.colors.red, 0, 100, 50, localization.saturation .. ": ", ""}, + {"Slider", 0x262626, 0x000000, 0, 100, 50, localization.brightness .. ": ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[4] == "OK" then + masterPixels = image.hueSaturationBrightness(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50) + drawAll() end - - if action == localization.exit then - ecs.prepareToExit() - return - elseif action == localization.hueSaturation then - local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, - {"EmptyLine"}, - {"CenterText", 0x262626, localization.hueSaturation}, - {"EmptyLine"}, - {"Slider", 0x262626, 0x880000, 0, 100, 50, localization.hue .. ": ", ""}, - {"Slider", 0x262626, ecs.colors.red, 0, 100, 50, localization.saturation .. ": ", ""}, - {"Slider", 0x262626, 0x000000, 0, 100, 50, localization.brightness .. ": ", ""}, - {"EmptyLine"}, - {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} - ) - if data[4] == "OK" then - masterPixels = image.hueSaturationBrightness(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50) - drawAll() - end - elseif action == localization.gaussianBlur then - local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, - {"EmptyLine"}, - {"CenterText", 0x262626, localization.gaussianBlur}, - {"EmptyLine"}, - {"Slider", 0x262626, 0x880000, 1, 5, 2, localization.radius .. ": ", ""}, - {"Slider", 0x262626, 0x880000, 1, 255, 0x88, localization.force .. ": ", ""}, - {"EmptyLine"}, - {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} - ) - if data[3] == "OK" then - masterPixels = image.gaussianBlur(masterPixels, tonumber(data[1]), tonumber(data[2])) - drawAll() - end - elseif action == localization.colorBalance then - local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, - {"EmptyLine"}, - {"CenterText", 0x262626, localization.colorBalance}, - {"EmptyLine"}, - {"Slider", 0x262626, 0x880000, 0, 100, 50, "R: ", ""}, - {"Slider", 0x262626, ecs.colors.green, 0, 100, 50, "G: ", ""}, - {"Slider", 0x262626, ecs.colors.blue, 0, 100, 50, "B: ", ""}, - {"EmptyLine"}, - {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} - ) - if data[4] == "OK" then - masterPixels = image.colorBalance(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50) - drawAll() - end - elseif action == localization.photoFilter then - local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, - {"EmptyLine"}, - {"CenterText", 0x262626, localization.photoFilter}, - {"EmptyLine"}, - {"Color", localization.filterColor, 0x333333}, - {"Slider", 0x262626, 0x880000, 0, 255, 100, localization.transparency .. ": ", ""}, - {"EmptyLine"}, - {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} - ) - if data[3] == "OK" then - masterPixels = image.photoFilter(masterPixels, data[1], data[2]) - drawAll() - end - elseif action == localization.crop then - crop() - elseif action == localization.expand then - expand() - elseif action == localization.flipVertical then - masterPixels = image.flipVertical(masterPixels) + elseif action == localization.gaussianBlur then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.gaussianBlur}, + {"EmptyLine"}, + {"Slider", 0x262626, 0x880000, 1, 5, 2, localization.radius .. ": ", ""}, + {"Slider", 0x262626, 0x880000, 1, 255, 0x88, localization.force .. ": ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[3] == "OK" then + masterPixels = image.gaussianBlur(masterPixels, tonumber(data[1]), tonumber(data[2])) drawAll() - elseif action == localization.flipHorizontal then - masterPixels = image.flipHorizontal(masterPixels) + end + elseif action == localization.colorBalance then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.colorBalance}, + {"EmptyLine"}, + {"Slider", 0x262626, 0x880000, 0, 100, 50, "R: ", ""}, + {"Slider", 0x262626, ecs.colors.green, 0, 100, 50, "G: ", ""}, + {"Slider", 0x262626, ecs.colors.blue, 0, 100, 50, "B: ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[4] == "OK" then + masterPixels = image.colorBalance(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50) drawAll() - elseif action == localization.invertColors then - masterPixels = image.invert(masterPixels) + end + elseif action == localization.photoFilter then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.photoFilter}, + {"EmptyLine"}, + {"Color", localization.filterColor, 0x333333}, + {"Slider", 0x262626, 0x880000, 0, 255, 100, localization.transparency .. ": ", ""}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[3] == "OK" then + masterPixels = image.photoFilter(masterPixels, data[1], data[2]) drawAll() - elseif action == localization.blackWhite then - masterPixels = image.blackAndWhite(masterPixels) - drawAll() - elseif action == localization.rotateBy90 then - masterPixels = image.rotate(masterPixels, 90) - drawAll() - elseif action == localization.rotateBy180 then - masterPixels = image.rotate(masterPixels, 180) - drawAll() - elseif action == localization.new then - new() - drawAll() - elseif action == localization.saveAs then - local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.saveAs}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, "Путь"}, {"Selector", 0x262626, 0x880000, "OCIF4", "OCIF1", "OCIFString", "RAW"}, {"CenterText", 0x262626, "Рекомендуется использовать"}, {"CenterText", 0x262626, "метод кодирования OCIF4"}, {"EmptyLine"}, {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}) - if data[3] == "OK" then - data[1] = data[1] or "Untitled" - data[2] = data[2] or "OCIF4" - - if data[2] == "RAW" then - data[2] = 0 - elseif data[2] == "OCIF1" then - data[2] = 1 - elseif data[2] == "OCIF4" then - data[2] = 4 - elseif data[2] == "OCIFString" then - data[2] = 6 - else - data[2] = 4 - end - - local filename = data[1] .. ".pic" - local encodingMethod = data[2] - - image.save(filename, masterPixels, encodingMethod) - savePath = filename - end - elseif action == localization.save then - image.save(savePath, masterPixels) - - elseif action == localization.open then - local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.open}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, "Путь"}, {"EmptyLine"}, {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}) - if data[2] == "OK" then - local fileFormat = ecs.getFileFormat(data[1]) + end + elseif action == localization.crop then + crop() + elseif action == localization.expand then + expand() + elseif action == localization.flipVertical then + masterPixels = image.flipVertical(masterPixels) + drawAll() + elseif action == localization.flipHorizontal then + masterPixels = image.flipHorizontal(masterPixels) + drawAll() + elseif action == localization.invertColors then + masterPixels = image.invert(masterPixels) + drawAll() + elseif action == localization.blackWhite then + masterPixels = image.blackAndWhite(masterPixels) + drawAll() + elseif action == localization.rotateBy90 then + masterPixels = image.rotate(masterPixels, 90) + drawAll() + elseif action == localization.rotateBy180 then + masterPixels = image.rotate(masterPixels, 180) + drawAll() + elseif action == localization.new then + new() + drawAll() + elseif action == localization.saveAs then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.saveAs}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.path}, {"Selector", 0x262626, 0x880000, "OCIF4", "OCIF1", "OCIFString", "RAW"}, {"CenterText", 0x262626, "Рекомендуется использовать"}, {"CenterText", 0x262626, "метод кодирования OCIF4"}, {"EmptyLine"}, {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}) + if data[3] == "OK" then + data[1] = data[1] or "Untitled" + data[2] = data[2] or "OCIF4" - if not data[1] then - ecs.error("Некорректное имя файла!") - elseif not fs.exists(data[1]) then - ecs.error("Файл\""..data[1].."\" не существует!") - elseif fileFormat ~= ".pic" and fileFormat ~= ".rawpic" and fileFormat ~= ".png" then - ecs.error("Формат файла \""..fileFormat.."\" не поддерживается!") - else - loadImageFromFile(data[1]) - drawAll() - end + if data[2] == "RAW" then + data[2] = 0 + elseif data[2] == "OCIF1" then + data[2] = 1 + elseif data[2] == "OCIF4" then + data[2] = 4 + elseif data[2] == "OCIFString" then + data[2] = 6 + else + data[2] = 4 + end + + local filename = string.gsub(data[1], ".pic$", "") .. ".pic" + local encodingMethod = data[2] + + image.save(filename, masterPixels, encodingMethod) + savePath = filename + end + elseif action == localization.save then + image.save(savePath, masterPixels) + + elseif action == localization.open then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.open}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.path}, {"EmptyLine"}, {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}) + if data[2] == "OK" then + local fileFormat = ecs.getFileFormat(data[1]) + + if not data[1] then + ecs.error("Некорректное имя файла!") + elseif not fs.exists(data[1]) then + ecs.error("Файл\""..data[1].."\" не существует!") + elseif fileFormat ~= ".pic" and fileFormat ~= ".rawpic" and fileFormat ~= ".png" then + ecs.error("Формат файла \""..fileFormat.."\" не поддерживается!") + else + loadImageFromFile(data[1]) + drawAll() end end - - drawTopMenu() - buffer.draw() - break - end - end - - --Топбар - for key in pairs(obj["TopBarInputs"]) do - if ecs.clickedAtArea(e[3], e[4], obj["TopBarInputs"][key][1], obj["TopBarInputs"][key][2], obj["TopBarInputs"][key][3], obj["TopBarInputs"][key][4]) then - local input = ecs.inputText(obj["TopBarInputs"][key][1], obj["TopBarInputs"][key][2], obj["TopBarInputs"][key][5], "", 0xffffff, 0x262626) - input = tonumber(input) - - if input then - if key == 1 then - if input > 0 and input < 10 then currentBrushSize = input end - elseif key == 2 then - if input > 0 and input <= 255 then currentAlpha = input end + elseif action == localization.createFromString then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.createFromString}, + {"EmptyLine"}, + {"Input", 0x262626, 0x880000, localization.string}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) + if data[2] == "OK" then + local success, picture = pcall(image.fromString, data[1]) + if success then + masterPixels, selection, savePath = picture, nil, nil + tryToFitImageOnCenterOfScreen() + drawAll() + else + error("Невозможно создать изображение из этой строки!") end end + elseif action == localization.transparencyPad then + local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, + {"EmptyLine"}, + {"CenterText", 0x262626, localization.transparencyPad}, + {"EmptyLine"}, + {"Color", localization.transparencyColor .. " 1", colors.transparencyWhite}, + {"Color", localization.transparencyColor .. " 2", colors.transparencyGray}, + {"EmptyLine"}, + {"Switch", 0xF2B233, 0xffffff, 0x262626, localization.transparencyGrid, showTransparencyGrid}, + {"EmptyLine"}, + {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}} + ) - drawTopBar() - buffer.draw() - - break + if data[4] == "OK" then + colors.transparencyWhite, colors.transparencyGray, showTransparencyGrid = data[1], data[2], data[3] + drawAll() + end end + + drawTopMenu() + buffer.draw() end else --Если кликнули на рисовабельную зонку 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 = context.menu(e[3], e[4], {localization.deselect}, {localization.crop, true}, "-", {localization.fill}, {localization.border}, "-", {localization.clear}) + local action = GUI.contextMenu(e[3], e[4], {localization.deselect}, {localization.crop, true}, "-", {localization.fill}, {localization.border}, "-", {localization.clear}):show() if action == localization.deselect then selection = nil drawAll() @@ -1361,7 +1348,6 @@ while true do if x + width + 1 >= buffer.screen.width then x = buffer.screen.width - width - 1 end currentBrushSize, currentAlpha = table.unpack(ecs.universalWindow(x, y, width, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, localization.brushParameters}, {"Slider", 0x262626, 0x880000, 1, 10, currentBrushSize, localization.size .. ": ", " px"}, {"Slider", 0x262626, 0x880000, 0, 255, currentAlpha, localization.transparency .. ": ", ""}, {"EmptyLine"}, {"Button", {0xbbbbbb, 0xffffff, "OK"}})) - drawTopBar() buffer.draw() end end diff --git a/Applications/RayWalk/About/English.txt b/Applications/RayWalk/About/English.txt index a11a0d7c..e3af170e 100644 --- a/Applications/RayWalk/About/English.txt +++ b/Applications/RayWalk/About/English.txt @@ -1 +1 @@ -This application demonstrates the power of our double buffering library and the power of RayEngine engine that renders graphics like a DOOM and Wolfenstein. \ No newline at end of file +This application demonstrates the power of our tribleBuffering library, power of RayEngine and OOP-based windows library that allows us to render graphics like in a DOOM and Wolfenstein. \ No newline at end of file diff --git a/Applications/RayWalk/About/Russian.txt b/Applications/RayWalk/About/Russian.txt old mode 100644 new mode 100755 index 829e4e49..afa9796e --- a/Applications/RayWalk/About/Russian.txt +++ b/Applications/RayWalk/About/Russian.txt @@ -1 +1 @@ -Это приложение - вершина графических возможностей OpenComputers! Оно демонстрирует всю мощь нашей библиотеки двойной буферизации и игрового движка RayEngine, ползволяющего рендерить графику на уровне Wolfenstein и DOOM. \ No newline at end of file +Это приложение - вершина графических возможностей OpenComputers! Оно демонстрирует всю мощь нашей библиотеки тройной буферизации, игрового движка RayEngine, а также объектно-ориентированной оконной библиотеки windows, которые в совокупности позволяют рендерить графику на уровне Wolfenstein и DOOM. \ No newline at end of file diff --git a/Applications/RayWalk/Localization/English.lang b/Applications/RayWalk/Localization/English.lang new file mode 100755 index 00000000..91a3697c --- /dev/null +++ b/Applications/RayWalk/Localization/English.lang @@ -0,0 +1,26 @@ +{ + continue = "Continue", + settings = "Settings", + exit = "Exit", + loadWorld = "Load world", + controls = "Controls:", + controlsHelp = { + "WASD for movement, QE - rotation", + "Space - jump, Ctrl - crouch", + "K - compass, P - watch, M - map, F1 - debug info", + "12345 - weapon selection, the first one allows to", + "place and destroy blocks", + "Mouse - shooting/world interaction", + "Enter - command line, Backspace - menu", + }, + rayEngineProperties = "RayEngine™ properties", + screenResolution = "Screen resolution", + drawDistance = "Draw distance: ", + shadingDistance = "Shading distance: ", + shadingCascades = "Shading cascades: ", + raycastQuality = "Raycast quality: ", + dayNightCycle = "World time: ", + enableSemipixelRenderer = "Semipixel renderer: ", + enableDayNightCycle = "Day/night cycle: ", + seconds = " sec", +} \ No newline at end of file diff --git a/Applications/RayWalk/Localization/Russian.lang b/Applications/RayWalk/Localization/Russian.lang new file mode 100755 index 00000000..a4a49179 --- /dev/null +++ b/Applications/RayWalk/Localization/Russian.lang @@ -0,0 +1,25 @@ +{ + continue = "Продолжить", + settings = "Настройки", + exit = "Выход", + loadWorld = "Загрузить мир", + controls = "Управление:", + controlsHelp = { + "WASD для перемещения, QE - поворот", + "Space - прыжок, Ctrl - приседание", + "K - компас, P - часы, M - карта, F1 - дебаг-инфо", + "12345 - выбор оружия, первое позволяет ставить и ломать блоки", + "Мышь - стрельба/взаимодействие с миром", + "Enter - командная строка, Backspace - меню", + }, + rayEngineProperties = "Параметры RayEngine™", + screenResolution = "Разрешение экрана", + drawDistance = "Дистанция прорисовки: ", + shadingDistance = "Дистанция затенения: ", + shadingCascades = "Каскады затенения: ", + raycastQuality = "Допущения рейкастинка: ", + dayNightCycle = "Время суток: ", + enableSemipixelRenderer = "Полу-пиксельный рендерер: ", + enableDayNightCycle = "Цикл смены дня и ночи: ", + seconds = " сек", +} \ No newline at end of file diff --git a/Applications/RayWalk/RayEngine.cfg b/Applications/RayWalk/RayEngine.cfg old mode 100644 new mode 100755 index 96572a06..f9bd0b1a --- a/Applications/RayWalk/RayEngine.cfg +++ b/Applications/RayWalk/RayEngine.cfg @@ -1,23 +1,28 @@ -{ - tileWidth = 32, - drawDistance = 1000, - raycastQuality = 0.2, - shadingCascades = 8, - shadingDistance = 0.5, - shadingTransparencyMap = { - 51, - 102, - 153, - 204, - 255, - 255, - 255, - 204, - 204, - 179, - 153, - 128, - 102, - 77, - }, +{ + ["useSimpleRenderer"] = true, + ["shadingCascades"] = 8, + ["shadingDistance"] = 500, + ["shadingTransparencyMap"] = { + [12] = 128, + [6] = 255, + [13] = 102, + [1] = 51, + [3] = 153, + [7] = 255, + [8] = 204, + [4] = 204, + [9] = 204, + [14] = 77, + [2] = 102, + [5] = 255, + [11] = 153, + [10] = 179 + }, + ["raycastQuality"] = 6.4, + ["screenResolution"] = { + ["width"] = 160, + ["height"] = 50 + }, + ["drawDistance"] = 1000, + ["tileWidth"] = 32 } \ No newline at end of file diff --git a/Applications/RayWalk/RayWalk.lua b/Applications/RayWalk/RayWalk.lua old mode 100644 new mode 100755 index 94432edc..6965c7ac --- a/Applications/RayWalk/RayWalk.lua +++ b/Applications/RayWalk/RayWalk.lua @@ -1,11 +1,13 @@ -package.loaded.rayEngine = nil -_G.rayEngine = nil + +package.loaded.doubleHeight, package.loaded.rayEngine, package.loaded.GUI, package.loaded.windows, _G.doubleHeight, _G.rayEngine, _G.GUI, _G.windows = nil, nil, nil, nil, nil, nil, nil, nil local libraries = { + component = "component", buffer = "doubleBuffering", - rayEngine = "rayEngine", GUI = "GUI", - ecs = "ECSAPI", + windows = "windows", + rayEngine = "rayEngine", + MineOSCore = "MineOSCore", unicode = "unicode", event = "event", } @@ -14,50 +16,83 @@ for library in pairs(libraries) do if not _G[library] then _G[library] = require ---------------------------------------------------------------------------------------------------------------------------------- -local applicationPath = "MineOS/Applications/RayWalk.app/Resources/" -local worldsPath = applicationPath .. "Worlds/" -local rayWalkVersion = "RayWalk v3.2 closed beta" +local applicationResourcesDirectory = MineOSCore.getCurrentApplicationResourcesDirectory() +local localization = MineOSCore.getLocalization(applicationResourcesDirectory .. "Localization/") +local worldsPath = applicationResourcesDirectory .. "Worlds/" +local rayWalkVersion = "RayWalk Tech Demo v3.3" ---------------------------------------------------------------------------------------------------------------------------------- -local function menu() - local buttonWidth, buttonHeight = 50, 3 - local selectWorldButtons, buttons = {}, {} - for file in fs.list(worldsPath) do table.insert(selectWorldButtons, unicode.sub(file, 1, -2)) end - local x, y = math.floor(buffer.screen.width / 2 - buttonWidth / 2), math.floor(buffer.screen.height / 2 - ((#selectWorldButtons + 3) * (buttonHeight + 1)) / 2) - local buttonData = {}; for i = 1, #selectWorldButtons do table.insert(buttonData, {GUI.buttonTypes.default, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, selectWorldButtons[i]}) end - +local function menuBackground() rayEngine.drawWorld() buffer.clear(0x000000, 50) - - GUI.centeredText(GUI.alignment.verticalCenter, y, 0xFFFFFF, rayWalkVersion); y = y + 2 - buttons.resume = GUI.button(x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, "Продолжить"); y = y + buttonHeight + 1 - buttons.quit = GUI.button(x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0x999999, 0x262626, "Выход"); y = y + buttonHeight + 1 - GUI.centeredText(GUI.alignment.verticalCenter, y, 0xFFFFFF, "Загрузить мир"); y = y + 2 - selectWorldButtons = GUI.buttons(x, y, GUI.directions.vertical, 1, table.unpack(buttonData)) - - buffer.draw() - - while true do - local e = {event.pull("touch")} - for _, button in pairs(selectWorldButtons) do - if button:isClicked(e[3], e[4]) then - button:press() - rayEngine.loadWorld(worldsPath .. button.text) - return - end - end - - if buttons.resume:isClicked(e[3], e[4]) then - buttons.resume:press() - return - elseif buttons.quit:isClicked(e[3], e[4]) then - buttons.quit:press() - os.exit() - end - end end +local function settings() + local window = windows.empty(1, 1, buffer.screen.width, buffer.screen.height, buffer.screen.width, buffer.screen.height) + window.onDrawStarted = menuBackground + + local sliderWidth, textBoxWidth = 43, 19 + local x, y = math.floor(window.width / 2 - sliderWidth / 2), math.floor(window.height / 2 - 19) + + window:addLabel("settingsLabel", 1, y, window.width, 1, 0xFFFFFF, localization.rayEngineProperties):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + + local resolutionTextBoxWidth = window:addInputTextBox("resolutionTextBoxWidth", x, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, buffer.screen.width, nil, nil, true) + window:addLabel("resolutionCrossLabel", x + textBoxWidth + 2, y + 1, 1, 1, 0xFFFFFF, "X") + local resolutionTextBoxHeight = window:addInputTextBox("resolutionTextBoxHeight", x + textBoxWidth + 5, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, buffer.screen.height, nil, nil, true); y = y + 4 + window:addLabel("resolutionLabel", 1, y, window.width, 1, 0xDDDDDD, localization.screenResolution):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + resolutionTextBoxWidth.validator = function(text) local num = tonumber(text); if num and num >= 40 and num <= 160 then return true end end + resolutionTextBoxHeight.validator = function(text) local num = tonumber(text); if num and num >= 12 and num <= 50 then return true end end + local function onAnyResolutionTextBoxInputFinished() window:close(); rayEngine.changeResolution(tonumber(resolutionTextBoxWidth.text), tonumber(resolutionTextBoxHeight.text)); settings() end + resolutionTextBoxWidth.onInputFinished = onAnyResolutionTextBoxInputFinished + resolutionTextBoxHeight.onInputFinished = onAnyResolutionTextBoxInputFinished + + window:addHorizontalSlider("drawDistanceSlider", x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 100, 5000, rayEngine.properties.drawDistance, true, localization.drawDistance).onValueChanged = function(object) rayEngine.properties.drawDistance = object.value; window:draw(); buffer:draw() end; y = y + 4 + window:addHorizontalSlider("shadingDistanceSlider", x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 100, 3000, rayEngine.properties.shadingDistance, true, localization.shadingDistance).onValueChanged = function(object) rayEngine.properties.shadingDistance = object.value; window:draw(); buffer:draw(); window:draw(); buffer:draw() end; y = y + 4 + window:addHorizontalSlider("shadingCascadesSlider", x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 2, 48, rayEngine.properties.shadingCascades, true, localization.shadingCascades).onValueChanged = function(object) rayEngine.properties.shadingCascades = object.value; window:draw(); buffer:draw() end; y = y + 4 + window:addHorizontalSlider("raycastQualitySlider", x, y, sliderWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xDDDDDD, 0.5, 32, rayEngine.properties.raycastQuality, true, localization.raycastQuality).onValueChanged = function(object) rayEngine.properties.raycastQuality = object.value; window:draw(); buffer:draw() end; y = y + 4 + window:addHorizontalSlider("currentTimeSlider", x, y, sliderWidth, rayEngine.world.colors.sky.current, 0x000000, rayEngine.world.colors.sky.current, 0xDDDDDD, 0, rayEngine.world.dayNightCycle.length, rayEngine.world.dayNightCycle.currentTime, true, localization.dayNightCycle, localization.seconds).onValueChanged = function(object) rayEngine.world.dayNightCycle.currentTime = object.value; rayEngine.refreshTimeDependentColors(); object.colors.active = rayEngine.world.colors.sky.current; object.colors.pipe = rayEngine.world.colors.sky.current; window:draw(); buffer:draw() end; y = y + 4 + + window:addLabel("graphonLabel", x, y, sliderWidth, 1, 0xDDDDDD, localization.enableSemipixelRenderer) + window:addSwitch("graphonSwitch", x + sliderWidth - 8, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, not rayEngine.properties.useSimpleRenderer).onStateChanged = function(object) rayEngine.properties.useSimpleRenderer = not object.state; window:draw(); buffer:draw() end; y = y + 3 + + window:addLabel("lockTimeLabel", x, y, sliderWidth, 1, 0xDDDDDD, localization.enableDayNightCycle) + window:addSwitch("lockTimeSwitch", x + sliderWidth - 8, y, 8, 0xFFDB40, 0xAAAAAA, 0xFFFFFF, rayEngine.world.dayNightCycle.enabled).onStateChanged = function(object) rayEngine.world.dayNightCycle.enabled = object.state; window:draw(); buffer:draw() end; y = y + 3 + + window:addButton("resumeButton", x, y, sliderWidth, 3, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, localization.continue).onTouch = function() window:close(); table.toFile(applicationResourcesDirectory .. "RayEngine.cfg", rayEngine.properties, true) end + + window:draw(); buffer.draw(); window:handleEvents() +end + +local function menu() + local window = windows.empty(1, 1, buffer.screen.width, buffer.screen.height, buffer.screen.width, buffer.screen.height) + window.onDrawStarted = menuBackground + + local buttonWidth, buttonHeight = 50, 3 + local worlds = {} + for file in fs.list(worldsPath) do table.insert(worlds, unicode.sub(file, 1, -2)) end + local x, y = math.floor(window.width / 2 - buttonWidth / 2), math.floor(window.height / 2 - #worlds * (buttonHeight + 1) / 2 - 11) + + window:addLabel("versionLabel", 1, y, window.width, 1, 0xFFFFFF, rayWalkVersion):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 + window:addButton("resumeButton", x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, localization.continue).onTouch = function() window:close() end; y = y + buttonHeight + 1 + window:addButton("settingsButton", x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, localization.settings).onTouch = function() window:close(); settings() end; y = y + buttonHeight + 1 + window:addButton("exitButton", x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0x999999, 0x262626, localization.exit).onTouch = function() buffer.clear(0x000000); buffer.draw(); os.exit() end; y = y + buttonHeight + 1 + window:addLabel("loadWorldLabel", 1, y, window.width, 1, 0xFFFFFF, localization.loadWorld):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 2 + + for i = 1, #worlds do + window:addButton("worldButton" .. i, x, y, buttonWidth, buttonHeight, 0xEEEEEE, 0x262626, 0xBBBBBB, 0x262626, worlds[i]).onTouch = function() rayEngine.loadWorld(worldsPath .. worlds[i]); window:close() end + y = y + buttonHeight + 1 + end + + local lines = localization.controlsHelp + table.insert(lines, 1, " ") + table.insert(lines, 1, {text = localization.controls, color = 0xFFFFFF}) + window:addTextBox("informationTextBox", 1, y, window.width, #lines, nil, 0xDDDDDD, lines, 1):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + #lines + 1 + + window:draw(); buffer.draw(); window:handleEvents() +end + + ---------------------------------------------------------------------------------------------------------------------------------- local controls = { @@ -75,6 +110,7 @@ local controls = { [28] = rayEngine.commandLine, --enter [57] = rayEngine.jump, --space [29] = rayEngine.crouch, --ctrl + [59] = rayEngine.toggleDebugInformation, -- F1 }, ["key_up"] = { [29] = rayEngine.crouch, --ctrl @@ -83,32 +119,30 @@ local controls = { -------------------------------------------------------------------------------------------------------------- -buffer.start() --- rayEngine.intro() -rayEngine.loadEngine(applicationPath .. "RayEngine.cfg") -rayEngine.loadWeapons(applicationPath .. "Weapons/") +rayEngine.loadEngineProperties(applicationResourcesDirectory .. "RayEngine.cfg") +rayEngine.loadWeapons(applicationResourcesDirectory .. "Weapons/") rayEngine.loadWorld(worldsPath .. "ExampleWorld") +rayEngine.changeResolution(rayEngine.properties.screenResolution.width, rayEngine.properties.screenResolution.height) +-- rayEngine.intro() menu() rayEngine.update() -while (true) do +while true do local e = { event.pull(1) } - - if ( e[1] ) then - if e[1] == "touch" then - if e[5] == 1 then - if not rayEngine.currentWeapon then rayEngine.place(3, 0x3) end - else - if rayEngine.currentWeapon then rayEngine.fire() else rayEngine.destroy(3) end - end + if e[1] == "touch" then + if e[5] == 1 then + if not rayEngine.currentWeapon then rayEngine.place(3, 0x3) end else - if e[4] > 1 and e[4] < 10 then - rayEngine.changeWeapon(e[4] - 2) - else - if controls[e[1]] and controls[e[1]][e[4]] then controls[e[1]][e[4]]() end - end + if rayEngine.currentWeapon then rayEngine.fire() else rayEngine.destroy(3) end end + elseif e[1] == "key_down" then + if e[4] > 1 and e[4] < 10 then + rayEngine.changeWeapon(e[4] - 2) + else + if controls[e[1]] and controls[e[1]][e[4]] then controls[e[1]][e[4]]() end + end + elseif e[1] == "key_up" then + if controls[e[1]] and controls[e[1]][e[4]] then controls[e[1]][e[4]]() end end - rayEngine.update() end \ No newline at end of file diff --git a/Applications/RayWalk/Weapons/CrosshairTextures/Angled.pic b/Applications/RayWalk/Weapons/CrosshairTextures/Angled.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/CrosshairTextures/Default.pic b/Applications/RayWalk/Weapons/CrosshairTextures/Default.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/CrosshairTextures/Dotted.pic b/Applications/RayWalk/Weapons/CrosshairTextures/Dotted.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/CrosshairTextures/Half.pic b/Applications/RayWalk/Weapons/CrosshairTextures/Half.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/FireTextures/Plasma.pic b/Applications/RayWalk/Weapons/FireTextures/Plasma.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/FireTextures/PowderFire.pic b/Applications/RayWalk/Weapons/FireTextures/PowderFire.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/WeaponTextures/Pistol.pic b/Applications/RayWalk/Weapons/WeaponTextures/Pistol.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/WeaponTextures/Plasmer.pic b/Applications/RayWalk/Weapons/WeaponTextures/Plasmer.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/WeaponTextures/Rifle.pic b/Applications/RayWalk/Weapons/WeaponTextures/Rifle.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/WeaponTextures/Sniper.pic b/Applications/RayWalk/Weapons/WeaponTextures/Sniper.pic old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Weapons/Weapons.cfg b/Applications/RayWalk/Weapons/Weapons.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/ExampleWorld/Blocks.cfg b/Applications/RayWalk/Worlds/ExampleWorld/Blocks.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/ExampleWorld/Map.cfg b/Applications/RayWalk/Worlds/ExampleWorld/Map.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/ExampleWorld/Player.cfg b/Applications/RayWalk/Worlds/ExampleWorld/Player.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/ExampleWorld/World.cfg b/Applications/RayWalk/Worlds/ExampleWorld/World.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/SundownBeams/Blocks.cfg b/Applications/RayWalk/Worlds/SundownBeams/Blocks.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/SundownBeams/Map.cfg b/Applications/RayWalk/Worlds/SundownBeams/Map.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/SundownBeams/Player.cfg b/Applications/RayWalk/Worlds/SundownBeams/Player.cfg old mode 100644 new mode 100755 diff --git a/Applications/RayWalk/Worlds/SundownBeams/World.cfg b/Applications/RayWalk/Worlds/SundownBeams/World.cfg old mode 100644 new mode 100755 diff --git a/Applications/Stargate/Stargate.lua b/Applications/Stargate/Stargate.lua old mode 100644 new mode 100755 index 2cabaa73..ca86ccac --- a/Applications/Stargate/Stargate.lua +++ b/Applications/Stargate/Stargate.lua @@ -120,17 +120,17 @@ local function drawSG() y = y + 1 - buttons.connectButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Прямое подключение", stargateState == "Connected"); y = y + 3 - buttons.disconnectButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Отключиться", stargateState ~= "Connected"); y = y + 3 - buttons.messageButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Сообщение", stargateState ~= "Connected"); y = y + 3 - buttons.closeIrisButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, irisState == "Closed" and "Открыть Iris" or "Закрыть Iris", irisState == "Offline"); y = y + 3 + buttons.connectButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Прямое подключение", stargateState == "Connected"):draw(); y = y + 3 + buttons.disconnectButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Отключиться", stargateState ~= "Connected"):draw(); y = y + 3 + buttons.messageButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Сообщение", stargateState ~= "Connected"):draw(); y = y + 3 + buttons.closeIrisButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, irisState == "Closed" and "Открыть Iris" or "Закрыть Iris", irisState == "Offline"):draw(); y = y + 3 y = y + 1 centerText(y, lineColor, "Контакты"); y = y + 2 local sizeOfContacts = getArraySize(contacts.addresses) - buttons.addContactButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Добавить"); y = y + 3 - buttons.removeContactButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Удалить", sizeOfContacts <= 0); y = y + 3 - buttons.connectToContactButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Соединиться", sizeOfContacts <= 0 or stargateState == "Connected"); y = y + 3 + buttons.addContactButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Добавить"):draw(); y = y + 3 + buttons.removeContactButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Удалить", sizeOfContacts <= 0):draw(); y = y + 3 + buttons.connectToContactButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Соединиться", sizeOfContacts <= 0 or stargateState == "Connected"):draw(); y = y + 3 y = y + 1 centerText(y, lineColor, "Затраты на активацию"); y = y + 2 buffer.text(x, y, 0x228822, string.rep("━", buttonWidth)) @@ -144,7 +144,7 @@ local function drawSG() end y = y + 2 - buttons.quitButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Выйти"); y = y + 3 + buttons.quitButton = GUI.framedButton(x, y, buttonWidth, 3, lineColor, lineColor, pressColor, pressColor, "Выйти"):draw(); y = y + 3 end @@ -181,7 +181,7 @@ while true do if e[1] == "touch" then for _, button in pairs(buttons) do if button:isClicked(e[3], e[4]) then - button:press(0.2) + button:pressAndRelease() if button.text == "Прямое подключение" then local data = ecs.universalWindow("auto", "auto", 36, 0x262626, true, diff --git a/Installer/Installer.lua b/Installer/Installer.lua index 82fe6c69..8c382e9d 100644 --- a/Installer/Installer.lua +++ b/Installer/Installer.lua @@ -201,7 +201,17 @@ do downloadAllApps, downloadWallpapers, showHelpTips = data[2], data[3], data[4] --УСТАНАВЛИВАЕМ НУЖНЫЙ ЯЗЫК - _G.OSSettings = { showHelpOnApplicationStart = showHelpTips, language = data[1] } + _G.OSSettings = { + showHelpOnApplicationStart = showHelpTips, + language = data[1], + dockShortcuts = { + {path = "/MineOS/Applications/AppMarket.app"}, + {path = "/MineOS/Applications/Finder.app"}, + {path = "/MineOS/Applications/Photoshop.app"}, + {path = "/MineOS/Applications/VK.app"}, + } + } + ecs.saveOSSettings() --Качаем язык diff --git a/MineOS/Icons/Application.pic b/MineOS/Icons/Application.pic new file mode 100755 index 0000000000000000000000000000000000000000..9563c32f336331ec7099583e29402ab5ef660fe8 GIT binary patch literal 156 zcmYMru?@md3Ps3{l$DM7MCMd8XN8>FVDOP|%~VFPNU;0S%uob=AV%js-d zbpTe!&Ojq61p_shw~#FqbwEdst6@J99s$+%pJL_Sarhs_F*UJv#pSu&4e#8(qJSm4 Q-Y}<+QKb2n{zT!Qzij*%)Bpeg literal 0 HcmV?d00001 diff --git a/MineOS/Languages/English.lang b/MineOS/Languages/English.lang old mode 100644 new mode 100755 index 7249e508..37946741 --- a/MineOS/Languages/English.lang +++ b/MineOS/Languages/English.lang @@ -13,6 +13,8 @@ contextMenuUploadToPastebin = "Upload to Pastebin", contextMenuAddToDock = "Add to Dock", contextMenuRemoveFromDock = "Remove from Dock", + contextMenuMoveRight = "Move right", + contextMenuMoveLeft = "Move left", contextMenuArchive = "Add to archive", contextMenuDelete = "Delete", contextMenuAddToFavourites = "Add to favourites", @@ -33,6 +35,8 @@ hideFileFormat = "Hide file format", showHiddenFiles = "Show hidden files", hideHiddenFiles = "Hide hidden files", + showApplicationIcons = "Show application icons", + hideApplicationIcons = "Hide application icons", sortByTypeShort = "By type", sortByNameShort = "By name", diff --git a/MineOS/Languages/Russian.lang b/MineOS/Languages/Russian.lang old mode 100644 new mode 100755 index 1409907b..fa7737b2 --- a/MineOS/Languages/Russian.lang +++ b/MineOS/Languages/Russian.lang @@ -13,13 +13,15 @@ contextMenuUploadToPastebin = "Загрузить на Pastebin", contextMenuAddToDock = "Добавить в Dock", contextMenuRemoveFromDock = "Удалить из Dock", + contextMenuMoveRight = "Передвинуть правее", + contextMenuMoveLeft = "Передвинуть левее", contextMenuArchive = "Добавить в архив", contextMenuDelete = "Удалить", contextMenuAddToFavourites = "Добавить в избранное", contextMenuCreateApplication = "Создать приложение MineOS", contextMenuSetAsWallpaper = "Установить как обои", contextMenuShowPackageContent = "Показать содержимое пакета", - contextMenuShowContainingFolder = "Показать содержащую папку", + contextMenuShowContainingFolder = "Открыть содержащую папку", contextMenuRemoveFromFavourites = "Удалить из избранного", favourites = "Избранное", @@ -33,6 +35,8 @@ hideFileFormat = "Скрывать формат файлов", showHiddenFiles = "Показывать скрытые файлы", hideHiddenFiles = "Скрывать скрытые файлы", + showApplicationIcons = "Показывать иконки приложений", + hideApplicationIcons = "Скрывать иконки приложений", sortByTypeShort = "По типу", sortByNameShort = "По имени", diff --git a/lib/ECSAPI.lua b/lib/ECSAPI.lua old mode 100644 new mode 100755 index b7e7ca10..182628ed --- a/lib/ECSAPI.lua +++ b/lib/ECSAPI.lua @@ -317,11 +317,8 @@ function ecs.getOSApplication(application) --Если имеется режим создания ярлыка, то создаем его if application.createShortcut then local desktopPath = "MineOS/Desktop/" - local dockPath = "MineOS/System/OS/Dock/" - if application.createShortcut == "dock" then - ecs.createShortCut(dockPath .. fs.name(application.name) .. ".lnk", application.name .. ".app") - else + if application.createShortcut == "desktop" then ecs.createShortCut(desktopPath .. fs.name(application.name) .. ".lnk", application.name .. ".app") end end diff --git a/lib/GUI.lua b/lib/GUI.lua old mode 100644 new mode 100755 index c64c9f95..588be725 --- a/lib/GUI.lua +++ b/lib/GUI.lua @@ -1,218 +1,644 @@ +----------------------------------------- Libraries ----------------------------------------- + local libraries = { + advancedLua = "advancedLua", buffer = "doubleBuffering", unicode = "unicode", event = "event", } for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end; libraries = nil + +----------------------------------------- Core constants ----------------------------------------- + local GUI = {} ----------------------------------------------------- Универсальные методы -------------------------------------------------------- - GUI.alignment = { - verticalCenter = 0, - horizontalCenter = 1, - horizontalAndVerticalCenter = 3, + horizontal = enum( + "left", + "center", + "right" + ), + vertical = enum( + "top", + "center", + "bottom" + ) } -GUI.directions = { - horizontal = 0, - vertical = 1, -} - -GUI.buttonTypes = { - default = 0, - adaptive = 1, - framedDefault = 2, - framedAdaptive = 3, -} +GUI.directions = enum( + "horizontal", + "vertical" +) GUI.colors = { - disabled = 0x888888, - disabledText = 0xAAAAAA, + disabled = { + background = 0x888888, + text = 0xAAAAAA + }, + contextMenu = { + background = 0xFFFFFF, + separator = 0xAAAAAA, + default = { + text = 0x2D2D2D + }, + disabled = { + text = 0xAAAAAA + }, + pressed = { + background = 0x3366CC, + text = 0xFFFFFF + }, + transparency = { + background = 20, + shadow = 50 + } + } } --- Универсальный метод для проверки клика на прямоугольный объект -local function objectClicked(object, x, y) +GUI.contextMenuElementTypes = enum( + "default", + "separator" +) + +GUI.objectTypes = enum( + "empty", + "panel", + "label", + "button", + "framedButton", + "image", + "windowActionButtons", + "windowActionButton", + "tabBar", + "tabBarTab", + "menu", + "menuElement", + "window", + "inputTextBox", + "textBox", + "horizontalSlider", + "switch" +) + +----------------------------------------- Primitive objects ----------------------------------------- + +-- Universal method to check if object was clicked by following coordinates +local function isObjectClicked(object, x, y) if x >= object.x and y >= object.y and x <= object.x + object.width - 1 and y <= object.y + object.height - 1 and not object.disabled and not object.invisible ~= false then return true end return false end -local function objectSetDisabled(object, state) - object.disabled = state +-- Limit object's text field to its' size +local function objectTextLimit(object) + local text, textLength = object.text, unicode.len(object.text) + if textLength > object.width then text = unicode.sub(text, 1, object.width); textLength = object.width end + return text, textLength end ---Создание базового примитива-объекта +-- Base object to use in everything function GUI.object(x, y, width, height) return { x = x, y = y, width = width, height = height, - isClicked = objectClicked, + isClicked = isObjectClicked } end ----------------------------------------------------- Кнопки -------------------------------------------------------------------- +----------------------------------------- Object alignment ----------------------------------------- --- Универсальынй метод-рисоватор кнопки -local function drawButton(buttonObject, isPressed) - local textLength = unicode.len(buttonObject.text) - if textLength > buttonObject.width then buttonObject.text = unicode.sub(buttonObject.text, 1, buttonObject.width) end - - local xText = math.floor(buttonObject.x + buttonObject.width / 2 - textLength / 2) - local yText = math.floor(buttonObject.y + buttonObject.height / 2) - local buttonColor = buttonObject.disabled and buttonObject.colors.disabled.button or (isPressed and buttonObject.colors.pressed.button or buttonObject.colors.default.button) - local textColor = buttonObject.disabled and buttonObject.colors.disabled.text or (isPressed and buttonObject.colors.pressed.text or buttonObject.colors.default.text) - - if buttonObject.type == GUI.buttonTypes.default or buttonObject.type == GUI.buttonTypes.adaptive then - buffer.square(buttonObject.x, buttonObject.y, buttonObject.width, buttonObject.height, buttonColor, textColor, " ") - buffer.text(xText, yText, textColor, buttonObject.text) - elseif buttonObject.type == GUI.buttonTypes.framedDefault or buttonObject.type == GUI.buttonTypes.framedAdaptive then - buffer.frame(buttonObject.x, buttonObject.y, buttonObject.width, buttonObject.height, buttonColor) - buffer.text(xText, yText, textColor, buttonObject.text) - end +-- Set children alignment in parent object +function GUI.setAlignment(object, horizontalAlignment, verticalAlignment) + object.alignment = { + horizontal = horizontalAlignment, + vertical = verticalAlignment + } + return object end --- Метод-нажиматор кнопки -local function pressButton(buttonObject, pressTime) - drawButton(buttonObject, true) +-- Get subObject position inside of parent object +function GUI.getAlignmentCoordinates(object, subObject) + local x, y + if object.alignment.horizontal == GUI.alignment.horizontal.left then + x = object.x + elseif object.alignment.horizontal == GUI.alignment.horizontal.center then + x = math.floor(object.x + object.width / 2 - subObject.width / 2) + elseif object.alignment.horizontal == GUI.alignment.horizontal.right then + x = object.x + object.width - subObject.width + else + error("Unknown horizontal alignment: " .. tostring(object.alignment.horizontal)) + end + + if object.alignment.vertical == GUI.alignment.vertical.top then + y = object.y + elseif object.alignment.vertical == GUI.alignment.vertical.center then + y = math.floor(object.y + object.height / 2 - subObject.height / 2) + elseif object.alignment.vertical == GUI.alignment.vertical.bottom then + y = object.y + object.height - subObject.height + else + error("Unknown vertical alignment: " .. tostring(object.alignment.vertical)) + end + + return x, y +end + +----------------------------------------- Containers ----------------------------------------- + +-- Object calling by it's name using 'container["objectName"]' against of 'container.children[1, 2, 3, ...]' +function GUI.setContainerMetasearch(container) + setmetatable(container, { + __index = function(container, objectName) + for objectIndex = 1, #container.children do + if container.children[objectIndex].name == objectName then return container.children[objectIndex] end + end + end + }) +end + +-- Go recursively through every container's object (including other containers) and return object that was clicked firstly by it's GUI-layer position +function GUI.getClickedObject(container, xEvent, yEvent) + local clickedObject, clickedIndex + for objectIndex = #container.children, 1, -1 do + container.children[objectIndex].x, container.children[objectIndex].y = container.children[objectIndex].localPosition.x + container.x - 1, container.children[objectIndex].localPosition.y + container.y - 1 + if container.children[objectIndex].children and #container.children[objectIndex].children > 0 then + clickedObject, clickedIndex = GUI.getClickedObject(container.children[objectIndex], xEvent, yEvent) + if clickedObject then break end + elseif not container.children[objectIndex].disableClicking and container.children[objectIndex]:isClicked(xEvent, yEvent) then + clickedObject, clickedIndex = container.children[objectIndex], objectIndex + break + end + end + + return clickedObject, clickedIndex +end + +-- Add any object as children to parent container with specified objectName +local function addObjectToContainer(container, objectType, objectName, object) + object.name = objectName + object.type = objectType + object.parent = container + object.localPosition = {x = object.x, y = object.y} + table.insert(container.children, object) + return object +end + +-- Add empty GUI.object to container +local function addEmptyObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.empty, objectName, GUI.object(...)) +end + +-- Add button object to container +local function addButtonObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.button, objectName, GUI.button(...)) +end + +-- Add adaptive button object to container +local function addAdaptiveButtonObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.button, objectName, GUI.adaptiveButton(...)) +end + +-- Add framedButton object to container +local function addFramedButtonObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.button, objectName, GUI.framedButton(...)) +end + +-- Add adaptive framedButton object to container +local function addAdaptiveFramedButtonObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.button, objectName, GUI.adaptiveFramedButton(...)) +end + +-- Add label object to container +local function addLabelObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.label, objectName, GUI.label(...)) +end + +-- Add panel object to container +local function addPanelObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.panel, objectName, GUI.panel(...)) +end + +-- Add windowActionButtons object to container +local function addWindowActionButtonsObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.windowActionButtons, objectName, GUI.windowActionButtons(...)) +end + +-- Add another container to container +local function addContainerToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.container, objectName, GUI.container(...)) +end + +-- Add image object to container +local function addImageObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.image, objectName, GUI.image(...)) +end + +-- Add image object to container +local function addTabBarObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.tabBar, objectName, GUI.tabBar(...)) +end + +-- Add InputTextBox object to container +local function addInputTextBoxObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.inputTextBox, objectName, GUI.inputTextBox(...)) +end + +-- Add TextBox object to container +local function addTextBoxObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.textBox, objectName, GUI.textBox(...)) +end + +-- Add Horizontal Slider object to container +local function addHorizontalSliderObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.horizontalSlider, objectName, GUI.horizontalSlider(...)) +end + +-- Add Switch object to container +local function addSwitchObjectToContainer(container, objectName, ...) + return addObjectToContainer(container, GUI.objectTypes.switch, objectName, GUI.switch(...)) +end + +-- Recursively draw container's content including all children container's content +local function drawContainerContent(container) + for objectIndex = 1, #container.children do + container.children[objectIndex].x, container.children[objectIndex].y = container.children[objectIndex].localPosition.x + container.x - 1, container.children[objectIndex].localPosition.y + container.y - 1 + if container.children[objectIndex].children then + -- drawContainerContent(container.children[objectIndex]) + container.children[objectIndex]:draw() + else + if container.children[objectIndex].draw then + container.children[objectIndex]:draw() + else + error("Container object with index " .. objectIndex .. " and name \"" .. tostring(container.children[objectIndex].name) .. "\" doesn't have :draw() method") + end + end + end + + return container +end + +-- Delete every container's children object +local function deleteContainersContent(container) + for objectIndex = 1, #container.children do container.children[objectIndex] = nil end +end + +-- Universal container to store any other objects like buttons, labels, etc +function GUI.container(x, y, width, height) + local container = GUI.object(x, y, width, height) + container.children = {} + GUI.setContainerMetasearch(container) + container.draw = drawContainerContent + container.getClickedObject = GUI.getClickedObject + container.deleteObjects = deleteContainersContent + + container.addContainer = addContainerToContainer + container.addPanel = addPanelObjectToContainer + container.addLabel = addLabelObjectToContainer + container.addButton = addButtonObjectToContainer + container.addAdaptiveButton = addAdaptiveButtonObjectToContainer + container.addFramedButton = addFramedButtonObjectToContainer + container.addAdaptiveFramedButton = addAdaptiveFramedButtonObjectToContainer + container.addWindowActionButtons = addWindowActionButtonsObjectToContainer + container.addImage = addImageObjectToContainer + container.addTabBar = addTabBarObjectToContainer + container.addTextBox = addTextBoxObjectToContainer + container.addInputTextBox = addInputTextBoxObjectToContainer + container.addHorizontalSlider = addHorizontalSliderObjectToContainer + container.addSwitch = addSwitchObjectToContainer + + return container +end + +----------------------------------------- Buttons ----------------------------------------- + +local function drawButton(object) + local text, textLength = objectTextLimit(object) + + local xText, yText = GUI.getAlignmentCoordinates(object, {width = textLength, 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) + + if buttonColor then + if object.buttonType == GUI.objectTypes.button then + buffer.square(object.x, object.y, object.width, object.height, buttonColor, textColor, " ") + else + buffer.frame(object.x, object.y, object.width, object.height, buttonColor) + end + end + + buffer.text(xText, yText, textColor, text) + + return object +end + +local function pressButton(object) + object.pressed = true + drawButton(object) +end + +local function releaseButton(object) + object.pressed = nil + drawButton(object) +end + +local function pressAndReleaseButton(object, pressTime) + pressButton(object) buffer.draw() os.sleep(pressTime or 0.2) - drawButton(buttonObject, false) + releaseButton(object) buffer.draw() end -- Создание таблицы кнопки со всеми необходимыми параметрами local function createButtonObject(buttonType, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - local buttonObject = GUI.object(x, y, width, height) - buttonObject.colors = { + local object = GUI.object(x, y, width, height) + object.colors = { default = { - button = buttonColor, + background = buttonColor, text = textColor }, pressed = { - button = buttonPressedColor, + background = buttonPressedColor, text = textPressedColor }, disabled = { - button = GUI.colors.disabled, - text = GUI.colors.disabledText, + background = GUI.colors.disabled.background, + text = GUI.colors.disabled.text, } } - buttonObject.disabled = disabledState - buttonObject.setDisabled = objectSetDisabled - buttonObject.type = buttonType - buttonObject.text = text - buttonObject.press = pressButton - buttonObject.draw = drawButton - return buttonObject + object.buttonType = buttonType + object.disabled = disabledState + object.text = text + object.press = pressButton + object.release = releaseButton + object.pressAndRelease = pressAndReleaseButton + object.draw = drawButton + object.setAlignment = GUI.setAlignment + object:setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.center) + + return object end -- Кнопка фиксированных размеров function GUI.button(x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - local buttonObject = createButtonObject(GUI.buttonTypes.default, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - buttonObject:draw() - return buttonObject + return createButtonObject(GUI.objectTypes.button, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) end -- Кнопка, подстраивающаяся под размер текста -function GUI.adaptiveButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - local buttonObject = createButtonObject(GUI.buttonTypes.adaptive, x, y, xOffset * 2 + unicode.len(text), yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - buttonObject:draw() - return buttonObject +function GUI.adaptiveButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) + return createButtonObject(GUI.objectTypes.button, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) end -- Кнопка в рамке function GUI.framedButton(x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - local buttonObject = createButtonObject(GUI.buttonTypes.framedDefault, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - buttonObject:draw() - return buttonObject + return createButtonObject(GUI.objectTypes.framedButton, x, y, width, height, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) end --- Кнопка в рамке, подстраивающаяся под размер текста function GUI.adaptiveFramedButton(x, y, xOffset, yOffset, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - local buttonObject = createButtonObject(GUI.buttonTypes.framedAdaptive, x, y, xOffset * 2 + unicode.len(text), yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) - buttonObject:draw() - return buttonObject + return createButtonObject(GUI.objectTypes.framedButton, x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, buttonColor, textColor, buttonPressedColor, textPressedColor, text, disabledState) end --- Вертикальный или горизонтальный ряд кнопок --- Каждая кнопка - это массив вида {enum GUI.buttonTypes.default или GUI.buttonTypes.adaptive, int ширина/отступ, int высота/отступ, int цвет кнопки, int цвет текста, int цвет нажатой кнопки, int цвет нажатого текста, string текст} --- Метод возвращает обычный массив кнопочных объектов (см. выше) -function GUI.buttons(x, y, direction, spaceBetweenButtons, ...) - local buttons = {...} - local buttonObjects = {} +----------------------------------------- TabBar ----------------------------------------- - local function drawCorrectButton(i) - if buttons[i][1] == GUI.buttonTypes.default then - return GUI.button(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) - elseif buttons[i][1] == GUI.buttonTypes.adaptive then - return GUI.adaptiveButton(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) - elseif buttons[i][1] == GUI.buttonTypes.framedDefault then - return GUI.framedButton(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) - elseif buttons[i][1] == GUI.buttonTypes.framedAdaptive then - return GUI.adaptiveFramedButton(x, y, buttons[i][2], buttons[i][3], buttons[i][4], buttons[i][5], buttons[i][6], buttons[i][7], buttons[i][8]) +local function drawTabBar(object) + for tab = 1, #object.tabs.children do + if tab == object.selectedTab then + object.tabs.children[tab].pressed = true else - error("Неподдерживаемый тип кнопки: " .. tostring(buttons[i][1])) + object.tabs.children[tab].pressed = false end end - for i = 1, #buttons do - buttonObjects[i] = drawCorrectButton(i) - if direction == GUI.directions.horizontal then - x = x + buttonObjects[i].width + spaceBetweenButtons - elseif direction == GUI.directions.vertical then - y = y + buttonObjects[i].height + spaceBetweenButtons - else - error("Неподдерживаемое направление: " .. tostring(buttons[i][1])) - end - end - - return buttonObjects + object:reimplementedDraw() + return object end -function GUI.menu(x, y, width, menuColor, ...) - local buttons = {...} - buffer.square(x, y, width, 1, menuColor) - x = x + 1 - local menuObjects = {} - for i = 1, #buttons do - menuObjects[i] = GUI.adaptiveButton(x, y, 1, 0, menuColor, buttons[i].textColor, buttons[i].buttonPressedColor or 0x3366CC, buttons[i].textPressedColor or 0xFFFFFF, buttons[i].text) - x = x + menuObjects[i].width - end - return menuObjects +function GUI.tabBar(x, y, width, height, spaceBetweenElements, backgroundColor, textColor, backgroundSelectedColor, textSelectedColor, ...) + local elements, object = {...}, GUI.container(x, y, width, height) + object.selectedTab = 1 + object.tabsWidth = 0; for elementIndex = 1, #elements do object.tabsWidth = object.tabsWidth + unicode.len(elements[elementIndex]) + 2 + spaceBetweenElements end; object.tabsWidth = object.tabsWidth - spaceBetweenElements + object.reimplementedDraw = object.draw + object.draw = drawTabBar + + object:addPanel("backgroundPanel", 1, 1, object.width, object.height, backgroundColor).disableClicking = true + object.tabs = object:addContainer("tabs", 1, 1, object.width, object.height) + + x = math.floor(width / 2 - object.tabsWidth / 2) + for elementIndex = 1, #elements do + local tab = object.tabs:addButton(elements[elementIndex], x, 1, unicode.len(elements[elementIndex]) + 2, height, backgroundColor, textColor, backgroundSelectedColor, textSelectedColor, elements[elementIndex]) + tab.type = GUI.objectTypes.tabBarTab + x = x + tab.width + spaceBetweenElements + end + + return object +end + +----------------------------------------- Panel ----------------------------------------- + +local function drawPanel(object) + buffer.square(object.x, object.y, object.width, object.height, object.colors.background, 0x000000, " ", object.colors.transparency) + return object +end + +function GUI.panel(x, y, width, height, color, transparency) + local object = GUI.object(x, y, width, height) + object.colors = {background = color, transparency = transparency} + object.draw = drawPanel + return object +end + +----------------------------------------- Label ----------------------------------------- + +local function drawLabel(object) + local text, textLength = objectTextLimit(object) + local xText, yText = GUI.getAlignmentCoordinates(object, {width = textLength, height = 1}) + buffer.text(xText, yText, object.colors.text, text) + return object +end + +function GUI.label(x, y, width, height, textColor, text) + local object = GUI.object(x, y, width, height) + object.setAlignment = GUI.setAlignment + object:setAlignment(GUI.alignment.horizontal.left, GUI.alignment.vertical.top) + object.colors = {text = textColor} + object.text = text + object.draw = drawLabel + return object +end + +----------------------------------------- Image ----------------------------------------- + +local function drawImage(object) + buffer.image(object.x, object.y, object.image) + return object +end + +function GUI.image(x, y, image) + local object = GUI.object(x, y, image.width, image.height) + object.image = image + object.draw = drawImage + return object +end + +----------------------------------------- Window action buttons ----------------------------------------- + +local function drawWindowActionButton(object) + local background = buffer.get(object.x, object.y) + object.colors.default.background, object.colors.pressed.background, object.colors.disabled.background = background, background, background + object:reimplementedDraw() + return object end function GUI.windowActionButtons(x, y, fatSymbol) local symbol = fatSymbol and "⬤" or "●" - local windowActionButtons, background = {} - background = buffer.get(x, y); windowActionButtons.close = GUI.button(x, y, 1, 1, background, 0xFF4940, background, 0x992400, symbol); x = x + 2 - background = buffer.get(x, y); windowActionButtons.minimize = GUI.button(x, y, 1, 1, background, 0xFFB640, background, 0x996D00, symbol); x = x + 2 - background = buffer.get(x, y); windowActionButtons.maximize = GUI.button(x, y, 1, 1, background, 0x00B640, background, 0x006D40, symbol); x = x + 2 - return windowActionButtons + + local container = GUI.container(x, y, 5, 1) + local closeButton = container:addButton("close", 1, 1, 1, 1, 0x000000, 0xFF4940, 0x000000, 0x992400, symbol) + local minimizeButton = container:addButton("minimize", 3, 1, 1, 1, 0x000000, 0xFFB640, 0x000000, 0x996D00, symbol) + local maximizeButton = container:addButton("maximize", 5, 1, 1, 1, 0x000000, 0x00B640, 0x000000, 0x006D40, symbol) + + closeButton.reimplementedDraw, minimizeButton.reimplementedDraw, maximizeButton.reimplementedDraw = closeButton.draw, minimizeButton.draw, maximizeButton.draw + closeButton.draw, minimizeButton.draw, maximizeButton.draw = drawWindowActionButton, drawWindowActionButton, drawWindowActionButton + + return container end -function GUI.toolbar(x, y, width, height, spaceBetweenElements, currentElement, toolbarColor, elementTextColor, activeElementColor, activeElementTextColor, ...) - local elements, objects, elementLength, isCurrent, elementWidth = {...}, {} - local totalWidth = 0; for i = 1, #elements do totalWidth = totalWidth + unicode.len(elements[i]) + 2 + spaceBetweenElements end; totalWidth = totalWidth - spaceBetweenElements - buffer.square(x, y, width, height, toolbarColor) - x = math.floor(x + width / 2 - totalWidth / 2) - local yText = math.floor(y + height / 2) +----------------------------------------- Context Menu ----------------------------------------- - for i = 1, #elements do - elementLength, isCurrent = unicode.len(elements[i]), i == currentElement - elementWidth = elementLength + 2 - if isCurrent then buffer.square(x, y, elementWidth, height, activeElementColor) end - buffer.text(x + 1, yText, isCurrent and activeElementTextColor or elementTextColor, elements[i]) - table.insert(objects, GUI.object(x, y, elementWidth, height)) - x = x + elementWidth + spaceBetweenElements - end +local function drawContextMenuElement(contextMenuObject, elementIndex, isPressed) + if contextMenuObject.elements[elementIndex].type == GUI.contextMenuElementTypes.default then + local textColor = contextMenuObject.elements[elementIndex].disabled and GUI.colors.contextMenu.disabled.text or (contextMenuObject.elements[elementIndex].color or GUI.colors.contextMenu.default.text) + + if isPressed then + buffer.square(contextMenuObject.x, contextMenuObject.y + elementIndex - 1, contextMenuObject.width, 1, GUI.colors.contextMenu.pressed.background, GUI.colors.contextMenu.pressed.text, " ") + textColor = GUI.colors.contextMenu.pressed.text + end - return objects + buffer.text(contextMenuObject.x + 2, contextMenuObject.y + elementIndex - 1, textColor, contextMenuObject.elements[elementIndex].text) + + if contextMenuObject.elements[elementIndex].shortcut then + buffer.text(contextMenuObject.x + contextMenuObject.width - unicode.len(contextMenuObject.elements[elementIndex].shortcut) - 2, contextMenuObject.y + elementIndex - 1, textColor, contextMenuObject.elements[elementIndex].shortcut) + end + else + buffer.text(contextMenuObject.x, contextMenuObject.y + elementIndex - 1, GUI.colors.contextMenu.separator, string.rep("─", contextMenuObject.width)) + end end +local function drawContextMenu(contextMenuObject) + buffer.square(contextMenuObject.x, contextMenuObject.y, contextMenuObject.width, contextMenuObject.height, GUI.colors.contextMenu.background, GUI.colors.contextMenu.default.text, " ", GUI.colors.contextMenu.transparency.background) + GUI.windowShadow(contextMenuObject.x, contextMenuObject.y, contextMenuObject.width, contextMenuObject.height, GUI.colors.contextMenu.transparency.shadow, true) + for elementIndex = 1, #contextMenuObject.elements do drawContextMenuElement(contextMenuObject, elementIndex, false) end +end + +local function showContextMenu(contextMenuObject) + local oldDrawLimit = buffer.getDrawLimit(); buffer.resetDrawLimit() + -- Расчет ширины окна меню + local longestElement, longestShortcut = 0, 0 + for elementIndex = 1, #contextMenuObject.elements do + if contextMenuObject.elements[elementIndex].type == GUI.contextMenuElementTypes.default then + longestElement = math.max(longestElement, unicode.len(contextMenuObject.elements[elementIndex].text)) + if contextMenuObject.elements[elementIndex].shortcut then longestShortcut = math.max(longestShortcut, unicode.len(contextMenuObject.elements[elementIndex].shortcut)) end + end + end + contextMenuObject.width, contextMenuObject.height = longestElement + 4 + (longestShortcut > 0 and longestShortcut + 3 or 0), #contextMenuObject.elements + + -- А это чтоб за края экрана не лезло + if contextMenuObject.y + contextMenuObject.height >= buffer.screen.height then contextMenuObject.y = buffer.screen.height - contextMenuObject.height end + if contextMenuObject.x + contextMenuObject.width + 1 >= buffer.screen.width then contextMenuObject.x = buffer.screen.width - contextMenuObject.width - 1 end + + local oldPixels = buffer.copy(contextMenuObject.x, contextMenuObject.y, contextMenuObject.width + 1, contextMenuObject.height + 1) + local function quit() + buffer.paste(contextMenuObject.x, contextMenuObject.y, oldPixels) + buffer.draw() + buffer.setDrawLimit(oldDrawLimit) + end + + drawContextMenu(contextMenuObject) + buffer.draw() + + while true do + local e = {event.pull()} + if e[1] == "touch" then + local objectFound = false + for elementIndex = 1, #contextMenuObject.elements do + if e[3] >= contextMenuObject.x and e[3] <= contextMenuObject.x + contextMenuObject.width - 1 and e[4] == contextMenuObject.y + elementIndex - 1 then + objectFound = true + if not contextMenuObject.elements[elementIndex].disabled and contextMenuObject.elements[elementIndex].type == GUI.contextMenuElementTypes.default then + drawContextMenuElement(contextMenuObject, elementIndex, true) + buffer.draw() + os.sleep(0.2) + quit() + return contextMenuObject.elements[elementIndex].text + end + break + end + end + + if not objectFound then quit(); return end + end + end +end + +local function addContextMenuElement(contextMenuObject, text, disabled, shortcut, color) + local element = {} + element.type = GUI.contextMenuElementTypes.default + element.text = text + element.disabled = disabled + element.shortcut = shortcut + element.color = color or GUI.colors.contextMenu.default.text --OPTIMIZATION + + table.insert(contextMenuObject.elements, element) + return element +end + +local function addContextMenuSeparator(contextMenuObject) + local element = {type = GUI.contextMenuElementTypes.separator} + table.insert(contextMenuObject.elements, element) + return element +end + +function GUI.contextMenu(x, y, ...) + local argumentElements = {...} + + local contextMenuObject = GUI.object(x, y, 1, 1) + contextMenuObject.elements = {} + contextMenuObject.addElement = addContextMenuElement + contextMenuObject.addSeparator = addContextMenuSeparator + contextMenuObject.show = showContextMenu + contextMenuObject.selectedElement = nil + + for elementIndex = 1, #argumentElements do + if argumentElements[elementIndex] == "-" then + contextMenuObject:addSeparator() + else + contextMenuObject:addElement(argumentElements[elementIndex][1], argumentElements[elementIndex][2], argumentElements[elementIndex][3], argumentElements[elementIndex][4]) + end + end + + return contextMenuObject +end + +----------------------------------------- Menu ----------------------------------------- + +function GUI.menu(x, y, width, backgroundColor, textColor, backgroundPressedColor, textPressedColor, backgroundTransparency, ...) + local elements = {...} + local menuObject = GUI.container(x, y, width, 1) + menuObject:addPanel("backgroundPanel", 1, 1, menuObject.width, 1, backgroundColor, backgroundTransparency).disableClicking = true + + local x = 2 + for elementIndex = 1, #elements do + local button = menuObject:addAdaptiveButton(elementIndex, x, 1, 1, 0, nil, elements[elementIndex][2] or textColor, elements[elementIndex][3] or backgroundPressedColor, elements[elementIndex][4] or textPressedColor, elements[elementIndex][1]) + button.type = GUI.objectTypes.menuElement + x = x + button.width + end + + return menuObject +end + +----------------------------------------- Other GUI elements ----------------------------------------- + function GUI.progressBar(x, y, width, height, firstColor, secondColor, value, maxValue, thin) local percent = value / maxValue local activeWidth = math.floor(percent * width) @@ -225,9 +651,16 @@ function GUI.progressBar(x, y, width, height, firstColor, secondColor, value, ma end end -function GUI.windowShadow(x, y, width, height, transparency) - buffer.square(x + width, y + 1, 2, height, 0x000000, 0x000000, " ", transparency) - buffer.square(x + 2, y + height, width - 2, 1, 0x000000, 0x000000, " ", transparency) +function GUI.windowShadow(x, y, width, height, transparency, thin) + transparency = transparency or 50 + if thin then + buffer.square(x + width, y + 1, 1, height - 1, 0x000000, 0x000000, " ", transparency) + buffer.text(x + 1, y + height, 0x000000, string.rep("▀", width), transparency) + buffer.text(x + width, y, 0x000000, "▄", transparency) + else + buffer.square(x + width, y + 1, 2, height, 0x000000, 0x000000, " ", transparency) + buffer.square(x + 2, y + height, width - 2, 1, 0x000000, 0x000000, " ", transparency) + end end ------------------------------------------------- Окна ------------------------------------------------------------------- @@ -285,14 +718,14 @@ function GUI.error(text, errorWindowParameters) --Текстус for i = 1, #text do buffer.text(x, yPos, textColor, text[i]); yPos = yPos + 1 end; yPos = yPos + 1 --Кнопачка - OKButton = GUI.button(x + widthOfText - buttonWidth, y + height - 2, buttonWidth, 1, 0x3392FF, 0xFFFFFF, 0xFFFFFF, 0x262626, "OK") + OKButton = GUI.button(x + widthOfText - buttonWidth, y + height - 2, buttonWidth, 1, 0x3392FF, 0xFFFFFF, 0xFFFFFF, 0x262626, "OK"):draw() --Атрисовачка buffer.draw() end --Графонистый выход local function quit() - OKButton:press(0.2) + OKButton:pressAndRelease(0.2) buffer.paste(1, y, oldPixels) buffer.draw() end @@ -316,11 +749,70 @@ function GUI.error(text, errorWindowParameters) end end --------------------------------------------------------------------------------------------------------------------------------- +----------------------------------------- Universal keyboard-input function ----------------------------------------- --- local textFieldProperties = { --- --Регурярное выражение, которому должны соответствовать вводимые данные. При несоответствии на выходе из функции выдается первоначальный текст, поданынй на выход функции --- regex = "^%d+$", +local function findValue(t, whatToSearch) + if type(t) ~= "table" then return end + for key, value in pairs(t) do + if type(key) == "string" and string.match(key, "^" .. whatToSearch) then + local valueType, postfix = type(value), "" + if valueType == "function" or (valueType == "table" and getmetatable(value) and getmetatable(value).__call) then + postfix = "()" + elseif valueType == "table" then + postfix = "." + end + return key .. postfix + end + end +end + +local function findTable(whereToSearch, t, whatToSearch) + local beforeFirstDot = string.match(whereToSearch, "^[^%.]+%.") + -- Если вообще есть таблица, где надо искать + if beforeFirstDot then + beforeFirstDot = unicode.sub(beforeFirstDot, 1, -2) + if t[beforeFirstDot] then + return findTable(unicode.sub(whereToSearch, unicode.len(beforeFirstDot) + 2, -1), t[beforeFirstDot], whatToSearch) + else + -- Кароч, слушай суда: вот в эту зону хуйня может зайти толька + -- тагда, кагда ты вручную ебенишь массив вида "abc.cda.blabla.test" + -- без автозаполнения, т.е. он МОЖЕТ быть неверным, однако прога все + -- равно проверяет на верность, и вот если НИ ХУЯ такого говнища типа + -- ... .blabla не существует, то интерхпретатор захуяривается СУДЫ + -- И ЧТОБ БОЛЬШЕ ВОПРОСОВ НЕ ЗАДАВАЛ!11! + end + -- Или если таблиц либо ваще нету, либо рекурсия суда вон вошла + else + return findValue(t[whereToSearch], whatToSearch) + end +end + +local function autocompleteVariables(sourceText) + local varPath = string.match(sourceText, "[a-zA-Z0-9%.%_]+$") + if varPath then + local prefix = string.sub(sourceText, 1, -unicode.len(varPath) - 1) + local whereToSearch = string.match(varPath, "[a-zA-Z0-9%.%_]+%.") + + if whereToSearch then + whereToSearch = unicode.sub(whereToSearch, 1, -2) + local findedTable = findTable(whereToSearch, _G, unicode.sub(varPath, unicode.len(whereToSearch) + 2, -1)) + return findedTable and prefix .. whereToSearch .. "." .. findedTable or sourceText + else + local findedValue = findValue(_G, varPath) + return findedValue and prefix .. findedValue or sourceText + end + else + return sourceText + end +end + +-- local inputProperties = { +-- --Метод, получающий на вход текущий текст и проверяющий вводимые данные. В случае успеха должен возвращать true +-- validator = function(text) if string.match(text, "^%d+$") then return true end +-- -- Автоматически очищает текстовое поле при начале ввода информации в него. +-- -- Если при окончании ввода тексет не будет соответствовать методу validator, указанному выше, +-- -- то будет возвращено исходное значение текста (не очищенное) +-- eraseTextWhenInputBegins = true -- --Отключает символ многоточия при выходе за пределы текстового поля -- disableDots = true, -- --Попросту отрисовывает всю необходимую информацию без активации нажатия на клавиши @@ -333,17 +825,23 @@ end -- cursorSymbol = "▌", -- --Символ-маскировщик, на который будет визуально заменен весь вводимый текст. Полезно для полей ввода пароля -- maskTextWithSymbol = "*", +-- --Активация подсветки Lua-синтаксиса +-- highlightLuaSyntax = true, +-- -- Активация автозаполнения названий переменных по нажатию клавиши Tab +-- autocompleteVariables = true, -- } -function GUI.input(x, y, width, foreground, startText, textFieldProperties) +function GUI.input(x, y, width, foreground, startText, inputProperties) + inputProperties = inputProperties or {} if not (y >= buffer.drawLimit.y and y <= buffer.drawLimit.y2) then return startText end local text = startText + if not inputProperties.justDrawNotEvent and inputProperties.eraseTextWhenInputBegins then text = "" end local textLength = unicode.len(text) local cursorBlinkState = false - local cursorBlinkDelay = (textFieldProperties and textFieldProperties.cursorBlinkDelay) and textFieldProperties.cursorBlinkDelay or 0.5 - local cursorColor = (textFieldProperties and textFieldProperties.cursorColor) and textFieldProperties.cursorColor or 0x00A8FF - local cursorSymbol = (textFieldProperties and textFieldProperties.cursorSymbol) and textFieldProperties.cursorSymbol or "┃" + local cursorBlinkDelay = inputProperties.cursorBlinkDelay and inputProperties.cursorBlinkDelay or 0.5 + local cursorColor = inputProperties.cursorColor and inputProperties.cursorColor or 0x00A8FF + local cursorSymbol = inputProperties.cursorSymbol and inputProperties.cursorSymbol or "┃" local oldPixels = {}; for i = x, x + width - 1 do table.insert(oldPixels, { buffer.get(i, y) }) end @@ -358,12 +856,12 @@ function GUI.input(x, y, width, foreground, startText, textFieldProperties) local function textFormat() local formattedText = text - if textFieldProperties and textFieldProperties.maskTextWithSymbol then - formattedText = string.rep(textFieldProperties.maskTextWithSymbol or "*", textLength) + if inputProperties.maskTextWithSymbol then + formattedText = string.rep(inputProperties.maskTextWithSymbol or "*", textLength) end if textLength > width then - if textFieldProperties and textFieldProperties.disableDots then + if inputProperties.disableDots then formattedText = unicode.sub(formattedText, -width, -1) else formattedText = "…" .. unicode.sub(formattedText, -width + 1, -1) @@ -375,7 +873,11 @@ function GUI.input(x, y, width, foreground, startText, textFieldProperties) local function draw() drawOldPixels() - buffer.text(x, y, foreground, textFormat()) + if inputProperties.highlightLuaSyntax then + require("syntax").highlightString(x, y, textFormat(), 1, width) + else + buffer.text(x, y, foreground, textFormat()) + end if cursorBlinkState then local cursorPosition = textLength < width and x + textLength or x + width - 1 @@ -383,7 +885,7 @@ function GUI.input(x, y, width, foreground, startText, textFieldProperties) buffer.set(cursorPosition, y, bg, cursorColor, cursorSymbol) end - if not (textFieldProperties and textFieldProperties.justDrawNotEvent) then buffer.draw() end + if not inputProperties.justDrawNotEvent then buffer.draw() end end local function backspace() @@ -392,7 +894,7 @@ function GUI.input(x, y, width, foreground, startText, textFieldProperties) local function quit() cursorBlinkState = false - if textFieldProperties and textFieldProperties.regex and not string.match(text, textFieldProperties.regex) then + if inputProperties.validator and not inputProperties.validator(text) then text = startText draw() return startText @@ -403,7 +905,7 @@ function GUI.input(x, y, width, foreground, startText, textFieldProperties) draw() - if textFieldProperties and textFieldProperties.justDrawNotEvent then return startText end + if inputProperties.justDrawNotEvent then return startText end while true do local e = { event.pull(cursorBlinkDelay) } @@ -412,6 +914,10 @@ function GUI.input(x, y, width, foreground, startText, textFieldProperties) backspace() elseif e[4] == 28 then return quit() + elseif e[4] == 15 then + if inputProperties.autocompleteVariables then + text = autocompleteVariables(text); getTextLength(); draw() + end else local symbol = unicode.char(e[3]) if not keyboard.isControl(e[3]) then @@ -433,65 +939,202 @@ function GUI.input(x, y, width, foreground, startText, textFieldProperties) end end -local function drawTextField(object, isFocused) - if not object.invisible then - local background = object.disabled and object.colors.disabled.textField or (isFocused and object.colors.focused.textField or object.colors.default.textField) - local foreground = object.disabled and object.colors.disabled.text or (isFocused and object.colors.focused.text or object.colors.default.text) - local y = math.floor(object.y + object.height / 2) - local text = isFocused and (object.text or "") or (object.text or object.placeholderText or "") +----------------------------------------- Input Text Box object ----------------------------------------- - if background then buffer.square(object.x, object.y, object.width, object.height, background, foreground, " ") end - local resultText = GUI.input(object.x + 1, y, object.width - 2, foreground, text, {justDrawNotEvent = not isFocused}) - object.text = isFocused and resultText or object.text - end +local function drawInputTextBox(object, isFocused) + local background = isFocused and object.colors.focused.background or object.colors.default.background + local foreground = isFocused and object.colors.focused.text or object.colors.default.text + local y = math.floor(object.y + object.height / 2) + local text = isFocused and (object.text or "") or (object.text or object.placeholderText or "") + + if background then buffer.square(object.x, object.y, object.width, object.height, background, foreground, " ") end + local resultText = GUI.input(object.x + 1, y, object.width - 2, foreground, text, { + justDrawNotEvent = not isFocused, + highlightLuaSyntax = isFocused and object.highlightLuaSyntax or nil, + autocompleteVariables = object.autocompleteVariables or nil, + maskTextWithSymbol = object.textMask or nil, + validator = object.validator or nil, + eraseTextWhenInputBegins = object.eraseTextOnFocus or nil, + }) + object.text = isFocused and resultText or object.text end -local function textFieldBeginInput(object) - drawTextField(object, true) - if object.text == "" then object.text = nil; drawTextField(object, false); buffer.draw() end +local function inputTextBoxBeginInput(object) + drawInputTextBox(object, true) + if object.text == "" then object.text = nil; drawInputTextBox(object, false); buffer.draw() end end -function GUI.textField(x, y, width, height, textFieldColor, textColor, textFieldFocusedColor, textFocusedColor, text, placeholderText, disabledState, invisibleState) +function GUI.inputTextBox(x, y, width, height, inputTextBoxColor, textColor, inputTextBoxFocusedColor, textFocusedColor, text, placeholderText, maskTextWithSymbol, eraseTextOnFocus) local object = GUI.object(x, y, width, height) - object.invisible = invisibleState - object.disabled = disabledState object.colors = { default = { - textField = textFieldColor, + background = inputTextBoxColor, text = textColor }, focused = { - textField = textFieldFocusedColor, + background = inputTextBoxFocusedColor, text = textFocusedColor - }, - disabled = { - textField = GUI.colors.disabled, - text = GUI.colors.disabledText, } } object.text = text object.placeholderText = placeholderText - object.isClicked = objectClicked - object.draw = drawTextField - object.input = textFieldBeginInput - object:draw() + object.isClicked = isObjectClicked + object.draw = drawInputTextBox + object.input = inputTextBoxBeginInput + object.eraseTextOnFocus = eraseTextOnFocus + object.textMask = maskTextWithSymbol + return object +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, " ") 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 + +function GUI.textBox(x, y, width, height, backgroundColor, textColor, lines, currentLine, horizontalOffset, verticalOffset) + local object = GUI.object(x, y, width, height) + 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.maximumValue) 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.square(object.x + activeWidth - 1, object.y, 2, 1, object.colors.pipe, 0x000000, " ") + + return object +end + +function GUI.horizontalSlider(x, y, width, activeColor, passiveColor, pipeColor, valueColor, minimumValue, maximumValue, value, showMaximumAndMinimumValues, currentValuePrefix, currentValuePostfix) + local object = GUI.object(x, y, width, 1) + 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 drawSwitch(object) + local pipeWidth = object.height * 2 + local pipePosition, backgroundColor + if object.state then pipePosition, backgroundColor = object.x + object.width - pipeWidth, object.colors.active else pipePosition, backgroundColor = object.x, object.colors.passive end + buffer.square(object.x, object.y, object.width, object.height, backgroundColor, 0x000000, " ") + buffer.square(pipePosition, object.y, pipeWidth, object.height, object.colors.pipe, 0x000000, " ") + return object +end + +function GUI.switch(x, y, width, activeColor, passiveColor, pipeColor, state) + local object = GUI.object(x, y, width, 1) + object.colors = {active = activeColor, passive = passiveColor, pipe = pipeColor, value = valueColor} + object.draw = drawSwitch + object.state = state or false return object end -------------------------------------------------------------------------------------------------------------------------------- -function GUI.centeredText(centrationENUM, coordinate, color, text) - local textLength, x, y = unicode.len(text) - if centrationENUM == GUI.alignment.verticalCenter then - x, y = math.floor(buffer.screen.width / 2 - textLength / 2), coordinate - elseif centrationENUM == GUI.alignment.horizontalCenter then - x, y = coordinate, math.floor(buffer.screen.height / 2) - else - x, y = math.floor(buffer.screen.width / 2 - textLength / 2), math.floor(buffer.screen.height / 2) - end +-- buffer.clear(0x1b1b1b) +-- buffer.draw(true) - buffer.text(x, y, color, text) -end +-- GUI.switch(2, 2, 8, 0x77FF77, 0x999999, 0xFFFFFF, true):draw() + +-- buffer.draw() -------------------------------------------------------------------------------------------------------------------------------- diff --git a/lib/MineOSCore.lua b/lib/MineOSCore.lua old mode 100644 new mode 100755 index 0697dfc4..74f68595 --- a/lib/MineOSCore.lua +++ b/lib/MineOSCore.lua @@ -1,37 +1,39 @@ + ---------------------------------------------- Библиотеки ------------------------------------------------------------------------ local libraries = { - advancedLua = "advancedLua", - computer = "computer", - ecs = "ECSAPI", component = "component", - files = "files", - fs = "filesystem", - context = "context", - buffer = "doubleBuffering", + advancedLua = "advancedLua", image = "image", + buffer = "doubleBuffering", GUI = "GUI", + ecs = "ECSAPI", zip = "archive", syntax = "syntax", + computer = "computer", + fs = "filesystem", } -for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end -libraries = nil - -local MineOSCore = {} +for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end; libraries = nil ----------------------------------------------------------------------------------------------------------------------------------- +local MineOSCore = {} + +MineOSCore.showApplicationIcons = true MineOSCore.iconWidth = 12 MineOSCore.iconHeight = 6 MineOSCore.paths = { - localizationFile = "MineOS/System/OS/Languages/" .. _G.OSSettings.language .. ".lang", - system = "MineOS/System/", - icons = "MineOS/System/OS/Icons/", - applications = "MineOS/Applications/", - pictures = "MineOS/Pictures/", - applicationList = "MineOS/System/OS/Applications.txt", + localizationFile = "/MineOS/System/OS/Languages/" .. _G.OSSettings.language .. ".lang", + system = "/MineOS/System/", + icons = "/MineOS/System/OS/Icons/", + applications = "/MineOS/Applications/", + pictures = "/MineOS/Pictures/", + desktop = "/MineOS/Desktop/", + dock = "/MineOS/System/OS/Dock/", + applicationList = "/MineOS/System/OS/Applications.txt", + trash = "/MineOS/Trash/", } MineOSCore.sortingMethods = { @@ -41,13 +43,36 @@ MineOSCore.sortingMethods = { } MineOSCore.colors = { - background = 0x262626. + background = 0x262626 } MineOSCore.localization = {} ----------------------------------------------------------------------------------------------------------------------------------- +function MineOSCore.getCurrentScriptDirectory() + return fs.path(getCurrentScript()) +end + +function MineOSCore.getCurrentApplicationResourcesDirectory() + return MineOSCore.getCurrentScriptDirectory() .. "/Resources/" +end + +function MineOSCore.getLocalization(pathToLocalizationFolder) + local localizationFileName = pathToLocalizationFolder .. _G.OSSettings.language .. ".lang" + if fs.exists(localizationFileName) then + return table.fromFile(localizationFileName) + else + error("Localization file \"" .. localizationFileName .. "\" doesn't exists") + end +end + +function MineOSCore.getCurrentApplicationLocalization() + return MineOSCore.getLocalization(MineOSCore.getCurrentApplicationResourcesDirectory() .. "Localization/") +end + +----------------------------------------------------------------------------------------------------------------------------------- + function MineOSCore.loadIcon(name, path) if not MineOSCore.icons[name] then MineOSCore.icons[name] = image.load(path) end return MineOSCore.icons[name] @@ -66,10 +91,11 @@ function MineOSCore.loadStandartIcons() 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") end function MineOSCore.init() - MineOSCore.localization = files.loadTableFromFile(MineOSCore.paths.localizationFile) + MineOSCore.localization = table.fromFile(MineOSCore.paths.localizationFile) MineOSCore.loadStandartIcons() end @@ -81,10 +107,12 @@ function MineOSCore.drawIcon(x, y, path, showFileFormat, nameColor, name) if fs.isDirectory(path) then if fileFormat == ".app" then - icon = "cyka" - MineOSCore.icons[icon] = image.load(path .. "/Resources/Icon.pic") - -- icon = path .. "/Resources/Icon.pic" - -- MineOSCore.loadIcon(icon, icon) + if MineOSCore.showApplicationIcons then + icon = "cyka" + MineOSCore.icons[icon] = image.load(path .. "/Resources/Icon.pic") + else + icon = "application" + end else icon = "folder" end @@ -155,34 +183,32 @@ function MineOSCore.parseErrorMessage(error, indentationWidth) end local function drawErrorWindow(path, programVersion, errorLine, reason, showSendToDeveloperButton) - local topbarColor = 0x383838 + local drawLimit = buffer.getDrawLimit(); buffer.resetDrawLimit() + local colors = { topBar = 0x383838, title = 0xFFFFFF } local programName = MineOSCore.localization.errorWhileRunningProgram .. "\"" .. fs.name(path) .. "\"" local width, height = buffer.screen.width, math.floor(buffer.screen.height * 0.45) local x, y = 1, math.floor(buffer.screen.height / 2 - height / 2) - local topbarHeight = 3 - local codeHeight = height - topbarHeight - 3 - local codeWidth = math.floor(width * 0.62) + local codeWidth, codeHeight = math.floor(width * 0.62), height - 3 local stackWidth = width - codeWidth - local buttons = {} - --Фончик - buffer.square(1, 1, buffer.screen.width, buffer.screen.height, 0x000000, 0x000000, " ", 50) + -- Затенение оконца + buffer.clear(0x000000, 50) - --Топбарчик - buffer.square(x, y, width, topbarHeight, topbarColor, 0xFFFFFF, " ") - buffer.text(math.floor(x + width / 2 - unicode.len(programName) / 2), y + 1, 0xFFFFFF, programName) + -- Окошечко и всякая шняжка на нем + local window = require("windows").empty(x, y, width, height, width, height) + window:addPanel("topBar", 1, 1, width, 3, colors.topBar) + window:addLabel("title", 1, 2, width, 1, colors.title, programName):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + local windowActionButtons = window:addWindowActionButtons("windowActionButtons", 2, 2, false) + local sendToDeveloperButton = window:addAdaptiveButton("sendToDeveloperButton", 9, 1, 2, 1, 0x444444, 0xFFFFFF, 0x343434, 0xFFFFFF, MineOSCore.localization.sendFeedback) + local stackTextBox = window:addTextBox("stackTextBox", codeWidth + 1, 4, stackWidth, codeHeight, 0xFFFFFF, 0x000000, string.wrap(MineOSCore.parseErrorMessage(reason, 4), stackWidth - 2), 1, 1, 0) + --Рисуем окошечко, чтобы кодику не было ОБИДНО + --!!1 + window:draw() - --Кнопачки - buttons = GUI.windowActionButtons(x + 1, y + 1, false) - if showSendToDeveloperButton and component.isAvailable("internet") then buttons.sendToDeveloper = GUI.adaptiveButton(x + 8, y, 2, 1, 0x444444, 0xFFFFFF, 0x343434, 0xFFFFFF, MineOSCore.localization.sendFeedback) end - y = y + topbarHeight - - --Кодик + --Кодик на окошечке local strings = {} - local fromString = errorLine - math.floor((codeHeight - 1) / 2) - if fromString < 0 then fromString = 1 end + local fromString = errorLine - math.floor((codeHeight - 1) / 2); if fromString < 0 then fromString = 1 end local toString = fromString + codeHeight - 1 - local file = io.open(path, "r") local lineCounter = 1 for line in file:lines() do @@ -195,11 +221,10 @@ local function drawErrorWindow(path, programVersion, errorLine, reason, showSend lineCounter = lineCounter + 1 end file:close() - syntax.viewCode( { x = x, - y = y, + y = y + 3, width = codeWidth, height = codeHeight, strings = strings, @@ -216,75 +241,58 @@ local function drawErrorWindow(path, programVersion, errorLine, reason, showSend } ) - --Стек - strings = string.wrap(MineOSCore.parseErrorMessage(reason, 4), stackWidth - 2) - x = x + codeWidth - buffer.square(x, y, stackWidth, codeHeight, 0xFFFFFF) - x = x + 1 - for i = 1, #strings do buffer.text(x, y, 0x000000, strings[i]); y = y + 1; if i > codeHeight - 1 then break end end + -- Всякие действия пиздатые + local function exit() + windowActionButtons.close:pressAndRelease() + buffer.setDrawLimit(drawLimit) + window:close() + end + + windowActionButtons.close.onTouch = exit + + window.onKeyDown = function(eventData) + if eventData[4] == 28 then exit() end + end - buffer.draw() - for i = 1, 2 do component.computer.beep(1500, 0.1) end + sendToDeveloperButton.onTouch = function() + local data = ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, + {"EmptyLine"}, + {"CenterText", 0x880000, MineOSCore.localization.sendFeedback}, + {"EmptyLine"}, + {"Input", 0x262626, 0x880000, MineOSCore.localization.yourContacts}, + {"Input", 0x262626, 0x880000, MineOSCore.localization.additionalInfo}, + {"EmptyLine"}, + {"CenterText", 0x880000, MineOSCore.localization.stackTraceback .. ":"}, + {"EmptyLine"}, + {"TextField", 5, 0xFFFFFF, 0x000000, 0xcccccc, 0x3366CC, reason}, + {"Button", {0x999999, 0xffffff, "OK"}, {0x777777, 0xffffff, MineOSCore.localization.cancel}} + ) - --Ивентовая параша - while true do - local e = {event.pull()} - if e[1] == "touch" then - for objectName, button in pairs(buttons) do - if button:isClicked(e[3], e[4]) then - button:press() - if objectName == "close" then - return - elseif objectName == "sendToDeveloper" then - local data = ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, - {"EmptyLine"}, - {"CenterText", 0x880000, MineOSCore.localization.sendFeedback}, - {"EmptyLine"}, - {"Input", 0x262626, 0x880000, MineOSCore.localization.yourContacts}, - {"Input", 0x262626, 0x880000, MineOSCore.localization.additionalInfo}, - {"EmptyLine"}, - {"CenterText", 0x880000, MineOSCore.localization.stackTraceback .. ":"}, - {"EmptyLine"}, - {"TextField", 5, 0xFFFFFF, 0x000000, 0xcccccc, 0x3366CC, reason}, - {"Button", {0x999999, 0xffffff, "OK"}, {0x777777, 0xffffff, MineOSCore.localization.cancel}} - ) - - if data[3] == "OK" then - if component.isAvailable("internet") then - local phpUrl = "http://igortimofeev.wallst.ru/MineOSErrorReports/Report.php" - local url = phpUrl .. - "?path=" .. path .. - "&version=" .. string.optimizeForURLRequests(programVersion) .. - "&userContacts=" .. string.optimizeForURLRequests(data[1]) .. - "&userMessage=" .. string.optimizeForURLRequests(data[2]) .. - "&errorMessage=" .. string.optimizeForURLRequests(reason) - - local success, reason = component.internet.request(url) - if success then - success:close() - else - ecs.error(reason) - end - end - - return - end - end - - break + if data[3] == "OK" then + if component.isAvailable("internet") then + local url = "http://igortimofeev.wallst.ru/MineOSErrorReports/Report.php?path=" .. path .. "&version=" .. string.optimizeForURLRequests(programVersion) .. "&userContacts=" .. string.optimizeForURLRequests(data[1]) .. "&userMessage=" .. string.optimizeForURLRequests(data[2]) .. "&errorMessage=" .. string.optimizeForURLRequests(reason) + local success, reason = component.internet.request(url) + if success then + success:close() + else + ecs.error(reason) end end - elseif e[1] == "key_down" and (e[4] == 28 or e[4] == 57 or e[4] == 14) then - return + exit() end end + + -- Начинаем гомоеблю! + buffer.draw() + for i = 1, 3 do component.computer.beep(1500, 0.08) end + window:handleEvents() end function MineOSCore.safeLaunch(path, ...) local args = {...} local oldResolutionWidth, oldResolutionHeight = component.gpu.getResolution() local finalSuccess, finalReason = true, true - local loadSuccess, loadReason = loadfile(path) + local loadSuccess, loadReason = loadfile(string.canonicalPath("/" .. path)) if fs.exists(path) then if loadSuccess then @@ -308,28 +316,33 @@ function MineOSCore.safeLaunch(path, ...) end if not finalSuccess then - local starting, ending = string.find(finalReason, "%:%d+%:") - --Проверяем, все ли удачно у нас нашлось - строка ошибки и т.п. - if starting and ending then - local errorLine = tonumber(unicode.sub(finalReason, starting + 1, ending - 1)) - path = unicode.sub(finalReason, 1, starting - 1) + finalReason = string.canonicalPath("/" .. finalReason) + local match = string.match(finalReason, "%/[^%:]+%:%d+%:") + if match then + local errorLine = tonumber(unicode.sub(string.match(match, "%:%d+%:"), 2, -2)) + local errorPath = unicode.sub(string.match(match, "%/[^%:]+%:"), 1, -2) + + --print(string.match("bad arg in cyka bla bla /lib/cyka.lua:2013:cykatest in path bin/pidor.lua:31:afa", "%/[^%:%/]+%:%d+%:")) --Проверяем, стоит ли нам врубать отсылку отчетов на мой сервер, ибо это должно быть онли у моих прожек - local applications = files.loadTableFromFile(MineOSCore.paths.applicationList) - local applicationExists = false - local programVersion = "N/A" + local applications, applicationExists, programVersion = table.fromFile(MineOSCore.paths.applicationList), true, "N/A" + -- errorPath = string.canonicalPath(errorPath) - for i = 1, #applications do - if string.canonicalPath("/" .. path) == string.canonicalPath("/" .. applications[i].name) then - applicationExists = true - programVersion = math.doubleToString(applications[i].version, 2) or programVersion - break - end - end + -- for i = 1, #applications do + -- if errorPath == string.canonicalPath("/" .. applications[i].name) then + -- applicationExists = true + -- programVersion = math.doubleToString(applications[i].version, 2) or programVersion + -- break + -- end + -- end - drawErrorWindow(path, programVersion, errorLine, finalReason, applicationExists) + -- ecs.error("EXISTS: " .. tostring(applicationExists)) + -- ecs.error("PATH: " .. errorPath .. ", ERRORLINE: " .. errorLine) + -- ecs.error("REASON: " .. finalReason) + + drawErrorWindow(errorPath, programVersion, errorLine, finalReason, applicationExists) else - GUI.error("Unknown error in lib/MineOSCore.lua: possible reason is \"" .. tostring(finalReason) .. "\"") + GUI.error("Unknown error in lib/MineOSCore.lua due program execution: possible reason is \"" .. tostring(finalReason) .. "\"") end end @@ -350,7 +363,7 @@ function MineOSCore.launchIcon(path, translate) MineOSCore.safeLaunch(path .. "/" .. ecs.hideFileFormat(fs.name(path)) .. ".lua") --Если это папка elseif (fileFormat == "" or fileFormat == nil) and isDirectory then - MineOSCore.safeLaunch("MineOS/Applications/Finder.app/Finder.lua", "open", path) + MineOSCore.safeLaunch("/MineOS/Applications/Finder.app/Finder.lua", "open", path) --Если это обычный луа файл - т.е. скрипт elseif fileFormat == ".lua" or fileFormat == nil then buffer.clear(MineOSCore.colors.background) @@ -366,7 +379,7 @@ function MineOSCore.launchIcon(path, translate) MineOSCore.safeLaunch("MineOS/Applications/3DPrint.app/3DPrint.lua open " .. path) --Если это текст или конфиг или языковой - elseif fileFormat == ".txt" or fileFormat == ".cfg" or fileFormat == ".MineOSCore.localization" then + elseif fileFormat == ".txt" or fileFormat == ".cfg" or fileFormat == ".lang" then ecs.prepareToExit() MineOSCore.safeLaunch("bin/edit.lua", path) @@ -453,7 +466,7 @@ function MineOSCore.iconRightClick(icon, oldPixelsOfIcon, eventData, fileFormat, -- Разные контекстные меню if fs.isDirectory(icon.path) then if fileFormat == ".app" then - action = context.menu(eventData[3], eventData[4], + action = GUI.contextMenu(eventData[3], eventData[4], {MineOSCore.localization.contextMenuShowPackageContent}, "-", {MineOSCore.localization.contextMenuCut}, @@ -464,11 +477,11 @@ function MineOSCore.iconRightClick(icon, oldPixelsOfIcon, eventData, fileFormat, -- "-", -- {MineOSCore.localization.contextMenuUploadToPastebin, true}, "-", - {MineOSCore.localization.contextMenuAddToDock, not somethingCanBeAddedToDock}, + {MineOSCore.localization.contextMenuAddToDock}, {MineOSCore.localization.contextMenuDelete} - ) + ):show() else - action = context.menu(eventData[3], eventData[4], + action = GUI.contextMenu(eventData[3], eventData[4], {MineOSCore.localization.contextMenuCut}, {MineOSCore.localization.contextMenuCopy}, {MineOSCore.localization.contextMenuRename}, @@ -477,11 +490,11 @@ function MineOSCore.iconRightClick(icon, oldPixelsOfIcon, eventData, fileFormat, {MineOSCore.localization.contextMenuArchive}, "-", {MineOSCore.localization.contextMenuDelete} - ) + ):show() end else if fileFormat == ".pic" then - action = context.menu(eventData[3], eventData[4], + action = GUI.contextMenu(eventData[3], eventData[4], -- {MineOSCore.localization.contextMenuEdit}, {MineOSCore.localization.contextMenuEditInPhotoshop}, {MineOSCore.localization.contextMenuSetAsWallpaper}, @@ -493,11 +506,11 @@ function MineOSCore.iconRightClick(icon, oldPixelsOfIcon, eventData, fileFormat, -- "-", -- {MineOSCore.localization.contextMenuUploadToPastebin, true}, "-", - {MineOSCore.localization.contextMenuAddToDock, not somethingCanBeAddedToDock}, + {MineOSCore.localization.contextMenuAddToDock}, {MineOSCore.localization.contextMenuDelete, false} - ) + ):show() else - action = context.menu(eventData[3], eventData[4], + action = GUI.contextMenu(eventData[3], eventData[4], {MineOSCore.localization.contextMenuEdit}, -- {MineOSCore.localization.contextMenuCreateApplication}, "-", @@ -508,9 +521,9 @@ function MineOSCore.iconRightClick(icon, oldPixelsOfIcon, eventData, fileFormat, -- "-", -- {MineOSCore.localization.contextMenuUploadToPastebin, true}, "-", - {MineOSCore.localization.contextMenuAddToDock, not somethingCanBeAddedToDock}, + {MineOSCore.localization.contextMenuAddToDock}, {MineOSCore.localization.contextMenuDelete} - ) + ):show() end end @@ -568,8 +581,11 @@ function MineOSCore.iconRightClick(icon, oldPixelsOfIcon, eventData, fileFormat, -- drawAll(true) elseif action == MineOSCore.localization.contextMenuSetAsWallpaper then --ecs.error(path) - ecs.createShortCut("MineOS/System/OS/Wallpaper.lnk", icon.path) + local wallpaperPath = "MineOS/System/OS/Wallpaper.lnk" + fs.remove(wallpaperPath) + ecs.createShortCut(wallpaperPath, icon.path) computer.pushSignal("OSWallpaperChanged") + executeMethod(drawAllMethod) return true -- buffer.paste(1, 1, oldPixelsOfFullScreen) -- buffer.draw() @@ -578,6 +594,10 @@ function MineOSCore.iconRightClick(icon, oldPixelsOfIcon, eventData, fileFormat, executeMethod(drawAllMethod) -- getFileList(workPathHistory[currentWorkPathHistoryElement]) -- drawAll() + elseif action == MineOSCore.localization.contextMenuAddToDock then + table.insert(_G.OSSettings.dockShortcuts, {path = icon.path}) + ecs.saveOSSettings() + executeMethod(fullRefreshMethod) else buffer.paste(icon.x, icon.y, oldPixelsOfIcon) buffer.draw() @@ -599,7 +619,13 @@ function MineOSCore.iconClick(icon, eventData, selectionColor, selectionTranspar end function MineOSCore.emptyZoneClick(eventData, workPath, drawAllMethod, fullRefreshMethod) - local action = context.menu(eventData[3], eventData[4], {MineOSCore.localization.contextMenuNewFile}, {MineOSCore.localization.contextMenuNewFolder}, {MineOSCore.localization.contextMenuNewApplication}, "-", {MineOSCore.localization.contextMenuPaste, (_G.clipboard == nil)}) + local action = GUI.contextMenu(eventData[3], eventData[4], + {MineOSCore.localization.contextMenuNewFile}, + {MineOSCore.localization.contextMenuNewFolder}, + {MineOSCore.localization.contextMenuNewApplication}, + "-", + {MineOSCore.localization.contextMenuPaste, (_G.clipboard == nil)} + ):show() if action == MineOSCore.localization.contextMenuNewFile then ecs.newFile(workPath) executeMethod(fullRefreshMethod) diff --git a/lib/advancedLua.lua b/lib/advancedLua.lua old mode 100644 new mode 100755 index 95c6c539..f57609de --- a/lib/advancedLua.lua +++ b/lib/advancedLua.lua @@ -1,7 +1,7 @@ --[[ - Advanced Lua Library v1.0 by ECS + Advanced Lua Library v1.1 by ECS This library extends a lot of default Lua methods and adds some really cool features that haven't been @@ -13,6 +13,35 @@ _G.filesystem = _G.filesystem or require("filesystem") _G.unicode = _G.unicode or require("unicode") +-------------------------------------------------- System extensions -------------------------------------------------- + +function _G.getCurrentScript() + local runLevel, info = 0 + while true do + info = debug.getinfo(runLevel) + if info then + if info.what == "main" and fs.exists(info.short_src) then return info.short_src end + else + error("Failed to get running script: current runLevel is " .. runLevel) + end + + runLevel = runLevel + 1 + end +end + +function enum(...) + local args, enums = {...}, {} + for i = 1, #args do + if type(args[i]) ~= "string" then error("Function argument " .. i .. " have non-string type: " .. type(args[i])) end + enums[args[i]] = i + end + return enums +end + +function swap(a, b) + return b, a +end + -------------------------------------------------- Math extensions -------------------------------------------------- function math.round(num) @@ -25,12 +54,12 @@ function math.roundToDecimalPlaces(num, decimalPlaces) end function math.doubleToString(num, digitCount) - return string.format("%." .. digitCount or 1 .. "f", num) + return string.format("%." .. (digitCount or 1) .. "f", num) end -------------------------------------------------- Table extensions -------------------------------------------------- -local function doSerialize(array, text, prettyLook, indentationSymbol, oldIndentationSymbol, equalsSymbol) +local function doSerialize(array, text, prettyLook, indentationSymbol, oldIndentationSymbol, equalsSymbol, currentRecusrionStack, recursionStackLimit) text = {"{"} table.insert(text, (prettyLook and "\n" or nil)) @@ -51,15 +80,20 @@ local function doSerialize(array, text, prettyLook, indentationSymbol, oldIndent table.insert(text, stringValue) table.insert(text, "\"") elseif valueType == "table" then - table.insert(text, table.concat(doSerialize(value, text, prettyLook, table.concat({indentationSymbol, indentationSymbol}), table.concat({oldIndentationSymbol, indentationSymbol}), equalsSymbol))) + -- Ограничение стека рекурсии + if currentRecusrionStack < recursionStackLimit then + table.insert(text, table.concat(doSerialize(value, text, prettyLook, table.concat({indentationSymbol, indentationSymbol}), table.concat({oldIndentationSymbol, indentationSymbol}), equalsSymbol, currentRecusrionStack + 1, recursionStackLimit))) + else + table.insert(text, "...") + end else - error("Unsupported table value type: " .. valueType) + -- error("Unsupported table value type: " .. valueType) end table.insert(text, ",") table.insert(text, (prettyLook and "\n" or nil)) else - error("Unsupported table key type: " .. keyType) + -- error("Unsupported table key type: " .. keyType) end end @@ -69,12 +103,12 @@ local function doSerialize(array, text, prettyLook, indentationSymbol, oldIndent return text end -function table.serialize(array, prettyLook, indentationWidth, indentUsingTabs) +function table.serialize(array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit) checkArg(1, array, "table") indentationWidth = indentationWidth or 2 local indentationSymbol = indentUsingTabs and " " or " " indentationSymbol, indentationSymbolHalf = string.rep(indentationSymbol, indentationWidth) - return table.concat(doSerialize(array, {}, prettyLook, indentationSymbol, "", prettyLook and " = " or "=")) + return table.concat(doSerialize(array, {}, prettyLook, indentationSymbol, "", prettyLook and " = " or "=", 1, recursionStackLimit or math.huge)) end function table.unserialize(serializedString) @@ -83,12 +117,20 @@ function table.unserialize(serializedString) if success then return result else return nil, result end end -function table.toFile(path, array, prettyLook, indentationWidth, indentUsingTabs, appendToFile) +function table.toString(...) + return table.serialize(...) +end + +function table.fromString(...) + return table.unserialize(...) +end + +function table.toFile(path, array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit, appendToFile) checkArg(1, path, "string") checkArg(2, array, "table") filesystem.makeDirectory(filesystem.path(path) or "") local file = io.open(path, appendToFile and "a" or "w") - file:write(table.serialize(array, prettyLook, indentationWidth, indentUsingTabs)) + file:write(table.serialize(array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit)) file:close() end @@ -150,8 +192,8 @@ function table.binarySearch(t, requestedValue) end function table.size(t) - local size = 0 - for key, value in pairs(t) do size = size + 1 end + local size = #t + if size == 0 then for key in pairs(t) do size = size + 1 end end return size end @@ -169,9 +211,9 @@ end function string.optimizeForURLRequests(code) if code then - code = string.gsub(code, "([^%w ])", function (c) - return string.format("%%%02X", string.byte(c)) - end) + code = string.gsub(code, "([^%w ])", function (c) + return string.format("%%%02X", string.byte(c)) + end) code = string.gsub(code, " ", "+") end return code @@ -275,10 +317,6 @@ end -- return safeCall(load(str)) -- end --- local cyka = table.copy({123, 542, {abc = true, 16, 32, {cyka = false, haha = "abc"}}}) --- print(table.serialize(cyka, true)) - - -- print(safeCallString("return 123")) ------------------------------------------------------------------------------------------------------------------ diff --git a/lib/colorlib.lua b/lib/colorlib.lua old mode 100644 new mode 100755 index 0ca379a8..1134ffe2 --- a/lib/colorlib.lua +++ b/lib/colorlib.lua @@ -1,9 +1,5 @@ local colorlib = {} local serialization = require("serialization") ---utils -local function check(tVal, tMaxVal, tMinVal, tType) - -end local function isNan(x) return x~=x @@ -11,7 +7,7 @@ end --RGB model function colorlib.HEXtoRGB(color) - color = math.ceil(color) + color = math.floor(color) local rr = bit32.rshift( color, 16 ) local gg = bit32.rshift( bit32.band(color, 0x00ff00), 8 ) @@ -47,7 +43,7 @@ function colorlib.RGBtoHSB(rr, gg, bb) end function colorlib.HSBtoRGB(h, s, v) - if h >359 then h = 0 end + if h > 359 then h = 0 end local rr, gg, bb = 0, 0, 0 local const = 255 @@ -68,7 +64,7 @@ function colorlib.HSBtoRGB(h, s, v) if ( i == 4 ) then rr, gg, bb = t, p, v end if ( i == 5 ) then rr, gg, bb = v, p, q end - return rr*const, gg*const, bb*const + return math.floor(rr * const), math.floor(gg * const), math.floor(bb * const) end function colorlib.HEXtoHSB(color) @@ -131,9 +127,9 @@ local openComputersPalette = { 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, possibleChannelValues = { - r = { 0x00, 0x0F, 0x1E, 0x2D, 0x33, 0x3C, 0x4B, 0x5A, 0x66, 0x69, 0x78, 0x87, 0x96, 0x99, 0xA5, 0xB4, 0xC3, 0xCC, 0xD2, 0xE1, 0xF0, 0xFF }, - g = { 0x00, 0x0F, 0x1E, 0x24, 0x2D, 0x3C, 0x49, 0x4B, 0x5A, 0x69, 0x6D, 0x78, 0x87, 0x92, 0x96, 0xA5, 0xB4, 0xB6, 0xC3, 0xD2, 0xDB, 0xE1, 0xF0, 0xFF }, - b = { 0x00, 0x0F, 0x1E, 0x2D, 0x3C, 0x40, 0x4B, 0x5A, 0x69, 0x78, 0x80, 0x87, 0x96, 0xA5, 0xB4, 0xBF, 0xC3, 0xD2, 0xE1, 0xF0, 0xFF }, + r = { 0x00, 0x0F, 0x1E, 0x2D, 0x33, 0x3C, 0x4B, 0x5A, 0x66, 0x69, 0x78, 0x87, 0x96, 0x99, 0xA5, 0xB4, 0xC3, 0xCC, 0xD2, 0xE1, 0xF0, 0xFF }, -- 22 + g = { 0x00, 0x0F, 0x1E, 0x24, 0x2D, 0x3C, 0x49, 0x4B, 0x5A, 0x69, 0x6D, 0x78, 0x87, 0x92, 0x96, 0xA5, 0xB4, 0xB6, 0xC3, 0xD2, 0xDB, 0xE1, 0xF0, 0xFF }, -- 24 + b = { 0x00, 0x0F, 0x1E, 0x2D, 0x3C, 0x40, 0x4B, 0x5A, 0x69, 0x78, 0x80, 0x87, 0x96, 0xA5, 0xB4, 0xBF, 0xC3, 0xD2, 0xE1, 0xF0, 0xFF }, -- 21 } } @@ -157,7 +153,6 @@ local function getClosestChannelValue(channelName, startIndex, endIndex, request end function colorlib.convert24BitTo8Bit(hex24) - local encodedIndex local r, g, b = colorlib.HEXtoRGB(hex24) local rClosest = getClosestChannelValue("r", 1, #openComputersPalette.possibleChannelValues.r, r) @@ -167,12 +162,11 @@ function colorlib.convert24BitTo8Bit(hex24) for i = 1, #openComputersPalette do if openComputersPalette[i] == hexFinal then - encodedIndex = i - break + return i end end - return encodedIndex - 1 + error("Failed to compress color from 24 bit to 8 bit: value \"" .. string.format("%06X", hexFinal) .. "\" not found in palette") end function colorlib.convert8BitTo24Bit(hex8) diff --git a/lib/doubleBuffering.lua b/lib/doubleBuffering.lua old mode 100644 new mode 100755 index 4f498aa8..1b7e85e4 --- a/lib/doubleBuffering.lua +++ b/lib/doubleBuffering.lua @@ -1,65 +1,59 @@ --- Адаптивная загрузка необходимых библиотек и компонентов local libraries = { - ["component"] = "component", - ["unicode"] = "unicode", - ["image"] = "image", - ["colorlib"] = "colorlib", + component = "component", + unicode = "unicode", + image = "image", + colorlib = "colorlib", } for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end; libraries = nil local buffer = {} -local debug = false -local sizeOfPixelData = 3 ------------------------------------------------- Вспомогательные методы ----------------------------------------------------------------- --Формула конвертации индекса массива изображения в абсолютные координаты пикселя изображения local function convertIndexToCoords(index) --Приводим индекс к корректному виду (1 = 1, 4 = 2, 7 = 3, 10 = 4, 13 = 5, ...) - index = (index + sizeOfPixelData - 1) / sizeOfPixelData + index = (index + 2) / 3 --Получаем остаток от деления индекса на ширину изображения local ostatok = index % buffer.screen.width --Если остаток равен 0, то х равен ширине изображения, а если нет, то х равен остатку local x = (ostatok == 0) and buffer.screen.width or ostatok --А теперь как два пальца получаем координату по Y local y = math.ceil(index / buffer.screen.width) - --Очищаем остаток из оперативки - ostatok = nil --Возвращаем координаты return x, y end --Формула конвертации абсолютных координат пикселя изображения в индекс для массива изображения local function convertCoordsToIndex(x, y) - return (buffer.screen.width * (y - 1) + x) * sizeOfPixelData - sizeOfPixelData + 1 -end - -local function printDebug(line, text) - if debug then - ecs.square(1, line, buffer.screen.width, 1, 0x262626) - ecs.colorText(2, line, 0xFFFFFF, text) - end + return (buffer.screen.width * (y - 1) + x) * 3 - 2 end -- Установить ограниченную зону рисования. Все пиксели, не попадающие в эту зону, будут игнорироваться. -function buffer.setDrawLimit(x, y, width, height) - buffer.drawLimit = { x = x, y = y, x2 = x + width - 1, y2 = y + height - 1 } +function buffer.setDrawLimit(xOrPasteArray, y, width, height) + if type(xOrPasteArray) == "table" then + buffer.drawLimit.x, buffer.drawLimit.y, buffer.drawLimit.x2, buffer.drawLimit.y2, buffer.drawLimit.width, buffer.drawLimit.height = xOrPasteArray.x, xOrPasteArray.y, xOrPasteArray.x2, xOrPasteArray.y2, xOrPasteArray.width, xOrPasteArray.height + else + buffer.drawLimit.x, buffer.drawLimit.y, buffer.drawLimit.x2, buffer.drawLimit.y2, buffer.drawLimit.width, buffer.drawLimit.height = xOrPasteArray, y, xOrPasteArray + width - 1, y + height - 1, width, height + end end -- Удалить ограничение зоны рисования, по умолчанию она будет от 1х1 до координат размера экрана. function buffer.resetDrawLimit() - buffer.drawLimit = {x = 1, y = 1, x2 = buffer.screen.width, y2 = buffer.screen.height} + buffer.drawLimit.x, buffer.drawLimit.y, buffer.drawLimit.x2, buffer.drawLimit.y2, buffer.drawLimit.width, buffer.drawLimit.height = 1, 1, buffer.screen.width, buffer.screen.height, buffer.screen.width, buffer.screen.height end --- Создать массив буфера с базовыми переменными и базовыми цветами. Т.е. черный фон, белый текст. -function buffer.start() - buffer.screen = {} - buffer.screen.current = {} - buffer.screen.new = {} - buffer.screen.width, buffer.screen.height = component.gpu.getResolution() +-- Cкопировать ограничение зоны рисования в виде отдельного массива +function buffer.getDrawLimit() + return { x = buffer.drawLimit.x, y = buffer.drawLimit.y, x2 = buffer.drawLimit.x2, y2 = buffer.drawLimit.y2, width = buffer.drawLimit.width, height = buffer.drawLimit.height } +end +-- Создание массивов буфера и всех необходимых параметров +function buffer.flush(width, height) + buffer.screen = {current = {}, new = {}, width = width, height = height} + buffer.drawLimit = {} buffer.resetDrawLimit() for y = 1, buffer.screen.height do @@ -75,6 +69,17 @@ function buffer.start() end end +-- Инициализация буфера со всеми необходимыми параметрами, вызывается автоматически +function buffer.start() + buffer.flush(component.gpu.getResolution()) +end + +-- Изменение разрешения экрана и пересоздание массивов буфера +function buffer.changeResolution(width, height) + component.gpu.setResolution(width, height) + buffer.flush(width, height) +end + ------------------------------------------------- Методы отрисовки ----------------------------------------------------------------- -- Получить информацию о пикселе из буфера @@ -83,7 +88,8 @@ function buffer.get(x, y) if x >= 1 and y >= 1 and x <= buffer.screen.width and y <= buffer.screen.height then return buffer.screen.new[index], buffer.screen.new[index + 1], buffer.screen.new[index + 2] else - error("Невозможно получить указанные значения, так как указанные координаты лежат за пределами экрана.\n") + return 0x000000, 0x000000, " " + -- error("Невозможно получить пиксель, так как его координаты лежат за пределами экрана: x = " .. x .. ", y = " .. y .. "\n") end end @@ -98,32 +104,37 @@ function buffer.set(x, y, background, foreground, symbol) end --Нарисовать квадрат -function buffer.square(x, y, width, height, background, foreground, symbol, transparency) - local index, indexPlus1, indexPlus2 - if transparency then transparency = transparency * 2.55 end +function buffer.square(x, y, width, height, background, foreground, symbol, transparency) + if transparency then + if transparency == 0 then + transparency = nil + else + transparency = transparency * 2.55 + end + end if not foreground then foreground = 0x000000 end if not symbol then symbol = " " end - -- if symbol == " " then foreground = 0x000000 elseif not symbol then symbol = " " end - + + local index, indexStepForward, indexPlus1 = convertCoordsToIndex(x, y), (buffer.screen.width - width) * 3 for j = y, (y + height - 1) do for i = x, (x + width - 1) do if i >= buffer.drawLimit.x and j >= buffer.drawLimit.y and i <= buffer.drawLimit.x2 and j <= buffer.drawLimit.y2 then - index = convertCoordsToIndex(i, j) indexPlus1 = index + 1 - indexPlus2 = index + 2 - if transparency then buffer.screen.new[index] = colorlib.alphaBlend(buffer.screen.new[index], background, transparency) buffer.screen.new[indexPlus1] = colorlib.alphaBlend(buffer.screen.new[indexPlus1], background, transparency) else buffer.screen.new[index] = background buffer.screen.new[indexPlus1] = foreground - buffer.screen.new[indexPlus2] = symbol + buffer.screen.new[index + 2] = symbol end end + index = index + 3 end + index = index + indexStepForward end end +buffer.rectangle = buffer.square --Очистка экрана, по сути более короткая запись buffer.square function buffer.clear(color, transparency) @@ -241,7 +252,7 @@ function buffer.paste(x, y, copyArray) index = convertCoordsToIndex(i, j) --Копипаст формулы, аккуратнее! --Рассчитываем индекс массива вставочного изображения - arrayIndex = (copyArray.width * (j - y) + (i - x + 1)) * sizeOfPixelData - sizeOfPixelData + 1 + arrayIndex = (copyArray.width * (j - y) + (i - x + 1)) * 3 - 2 --Вставляем данные buffer.screen.new[index] = copyArray[arrayIndex] buffer.screen.new[index + 1] = copyArray[arrayIndex + 1] @@ -282,44 +293,53 @@ end -- Отрисовка текста, подстраивающегося под текущий фон function buffer.text(x, y, color, text, transparency) - local index - if transparency then transparency = transparency * 2.55 end - local sText = unicode.len(text) + if transparency then + if transparency == 0 then + transparency = nil + else + transparency = transparency * 2.55 + end + end + + local index, sText = convertCoordsToIndex(x, y), unicode.len(text) for i = 1, sText do - if (x + i - 1) >= buffer.drawLimit.x and y >= buffer.drawLimit.y and (x + i - 1) <= buffer.drawLimit.x2 and y <= buffer.drawLimit.y2 then - index = convertCoordsToIndex(x + i - 1, y) + if x >= buffer.drawLimit.x and y >= buffer.drawLimit.y and x <= buffer.drawLimit.x2 and y <= buffer.drawLimit.y2 then buffer.screen.new[index + 1] = not transparency and color or colorlib.alphaBlend(buffer.screen.new[index], color, transparency) buffer.screen.new[index + 2] = unicode.sub(text, i, i) end + index = index + 3 + x = x + 1 end end -- Отрисовка изображения function buffer.image(x, y, picture) - local xPos, xEnd = x, x + picture.width - 1 + local xPos, xEnd, bufferIndexStepOnReachOfImageWidth = x, x + picture.width - 1, (buffer.screen.width - picture.width) * 3 local bufferIndex = convertCoordsToIndex(x, y) - local bufferIndexIterationStep = (buffer.screen.width - picture.width) * 3 + local imageIndexPlus2, imageIndexPlus3 for imageIndex = 1, #picture, 4 do if xPos >= buffer.drawLimit.x and y >= buffer.drawLimit.y and xPos <= buffer.drawLimit.x2 and y <= buffer.drawLimit.y2 then - --Фон и его прозрачность - if picture[imageIndex + 2] == 0x00 then + imageIndexPlus2, imageIndexPlus3 = imageIndex + 2, imageIndex + 3 + -- Ебля с прозрачностью + if picture[imageIndexPlus2] == 0x00 then buffer.screen.new[bufferIndex] = picture[imageIndex] - else - buffer.screen.new[bufferIndex] = colorlib.alphaBlend(buffer.screen.new[bufferIndex], picture[imageIndex], picture[imageIndex + 2]) + buffer.screen.new[bufferIndex + 1] = picture[imageIndex + 1] + buffer.screen.new[bufferIndex + 2] = picture[imageIndexPlus3] + elseif picture[imageIndexPlus2] > 0x00 and picture[imageIndexPlus2] < 0xFF then + buffer.screen.new[bufferIndex] = colorlib.alphaBlend(buffer.screen.new[bufferIndex], picture[imageIndex], picture[imageIndexPlus2]) + buffer.screen.new[bufferIndex + 1] = picture[imageIndex + 1] + buffer.screen.new[bufferIndex + 2] = picture[imageIndexPlus3] + elseif picture[imageIndexPlus2] == 0xFF and picture[imageIndexPlus3] ~= " " then + buffer.screen.new[bufferIndex + 1] = picture[imageIndex + 1] + buffer.screen.new[bufferIndex + 2] = picture[imageIndexPlus3] end - --Цвет символа - buffer.screen.new[bufferIndex + 1] = picture[imageIndex + 1] - --Символ - buffer.screen.new[bufferIndex + 2] = picture[imageIndex + 3] end --Корректируем координаты и индексы xPos = xPos + 1 bufferIndex = bufferIndex + 3 - if xPos > xEnd then - xPos, y, bufferIndex = x, y + 1, bufferIndex + bufferIndexIterationStep - end + if xPos > xEnd then xPos, y, bufferIndex = x, y + 1, bufferIndex + bufferIndexStepOnReachOfImageWidth end end end @@ -404,18 +424,14 @@ end -- Прамоугольная рамочка function buffer.frame(x, y, width, height, color) - local stringUp = "┌" .. string.rep("─", width - 2) .. "┐" - local stringDown = "└" .. string.rep("─", width - 2) .. "┘" - - buffer.text(x, y, color, stringUp) - buffer.text(x, y + height - 1, color, stringDown) - - local yPos = 1 + local stringUp, stringDown, x2 = "┌" .. string.rep("─", width - 2) .. "┐", "└" .. string.rep("─", width - 2) .. "┘", x + width - 1 + buffer.text(x, y, color, stringUp); y = y + 1 for i = 1, (height - 2) do - buffer.text(x, y + yPos, color, "│") - buffer.text(x + width - 1, y + yPos, color, "│") - yPos = yPos + 1 + buffer.text(x, y, color, "│") + buffer.text(x2, y, color, "│") + y = y + 1 end + buffer.text(x, y, color, stringDown) end -- Кнопка в виде текста в рамке @@ -429,6 +445,56 @@ function buffer.framedButton(x, y, width, height, backColor, buttonColor, text) buffer.text(x, y, buttonColor, text) end +------------------------------------------- Полупиксельные методы ------------------------------------------------------------------------ + +local function semiPixelAdaptiveSet(y, index, color, yPercentTwoEqualsZero) + local upperPixel, lowerPixel, bothPixel, indexPlus1, indexPlus2 = "▀", "▄", " ", index + 1, index + 2 + local background, foreground, symbol = buffer.screen.new[index], buffer.screen.new[indexPlus1], buffer.screen.new[indexPlus2] + + if yPercentTwoEqualsZero then + if symbol == upperPixel then + buffer.screen.new[index], buffer.screen.new[indexPlus1], buffer.screen.new[indexPlus2] = color, foreground, bothPixel + else + buffer.screen.new[index], buffer.screen.new[indexPlus1], buffer.screen.new[indexPlus2] = background, color, lowerPixel + end + else + if symbol == lowerPixel then + buffer.screen.new[index], buffer.screen.new[indexPlus1], buffer.screen.new[indexPlus2] = color, foreground, bothPixel + else + buffer.screen.new[index], buffer.screen.new[indexPlus1], buffer.screen.new[indexPlus2] = background, color, upperPixel + end + end +end + +function buffer.semiPixelSet(x, y, color) + local yFixed = math.ceil(y / 2) + if x >= buffer.drawLimit.x and yFixed >= buffer.drawLimit.y and x <= buffer.drawLimit.x2 and yFixed <= buffer.drawLimit.y2 then + semiPixelAdaptiveSet(y, convertCoordsToIndex(x, yFixed), color, y % 2 == 0) + end +end + +function buffer.semiPixelSquare(x, y, width, height, color) + -- for j = y, y + height - 1 do for i = x, x + width - 1 do buffer.semiPixelSet(i, j, color) end end + local index, indexStepForward, indexStepBackward, jPercentTwoEqualsZero, jFixed = convertCoordsToIndex(x, math.ceil(y / 2)), (buffer.screen.width - width) * 3, width * 3 + for j = y, y + height - 1 do + jPercentTwoEqualsZero = j % 2 == 0 + + for i = x, x + width - 1 do + jFixed = math.ceil(j / 2) + if x >= buffer.drawLimit.x and jFixed >= buffer.drawLimit.y and x <= buffer.drawLimit.x2 and jFixed <= buffer.drawLimit.y2 then + semiPixelAdaptiveSet(j, index, color, jPercentTwoEqualsZero) + end + index = index + 3 + end + + if jPercentTwoEqualsZero then + index = index + indexStepForward + else + index = index - indexStepBackward + end + end +end + ------------------------------------------- Просчет изменений и отрисовка ------------------------------------------------------------------------ --Функция рассчитывает изменения и применяет их, возвращая то, что было изменено @@ -465,82 +531,80 @@ end --Функция группировки изменений и их отрисовки на экран function buffer.draw(force) --Необходимые переменные, дабы не создавать их в цикле и не генерировать конструкторы - local somethingIsChanged, index, indexPlus1, indexPlus2, massiv, x, y + local somethingIsChanged, index, indexPlus1, indexPlus2, sameCharArray --Массив третьего буфера, содержащий в себе измененные пиксели - buffer.screen.changes = {} - - --Перебираем содержимое нашего буфера по X и Y - for y = 1, buffer.screen.height do - x = 1 - while x <= buffer.screen.width do - --Получаем индекс массива из координат, уменьшая нагрузку на CPU - index = convertCoordsToIndex(x, y) - indexPlus1 = index + 1 - indexPlus2 = index + 2 + buffer.screen.changes, indexStepOnEveryLine = {}, (buffer.screen.width - buffer.drawLimit.width) * 3 + + index = convertCoordsToIndex(buffer.drawLimit.x, buffer.drawLimit.y) + for y = buffer.drawLimit.y, buffer.drawLimit.y2 do + local x = buffer.drawLimit.x + while x <= buffer.drawLimit.x2 do + --Чутка оптимизируем рассчеты + indexPlus1, indexPlus2 = index + 1, index + 2 --Получаем изменения и применяем их somethingIsChanged = buffer.calculateDifference(index) - --Если хоть что-то изменилось, то начинаем работу if somethingIsChanged or force then - --Оптимизация by Krutoy, создаем массив, в который заносим чарсы. Работает быстрее, чем конкатенейт строк - massiv = { buffer.screen.current[indexPlus2] } + sameCharArray = { buffer.screen.current[indexPlus2] } --Загоняем в наш чарс-массив одинаковые пиксели справа, если таковые имеются - local iIndex - local i = x + 1 - while i <= buffer.screen.width do - iIndex = convertCoordsToIndex(i, y) + local xCharCheck, indexCharCheck = x + 1, index + 3 + while xCharCheck <= buffer.drawLimit.x2 do + indexCharCheckPlus2 = indexCharCheck + 2 if - buffer.screen.current[index] == buffer.screen.new[iIndex] and + buffer.screen.current[index] == buffer.screen.new[indexCharCheck] + and ( - buffer.screen.new[iIndex + 2] == " " + buffer.screen.new[indexCharCheckPlus2] == " " or - buffer.screen.current[indexPlus1] == buffer.screen.new[iIndex + 1] + buffer.screen.current[indexPlus1] == buffer.screen.new[indexCharCheck + 1] ) then - buffer.calculateDifference(iIndex) - table.insert(massiv, buffer.screen.current[iIndex + 2]) + buffer.calculateDifference(indexCharCheck) + table.insert(sameCharArray, buffer.screen.current[indexCharCheckPlus2]) else break end - i = i + 1 + indexCharCheck = indexCharCheck + 3 + xCharCheck = xCharCheck + 1 end --Заполняем третий буфер полученными данными buffer.screen.changes[buffer.screen.current[indexPlus1]] = buffer.screen.changes[buffer.screen.current[indexPlus1]] or {} buffer.screen.changes[buffer.screen.current[indexPlus1]][buffer.screen.current[index]] = buffer.screen.changes[buffer.screen.current[indexPlus1]][buffer.screen.current[index]] or {} - table.insert(buffer.screen.changes[buffer.screen.current[indexPlus1]][buffer.screen.current[index]], index) - table.insert(buffer.screen.changes[buffer.screen.current[indexPlus1]][buffer.screen.current[index]], table.concat(massiv)) + table.insert(buffer.screen.changes[buffer.screen.current[indexPlus1]][buffer.screen.current[index]], x) + table.insert(buffer.screen.changes[buffer.screen.current[indexPlus1]][buffer.screen.current[index]], y) + table.insert(buffer.screen.changes[buffer.screen.current[indexPlus1]][buffer.screen.current[index]], table.concat(sameCharArray)) --Смещаемся по иксу вправо - x = x + #massiv - 1 + index = index + #sameCharArray * 3 - 3 + x = x + #sameCharArray - 1 end + index = index + 3 x = x + 1 end + + index = index + indexStepOnEveryLine end --Сбрасываем переменные на невозможное значение цвета, чтобы не багнуло - index, indexPlus1 = -math.huge, -math.huge + local currentBackground, currentForeground = -math.huge, -math.huge --Перебираем все цвета текста и фона, выполняя гпу-операции for foreground in pairs(buffer.screen.changes) do - if indexPlus1 ~= foreground then component.gpu.setForeground(foreground); indexPlus1 = foreground end + if currentForeground ~= foreground then component.gpu.setForeground(foreground); currentForeground = foreground end for background in pairs(buffer.screen.changes[foreground]) do - if index ~= background then component.gpu.setBackground(background); index = background end - - for i = 1, #buffer.screen.changes[foreground][background], 2 do - --Конвертируем указанный индекс в координаты - x, y = convertIndexToCoords(buffer.screen.changes[foreground][background][i]) - --Выставляем ту самую собранную строку из одинаковых цветов - component.gpu.set(x, y, buffer.screen.changes[foreground][background][i + 1]) + if currentBackground ~= background then component.gpu.setBackground(background); currentBackground = background end + for i = 1, #buffer.screen.changes[foreground][background], 3 do + component.gpu.set(buffer.screen.changes[foreground][background][i], buffer.screen.changes[foreground][background][i + 1], buffer.screen.changes[foreground][background][i + 2]) end end end - --Очищаем память, ибо незачем нам хранить третий буфер + --Очищаем память, ибо на кой хер нам хранить третий буфер buffer.screen.changes = nil end @@ -548,6 +612,17 @@ end buffer.start() +-- ecs.prepareToExit() +-- buffer.clear(0xFF8888) + +-- -- buffer.square(2, 2, 10, 5, 0xFFFFFF, 0x000000, " ") +-- -- buffer.square(5, 4, 10, 5, 0x000000, 0x000000, " ") +-- -- buffer.square(20, 4, 10, 5, 0xAAAAAA, 0x000000, " ") + +-- buffer.semiPixelSquare(3, 3, 30, 30, 0x880088) + +-- buffer.draw() + ------------------------------------------------------------------------------------------------------ return buffer diff --git a/lib/doubleHeight.lua b/lib/doubleHeight.lua old mode 100644 new mode 100755 index c60db4bd..74aad3a3 --- a/lib/doubleHeight.lua +++ b/lib/doubleHeight.lua @@ -2,79 +2,49 @@ if not _G.buffer then _G.buffer = require("doubleBuffering") end local doubleHeight = {} -local upperPixel = "▀" -local lowerPixel = "▄" +------------------------------------------------------------------------------------------------------------------------------------------ + +function doubleHeight.line(x0, y0, x1, y1, color) + local steep = false; + + if math.abs(x0 - x1) < math.abs(y0 - y1 ) then + x0, y0 = swap(x0, y0) + x1, y1 = swap(x1, y1) + steep = true; + end + + if (x0 > x1) then + x0, x1 = swap(x0, x1) + y0, y1 = swap(y0, y1) + end + + local dx = x1 - x0; + local dy = y1 - y0; + local derror2 = math.abs(dy) * 2 + local error2 = 0; + local y = y0; + + for x = x0, x1, 1 do + if steep then + buffer.semiPixelSet(y, x, color); + else + buffer.semiPixelSet(x, y, color) + end + + error2 = error2 + derror2; + + if error2 > dx then + y = y + (y1 > y0 and 1 or -1); + error2 = error2 - dx * 2; + end + end +end ------------------------------------------------------------------------------------------------------------------------------------------ -function doubleHeight.set(x, y, color) - if x >= 1 and x <= buffer.screen.width and y >= 1 and y <= buffer.screen.height * 2 then - local yFixed = math.ceil(y / 2) - local background, foreground, symbol = buffer.get(x, yFixed) - - if y % 2 == 0 then - if symbol == upperPixel then - buffer.set(x, yFixed, color, foreground, upperPixel) - else - buffer.set(x, yFixed, background, color, lowerPixel) - end - else - if symbol == lowerPixel then - buffer.set(x, yFixed, color, foreground, lowerPixel) - else - buffer.set(x, yFixed, background, color, upperPixel) - end - end - end -end - -function doubleHeight.square(x, y, width, height, color) - for j = y, y + height - 1 do - for i = x, x + width - 1 do - doubleHeight.set(i, j, color) - end - end -end - -local function swap(a, b) - return b, a -end - -function doubleHeight.line(x0, y0, x1, y1, color) - local steep = false; - - if math.abs(x0 - x1) < math.abs(y0 - y1 ) then - x0, y0 = swap(x0, y0) - x1, y1 = swap(x1, y1) - steep = true; - end - - if (x0 > x1) then - x0, x1 = swap(x0, x1) - y0, y1 = swap(y0, y1) - end - - local dx = x1 - x0; - local dy = y1 - y0; - local derror2 = math.abs(dy) * 2 - local error2 = 0; - local y = y0; - - for x = x0, x1, 1 do - if steep then - doubleHeight.set(y, x, color); - else - doubleHeight.set(x, y, color) - end - - error2 = error2 + derror2; - - if error2 > dx then - y = y + (y1 > y0 and 1 or -1); - error2 = error2 - dx * 2; - end - end -end +-- buffer.clear(0x262626); buffer.draw(true) +-- doubleHeight.square(3, 3, 20, 20, 0xFF8888) +-- buffer.draw() ------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/lib/image.lua b/lib/image.lua old mode 100644 new mode 100755 index 08a38a80..f1c951c9 --- a/lib/image.lua +++ b/lib/image.lua @@ -668,31 +668,20 @@ function image.convertToGroupedImage(picture) end --Нарисовать по указанным координатам картинку указанной ширины и высоты для теста -function image.createImage(width, height, random) - local picture = {} - local symbolArray = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "Й", "К", "Л", "И", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы", "Ь", "Э", "Ю", "Я"} - picture.width = width - picture.height = height - local background, foreground, symbol - for j = 1, height do - for i = 1, width do - if random then - background = math.random(0x000000, 0xffffff) - foreground = math.random(0x000000, 0xffffff) - symbol = symbolArray[math.random(1, #symbolArray)] - else - background = 0x880000 - foreground = 0xffffff - symbol = "Q" - end - - table.insert(picture, background) - table.insert(picture, foreground) - table.insert(picture, 0x00) - table.insert(picture, symbol) +function image.create(width, height, background, foreground, alpha, symbol, random) + background, foreground, alpha, symbol = background or 0x0, foreground or 0x0, alpha or 0x0, symbol or " " + local picture, symbolArray = {width = width, height = height}, {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "Й", "К", "Л", "И", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы", "Ь", "Э", "Ю", "Я"} + for i = 1, picture.width * picture.height do + if random then + background = math.random(0x000000, 0xffffff) + foreground = math.random(0x000000, 0xffffff) + symbol = symbolArray[math.random(1, #symbolArray)] end + table.insert(picture, background) + table.insert(picture, foreground) + table.insert(picture, alpha) + table.insert(picture, symbol) end - -- image.draw(x, y, picture) return picture end @@ -728,7 +717,7 @@ function image.get(picture, x, y) end --Установить пиксель в изображении по указанным координатам -function image.set(picture, x, y, background, foreground, alpha, symbol) +function image.set(picture, x, y, background, foreground, alpha, symbol, debug) if x >= 1 and y >= 1 and x <= picture.width and y <= picture.height then local index = convertCoordsToIndex(x, y, picture.width) picture[index] = background or 0xFF00FF diff --git a/lib/palette.lua b/lib/palette.lua old mode 100644 new mode 100755 index 7b1570c7..68f39e10 --- a/lib/palette.lua +++ b/lib/palette.lua @@ -1,379 +1,287 @@ -local component = require("component") -local event = require("event") -local term = require("term") -local unicode = require("unicode") -local ecs = require("ECSAPI") -local colorlib = require("colorlib") -local gpu = component.gpu +-- _G.windows, _G.GUI, package.loaded.windows, package.loaded.GUI = nil, nil, nil, nil + +local libraries = { + advancedLua = "advancedLua", + component = "component", + fs = "filesystem", + colorlib = "colorlib", + image = "image", + buffer = "doubleBuffering", + GUI = "GUI", + windows = "windows", +} + +for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end; libraries = nil + +-------------------------------------------------------------------------------------------------------------- local palette = {} +local window +local currentColor, favourites +local xBigCrest, yBigCrest, yMiniCrest +local favouritesContainer, bigRainbow, miniRainbow, currentColorPanel +local pathToFavouritesConfig = "/MineOS/System/Palette/Favourites.cfg" +local inputs ------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------------- -local height = 23 -local width = 78 -local rainbowWidth, rainbowHeight = 40, 20 -local h, s, b, rr, gg, bb, hex = 0, 100, 100, 255, 0, 0, 0xff0000 - -local yHueSelector, xCrest, yCrest, oldCrest, startColor, xPalette, yPalette, xBigRainbow, yBigRainbow, xMiniRainbow, xColors, oldPixels - ------------------------------------------------------------------------------------- - -local obj = {} -local function newObj(class, name, ...) - obj[class] = obj[class] or {} - obj[class][name] = {...} +local function switchColorFromHex(hex) + currentColor = {hsb = {}, rgb = {}, hex = hex} + currentColor.rgb.red, currentColor.rgb.green, currentColor.rgb.blue = colorlib.HEXtoRGB(hex) + currentColor.hsb.hue, currentColor.hsb.saturation, currentColor.hsb.brightness = colorlib.RGBtoHSB(currentColor.rgb.red, currentColor.rgb.green, currentColor.rgb.blue) end -local function drawBigRainbow() - local x, y = xBigRainbow - 1, yBigRainbow - 1 +local function switchColorFromHsb(hue, saturation, brightness) + currentColor = {hsb = {hue = hue, saturation = saturation, brightness = brightness}, rgb = {}, hex = nil} + currentColor.rgb.red, currentColor.rgb.green, currentColor.rgb.blue = colorlib.HSBtoRGB(hue, saturation, brightness) + currentColor.hex = colorlib.RGBtoHEX(currentColor.rgb.red, currentColor.rgb.green, currentColor.rgb.blue) +end - local saturation, brightness = 1, 100 - local xModifyer, yModifyer = 2.53, 5.263157 +local function switchColorFromRgb(red, green, blue) + currentColor = {hsb = {}, rgb = {red = red, green = green, blue = blue}, hex = nil} + currentColor.hsb.hue, currentColor.hsb.saturation, currentColor.hsb.brightness = colorlib.RGBtoHSB(red, green, blue) + currentColor.hex = colorlib.RGBtoHEX(red, green, blue) +end - for i = 1, rainbowWidth do - brightness = 100 - for j = 1, rainbowHeight do - ecs.square(x + i, y + j, 2, 1, colorlib.HSBtoHEX(h, saturation, brightness)) - brightness = brightness - yModifyer +-------------------------------------------------------------------------------------------------------------- + +local function randomizeFavourites() + favourites = {}; for i = 1, 6 do favourites[i] = math.random(0x000000, 0xFFFFFF) end +end + +local function saveFavoutites() + table.toFile(pathToFavouritesConfig, favourites) +end + +local function loadFavourites() + if fs.exists(pathToFavouritesConfig) then + favourites = table.fromFile(pathToFavouritesConfig) + else + randomizeFavourites() + saveFavoutites() + end +end + +-------------------------------------------------------------------------------------------------------------- + +local function changeInputsValueToCurrentColor() + inputs[1].object.text = tostring(currentColor.rgb.red) + inputs[2].object.text = tostring(currentColor.rgb.green) + inputs[3].object.text = tostring(currentColor.rgb.blue) + inputs[4].object.text = tostring(math.floor(currentColor.hsb.hue)) + inputs[5].object.text = tostring(math.floor(currentColor.hsb.saturation)) + inputs[6].object.text = tostring(math.floor(currentColor.hsb.brightness)) + inputs[7].object.text = string.format("%06X", currentColor.hex) +end + +-------------------------------------------------------------------------------------------------------------- + +local function refreshBigRainbow(width, height) + local picture = image.create(width, height, 0x0, 0x0, 0x0, " ") + local saturationStep, brightnessStep, saturation, brightness = 100 / width, 100 / height, 0, 100 + for j = 1, height do + for i = 1, width do + image.set(picture, i, j, colorlib.HSBtoHEX(currentColor.hsb.hue, saturation, brightness), 0x0, 0x0, " ") + saturation = saturation + saturationStep end - saturation = saturation + xModifyer + saturation = 0; brightness = brightness - brightnessStep end + return picture end -local function drawMiniRainbow(x, y) - y = y - 1 - - local hue = 0 - local yModifyer = 18.94736 - for i = 1, rainbowHeight do - ecs.square(x, y + i, 3, 1, colorlib.HSBtoHEX(hue, 100, 100)) - hue = hue + yModifyer +local function refreshMiniRainbow(width, height) + local picture = image.create(width, height, 0x0, 0x0, 0x0, " ") + local hueStep, hue = 360 / height, 0 + for j = 1, height do + for i = 1, width do + image.set(picture, i, j, colorlib.HSBtoHEX(hue, 100, 100), 0x0, 0x0, " ") + end + hue = hue + hueStep end + return picture end - -local function drawHueSelector(x, y) - ecs.colorTextWithBack(x, y, 0x000000, ecs.windowColors.background, ">") - gpu.set(x + 4, y, "<") +local function refreshRainbows() + bigRainbow.image = refreshBigRainbow(50, 25) + miniRainbow.image = refreshMiniRainbow(3, 25) end -local function calculateAllColors(hexColor) - rr, gg, bb = colorlib.HEXtoRGB(hexColor) - h, s, b = colorlib.RGBtoHSB(rr, gg, bb) - hex = hexColor - - --ecs.error("Подсчитано: r = "..rr..", g = "..gg..", b = "..bb..", h = "..h..", s = "..s..", b = "..b..", hex = "..tostring(hex)) +local function betterVisiblePixel(x, y, symbol) + local background, foreground = buffer.get(x, y) + if background > 0x888888 then foreground = 0x000000 else foreground = 0xFFFFFF end + buffer.set(x, y, background, foreground, symbol) end -local function rememberOldCrest() - oldCrest = ecs.rememberOldPixels(xCrest - 2, yCrest - 1, xCrest + 2, yCrest + 1) +local function drawBigCrest() + local drawLimit = buffer.getDrawLimit(); buffer.setDrawLimit(window.x, window.y, bigRainbow.width + 2, bigRainbow.height) + betterVisiblePixel(xBigCrest - 2, yBigCrest, "─") + betterVisiblePixel(xBigCrest - 1, yBigCrest, "─") + betterVisiblePixel(xBigCrest + 1, yBigCrest, "─") + betterVisiblePixel(xBigCrest + 2, yBigCrest, "─") + betterVisiblePixel(xBigCrest, yBigCrest - 1, "│") + betterVisiblePixel(xBigCrest, yBigCrest + 1, "│") + buffer.setDrawLimit(drawLimit) end ---ЭТО КУРСОРЧИК КРЕСТИК -local function drawCrest(pointX, pointY) - ecs.drawOldPixels(oldCrest) - rememberOldCrest() - - ecs.invertedText(pointX-2,pointY,"─") - ecs.invertedText(pointX+2,pointY,"─") - ecs.invertedText(pointX-1,pointY,"─") - ecs.invertedText(pointX+1,pointY,"─") - ecs.invertedText(pointX,pointY-1,"│") - ecs.invertedText(pointX,pointY+1,"│") +local function drawMiniCrest() + buffer.text(miniRainbow.x - 1, yMiniCrest, 0x000000, ">") + buffer.text(miniRainbow.x + miniRainbow.width, yMiniCrest, 0x000000, "<") end -local function drawColors() - ecs.square(xColors, yBigRainbow, 10, 3, hex) - ecs.square(xColors, yBigRainbow + 3, 10, 3, startColor) +local function drawCrests() + drawBigCrest() + drawMiniCrest() end -local function convertHexToString(hex) - local stroka = string.format("%x", hex) - local sStroka = unicode.len(stroka) - - if sStroka < 6 then - stroka = string.rep("0", 6 - sStroka) .. stroka - end - - return stroka +local function drawAll() + currentColorPanel.colors.background = currentColor.hex + changeInputsValueToCurrentColor() + window:draw() + drawCrests() + buffer.draw() end -local function convertStringToHex(stroka) - return tonumber(stroka) +-------------------------------------------------------------------------------------------------------------- + +local function createCrestsCoordinates() + local xBigCrestModifyer = (bigRainbow.width - 1) * currentColor.hsb.saturation / 100 + local yBigCrestModifyer = (bigRainbow.height - 1) - (bigRainbow.height - 1) * currentColor.hsb.brightness / 100 + local yMiniCrestModifyer = (miniRainbow.height - 1) - (miniRainbow.height - 1) * currentColor.hsb.hue / 360 + + xBigCrest, yBigCrest, yMiniCrest = math.floor(window.x + xBigCrestModifyer), math.floor(window.y + yBigCrestModifyer), math.floor(window.y + yMiniCrestModifyer) end -local function drawInfo() +local function createInputs(x, y) + local function onAnyInputFinished() refreshRainbows(); createCrestsCoordinates(); drawAll() end + local function onHexInputFinished(object) switchColorFromHex(tonumber("0x" .. inputs[7].object.text)); onAnyInputFinished() end + local function onRgbInputFinished(object) switchColorFromRgb(tonumber(inputs[1].object.text), tonumber(inputs[2].object.text), tonumber(inputs[3].object.text)); onAnyInputFinished() end + local function onHsbInputFinished(object) switchColorFromHsb(tonumber(inputs[4].object.text), tonumber(inputs[5].object.text), tonumber(inputs[6].object.text)); onAnyInputFinished() end - local x, y = xColors, yBigRainbow + 7 + local function rgbValidaror(text) local num = tonumber(text) if num and num >= 0 and num <= 255 then return true end end + local function hValidator(text) local num = tonumber(text) if num and num >= 0 and num <= 359 then return true end end + local function sbValidator(text) local num = tonumber(text) if num and num >= 0 and num <= 100 then return true end end + local function hexValidator(text) if string.match(text, "^[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$") then return true end end - local massiv = { - {"R:", math.floor(rr)}, - {"G:", math.floor(gg)}, - {"B:", math.floor(bb)}, - {"H:", math.floor(h)}, - {"S:", math.floor(s)}, - {"L:", math.floor(b)}, - {"0x", convertHexToString(hex)}, + inputs = { + { shortcut = "R:", arrayName = "red", validator = rgbValidaror, onInputFinished = onRgbInputFinished }, + { shortcut = "G:", arrayName = "green", validator = rgbValidaror, onInputFinished = onRgbInputFinished }, + { shortcut = "B:", arrayName = "blue", validator = rgbValidaror, onInputFinished = onRgbInputFinished }, + { shortcut = "H:", arrayName = "hue", validator = hValidator, onInputFinished = onHsbInputFinished }, + { shortcut = "S:", arrayName = "saturation", validator = sbValidator, onInputFinished = onHsbInputFinished }, + { shortcut = "L:", arrayName = "brightness", validator = sbValidator, onInputFinished = onHsbInputFinished }, + { shortcut = "0x", arrayName = "red", validator = hexValidator, onInputFinished = onHexInputFinished } } - local yPos = y - - for i = 1, #massiv do - ecs.colorTextWithBack(x, yPos, ecs.windowColors.usualText, ecs.windowColors.background, massiv[i][1]) - ecs.inputText(x + 3, yPos, 7, tostring(massiv[i][2]), 0xffffff, 0x000000, true) - - newObj("Inputs", massiv[i][1], x + 3, yPos, x + 10, yPos) - - yPos = yPos + 2 + for i = 1, #inputs do + window:addLabel("inputShortcut" .. i, x, y, 2, 1, 0x000000, inputs[i].shortcut) + inputs[i].object = window:addInputTextBox("inputObject" .. i, x + 3, y, 9, 1, 0xFFFFFF, 0x444444, 0xFFFFFF, 0x000000, "", nil, nil, true) + inputs[i].object.validator = inputs[i].validator + inputs[i].object.onInputFinished = inputs[i].onInputFinished + y = y + 2 end + + return y end ---Просчитать позицию креста, основываясь на цветах -local function calculateCrest() - xModifyer, yModifyer = rainbowWidth / 100, rainbowHeight / 100 - xCrest, yCrest = xBigRainbow + s * xModifyer, yBigRainbow + rainbowHeight - (b * yModifyer) - - if yCrest == yPalette + height - 1 then yCrest = yCrest - 1 end +local function createFavourites() + local function onFavouriteClicked(button) switchColorFromHex(button.colors.default.background); refreshRainbows(); createCrestsCoordinates(); drawAll() end + for i = 1, #favourites do favouritesContainer:addButton("favourite" .. i, i * 2 - 1, 1, 2, 1, favourites[i], 0x0, 0x0, 0x0, " ").onTouch = onFavouriteClicked end end ---То же самое, но на основе текущего Хуя -local function calculateMini() - yModifyer = rainbowHeight / 360 - yHueSelector = yBigRainbow + math.abs(h * yModifyer - yModifyer) -end +local function createWindow(x, y) + window = windows.empty(x, y, 71, 25, 71, 25) + + x, y = 1, 1 + window:addPanel("backgroundPanel", x, y, window.width, window.height, 0xEEEEEE) + + bigRainbow = window:addImage("bigRainbow", x, y, image.create(50, 25)) + bigRainbow.onTouch = function(object, eventData) + xBigCrest, yBigCrest = eventData[3], eventData[4] + local _, _, background = component.gpu.get(eventData[3], eventData[4]) + switchColorFromHex(background) + drawAll() + end + bigRainbow.onDrag = bigRainbow.onTouch -local function drawButtons() - local xButtons, yButtons = xColors + 12, yBigRainbow - newObj("Buttons", " OK ", ecs.drawAdaptiveButton(xButtons, yButtons, 3, 0, " OK ", ecs.colors.lightBlue, 0xffffff)) - newObj("Buttons", "Отмена", ecs.drawAdaptiveButton(xButtons, yButtons + 2, 3, 0, "Отмена", 0xffffff, 0x000000)) -end + x = x + bigRainbow.width + 2 + + miniRainbow = window:addImage("miniRainbow", x, y, image.create(3, 25)) + miniRainbow.onTouch = function(object, eventData) + yMiniCrest = eventData[4] + switchColorFromHsb((eventData[4] - miniRainbow.y) * 360 / miniRainbow.height, currentColor.hsb.saturation, currentColor.hsb.brightness) + refreshRainbows() + drawAll() + end + miniRainbow.onDrag = miniRainbow.onTouch + x, y = x + 5, y + 1 + + currentColorPanel = window:addPanel("currentColorPanel", x, y, 12, 3, currentColor.hex) + y = y + 4 + + window:addButton("okButton", x, y, 12, 1, 0x444444, 0xFFFFFF, 0x88FF88, 0xFFFFFF, "OK").onTouch = function() + window:returnData(currentColor.hex) + end + y = y + 2 + + window:addButton("cancelButton", x, y, 12, 1, 0xFFFFFF, 0x444444, 0x88FF88, 0xFFFFFF, "Cancel").onTouch = function() + window:close() + end + y = y + 2 ---Собственно, отрисовка палитры -local function drawPalette() + y = createInputs(x, y) + + favouritesContainer = window:addContainer("favouritesContainer", x, y, 12, 1) + createFavourites() + y = y + 1 + + window:addButton("favouritesAddButton", x, y, 12, 1, 0xFFFFFF, 0x444444, 0x88FF88, 0xFFFFFF, "+").onTouch = function() + local favouriteExists = false; for i = 1, #favourites do if favourites[i] == currentColor.hex then favouriteExists = true; break end end + if not favouriteExists then + table.insert(favourites, 1, currentColor.hex); table.remove(favourites, #favourites) + for i = 1, #favourites do favouritesContainer.children[i].colors.default.background = favourites[i]; favouritesContainer.children[i].colors.pressed.background = 0x0 end + saveFavoutites() + drawAll() + end + end - --Считаем все цвета от стартового хекса - calculateAllColors(startColor) + window.onDrawFinished = function() + drawCrests() + buffer.draw() + end - --Рисуем окошечко и прочее - xPalette, yPalette = ecs.correctStartCoords(xPalette, yPalette, width, height) - oldPixels = ecs.emptyWindow(xPalette, yPalette, width, height, "Выберите цвет") - - --Считаем коорды радуки и всякую хуйню - xBigRainbow, yBigRainbow = xPalette + 2, yPalette + 2 - xMiniRainbow = xPalette + 46 - xColors = xMiniRainbow + 6 - - --Рисуем обе радуги - drawBigRainbow() - drawMiniRainbow(xMiniRainbow, yBigRainbow) - - --Рисуем крест - calculateCrest() - rememberOldCrest() - drawCrest(xCrest, yCrest) - - --Рисуем черточки у выбора Хуя - calculateMini() - drawHueSelector(xMiniRainbow - 1, yHueSelector) - - --Рисуем цвета - drawColors() - - --Рисуем текстики - drawInfo() - - --Рисуем кнопочки - drawButtons() -end - ---ТУ ХУЙНЮ НАРИСОВАТЬ -local function drawGOVNO() - --Две горизонтальные сверху и снизу - ecs.square(xBigRainbow - 2, yBigRainbow - 1, rainbowWidth + 4, 1, ecs.windowColors.background) - gpu.fill(xBigRainbow - 2, yBigRainbow + rainbowHeight, rainbowWidth + 4, 1, " ") - - --И две вертикальные - gpu.fill(xBigRainbow - 2, yBigRainbow, 2, rainbowHeight, " ") - gpu.fill(xBigRainbow + rainbowWidth + 1, yBigRainbow, 2, rainbowHeight, " ") - - --И еще две мелких хуйни около мелкой радужки - gpu.fill(xMiniRainbow - 1, yBigRainbow, 1, rainbowHeight, " ") - gpu.fill(xMiniRainbow + 3, yBigRainbow, 1, rainbowHeight, " ") -end - ---Вот эту херь вызывать только в случае глобального изменения Хуя -local function changeColor() - drawBigRainbow() - drawGOVNO() - rememberOldCrest() - calculateCrest() - calculateMini() - drawCrest(xCrest, yCrest) - drawHueSelector(xMiniRainbow - 1, yHueSelector) - drawColors() - drawInfo() -end - ------------------------------------------------------------- - ---Самая жирная и главная пиздофункция! -function palette.draw(xPalette1, yPalette1, startColor1) - - --Всякие стартовые хуевинки - if not startColor1 then startColor1 = 0xff0000 end - - --Костыли, костыли - xPalette, yPalette = xPalette1, yPalette1 - startColor = startColor1 - hex = startColor - - --Рисуем саму палитру - drawPalette() - - --Объектики создаем на всякий - newObj("Zones", "Big", xBigRainbow, yBigRainbow, xBigRainbow + rainbowWidth, yBigRainbow + rainbowHeight - 1) - newObj("Zones", "Mini", xMiniRainbow, yBigRainbow, xMiniRainbow + 2, yBigRainbow + rainbowHeight - 1) - - --Смотрим, че как - while true do - local e = {event.pull()} - if e[1] == "touch" or e[1] == "drag" then - - --Клик на жирную радугу - if ecs.clickedAtArea(e[3], e[4], obj["Zones"]["Big"][1], obj["Zones"]["Big"][2], obj["Zones"]["Big"][3], obj["Zones"]["Big"][4]) then - --Крест на новое место - xCrest = e[3] - yCrest = e[4] - drawCrest(xCrest, yCrest) - - --Просчет цвета - local symbol, fore, back = gpu.get(e[3], e[4]) - calculateAllColors(back) - drawColors() - drawInfo() - --А это если на мелкую радугу - elseif ecs.clickedAtArea(e[3], e[4], obj["Zones"]["Mini"][1], obj["Zones"]["Mini"][2], obj["Zones"]["Mini"][3], obj["Zones"]["Mini"][4]) then - local symbol, fore, back = gpu.get(e[3], e[4]) - --Считаем цвета - h = colorlib.HEXtoHSB(back) - rr, gg, bb = colorlib.HSBtoRGB(h, s, b) - - --перерисовываем - drawGOVNO() - drawHueSelector(xMiniRainbow - 1, e[4]) - drawBigRainbow() - rememberOldCrest() - drawCrest(xCrest, yCrest) - - symbol, fore, back = gpu.get(xCrest, yCrest) - hex = back - - drawColors() - drawInfo() - end - - --А это кнопочки! - for key, val in pairs(obj["Buttons"]) do - if ecs.clickedAtArea(e[3], e[4], obj["Buttons"][key][1], obj["Buttons"][key][2], obj["Buttons"][key][3], obj["Buttons"][key][4]) then - ecs.drawAdaptiveButton(obj["Buttons"][key][1], obj["Buttons"][key][2], 3, 0, key, ecs.colors.blue, 0xffffff) - os.sleep(0.3) - - if key == " OK " then - ecs.drawOldPixels(oldPixels) - return hex - else - ecs.drawOldPixels(oldPixels) - return nil - end - end - end - - - --А это... уууу, бля! Не лезь сюда вообще. Говнокод, но рабочий! - for key, val in pairs(obj["Inputs"]) do - if ecs.clickedAtArea(e[3], e[4], obj["Inputs"][key][1], obj["Inputs"][key][2], obj["Inputs"][key][3], obj["Inputs"][key][4]) then - - local text = ecs.inputText(obj["Inputs"][key][1], obj["Inputs"][key][2], 7, "", 0xffffff, 0x000000, false) - - if text ~= "" and text ~= " " and text then - if key == "0x" then - hex = convertStringToHex("0x"..text) - calculateAllColors(hex) - elseif key == "R:" then - local color = tonumber(text) - if color >= 255 then color = 255 end - if color < 1 then color = 1 end - rr = color - - hex = colorlib.RGBtoHEX(rr, gg, bb) - h, s, b = colorlib.RGBtoHSB(rr, gg, bb) - elseif key == "G:" then - local color = tonumber(text) - if color >= 255 then color = 255 end - if color < 1 then color = 1 end - gg = color - - hex = colorlib.RGBtoHEX(rr, gg, bb) - h, s, b = colorlib.RGBtoHSB(rr, gg, bb) - elseif key == "B:" then - local color = tonumber(text) - if color >= 255 then color = 255 end - if color < 1 then color = 1 end - bb = color - - hex = colorlib.RGBtoHEX(rr, gg, bb) - h, s, b = colorlib.RGBtoHSB(rr, gg, bb) - elseif key == "H:" then - local color = tonumber(text) - if color >= 360 then color = 0 end - if color < 0 then color = 0 end - h = color - - hex = colorlib.HSBtoHEX(h, s, b) - rr, gg, bb = colorlib.HSBtoRGB(h, s, b) - elseif key == "S:" then - local color = tonumber(text) - if color >= 100 then color = 100 end - if color < 0 then color = 0 end - s = color - - hex = colorlib.HSBtoHEX(h, s, b) - rr, gg, bb = colorlib.HSBtoRGB(h, s, b) - elseif key == "L:" then - local color = tonumber(text) - if color >= 100 then color = 100 end - if color < 0 then color = 0 end - b = color - - hex = colorlib.HSBtoHEX(h, s, b) - rr, gg, bb = colorlib.HSBtoRGB(h, s, b) - end - - changeColor() - - break - end - end - end + window.onKeyDown = function(eventData) + if eventData[4] == 28 then + window.okButton:press() + drawAll() + window:returnData(currentColor.hex) end end end --------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------------- ---print( convertHexToString( palette.draw(5, 5, 0xff00ff) )) +function palette.show(x, y, startColor) + loadFavourites() + switchColorFromHex(startColor or 0x00B6FF) + createWindow(x, y) + createCrestsCoordinates() + + refreshRainbows() + window.drawShadow = true + drawAll() + window.drawShadow = false + + return window:handleEvents() +end + +-- Поддержим олдфагов! +palette.draw = palette.show + +-------------------------------------------------------------------------------------------------------------- + +-- ecs.error(palette.show("auto", "auto", 0xFF5555)) + +-------------------------------------------------------------------------------------------------------------- return palette - - - - - - - - - - - diff --git a/lib/rayEngine.lua b/lib/rayEngine.lua old mode 100644 new mode 100755 index e94a8681..de780ded --- a/lib/rayEngine.lua +++ b/lib/rayEngine.lua @@ -1,4 +1,5 @@ local libraries = { + computer = "computer", advancedLua = "advancedLua", colorlib = "colorlib", image = "image", @@ -6,35 +7,67 @@ local libraries = { doubleHeight = "doubleHeight", GUI = "GUI", files = "files", - computer = "computer", event = "event", } for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end; libraries = nil -local rayEngine = {} ---------------------------------------------------- Константы ------------------------------------------------------------------ -rayEngine.horizonPosition = math.floor(buffer.screen.height / 2) +local rayEngine = {} + +rayEngine.debugInformationEnabled = true rayEngine.minimapEnabled = true rayEngine.compassEnabled = false rayEngine.watchEnabled = false rayEngine.drawFieldOfViewOnMinimap = false rayEngine.chatShowTime = 4 rayEngine.chatHistory = {} -rayEngine.chatPanelWidth, rayEngine.chatPanelHeight = math.floor(buffer.screen.width * 0.4), math.floor(buffer.screen.height * 0.4) -rayEngine.chatHistoryLimit = rayEngine.chatPanelHeight + +---------------------------------------------- Расчетные функции ------------------------------------------------------------------ + +-- Позиция горизонта, относительно которой рисуется мир +function rayEngine.calculateHorizonPosition() + rayEngine.horizonPosition = math.floor(buffer.screen.height / 2) +end + +-- Размер панели чата и лимита его истории +function rayEngine.calculateChatSize() + rayEngine.chatPanelWidth, rayEngine.chatPanelHeight = math.floor(buffer.screen.width * 0.4), math.floor(buffer.screen.height * 0.4) + rayEngine.chatHistoryLimit = rayEngine.chatPanelHeight +end + +-- Шаг, с которым будет изменяться угол рейкаста +function rayEngine.calculateRaycastStep() + rayEngine.raycastStep = rayEngine.player.fieldOfView / buffer.screen.width +end + +-- Позиция оружия на экране и всех его вспомогательных текстур +function rayEngine.calculateWeaponPosition() + rayEngine.currentWeapon.xWeapon = buffer.screen.width - rayEngine.currentWeapon.weaponTexture.width + 1 + rayEngine.currentWeapon.yWeapon = buffer.screen.height - rayEngine.currentWeapon.weaponTexture.height + 1 + rayEngine.currentWeapon.xFire = rayEngine.currentWeapon.xWeapon + rayEngine.weapons[rayEngine.currentWeapon.ID].firePosition.x + rayEngine.currentWeapon.yFire = rayEngine.currentWeapon.yWeapon + rayEngine.weapons[rayEngine.currentWeapon.ID].firePosition.y + rayEngine.currentWeapon.xCrosshair = math.floor(buffer.screen.width / 2 - rayEngine.currentWeapon.crosshairTexture.width / 2) + rayEngine.currentWeapon.yCrosshair = math.floor(buffer.screen.height / 2 - rayEngine.currentWeapon.crosshairTexture.height / 2) +end + +-- Грубо говоря, это расстояние от камеры до виртуального экрана, на котором рисуется весь наш мир, влияет на размер блоков +function rayEngine.calculateDistanceToProjectionPlane() + rayEngine.distanceToProjectionPlane = (buffer.screen.width / 2) / math.tan(math.rad((rayEngine.player.fieldOfView / 2))) +end + +-- Быстрый перерасчет всего, что нужно +function rayEngine.calculateAllParameters() + rayEngine.calculateHorizonPosition() + rayEngine.calculateChatSize() + rayEngine.calculateRaycastStep() + rayEngine.calculateDistanceToProjectionPlane() + if rayEngine.currentWeapon then rayEngine.calculateWeaponPosition() end +end ---------------------------------------------- Вспомогательные функции ------------------------------------------------------------------ -local function round(num) - if num >= 0 then - return math.floor(num + 0.5) - else - return math.ceil(num - 0.5) - end -end - local function constrainAngle(value) if ( value < 0 ) then value = value + 360 @@ -54,15 +87,15 @@ end local function getTileColor(basecolor, distance) local limitedDistance = math.floor(distance * rayEngine.properties.shadingCascades / rayEngine.properties.shadingDistance) - local transparency = rayEngine.properties.shadingTransparencyMap.current - math.floor(limitedDistance * 255 / rayEngine.properties.shadingCascades) - transparency = (transparency >= rayEngine.properties.shadingTransparencyMap[1] and transparency <= 255) and transparency or rayEngine.properties.shadingTransparencyMap[1] + local transparency = rayEngine.currentShadingTransparencyMapValue - math.floor(limitedDistance * 255 / rayEngine.properties.shadingCascades) + transparency = (transparency >= rayEngine.properties.shadingTransparencyMap[1] and transparency <= 255) and transparency or rayEngine.properties.shadingTransparencyMap[1] return colorlib.alphaBlend(basecolor, 0x000000, transparency) end -local function getTimeDependentColors() +function rayEngine.refreshTimeDependentColors() rayEngine.world.colors.sky.current = getSkyColorByTime() - rayEngine.properties.shadingTransparencyMap.current = getBrightnessByTime() - rayEngine.world.colors.groundByTime = colorlib.alphaBlend(rayEngine.world.colors.ground, 0x000000, rayEngine.properties.shadingTransparencyMap.current) + rayEngine.currentShadingTransparencyMapValue = getBrightnessByTime() + rayEngine.world.colors.groundByTime = colorlib.alphaBlend(rayEngine.world.colors.ground, 0x000000, rayEngine.currentShadingTransparencyMapValue) end local function doDayNightCycle() @@ -73,17 +106,13 @@ local function doDayNightCycle() if rayEngine.world.dayNightCycle.currentTime > rayEngine.world.dayNightCycle.length then rayEngine.world.dayNightCycle.currentTime = 0 end rayEngine.world.dayNightCycle.lastComputerUptime = computerUptime - getTimeDependentColors() + rayEngine.refreshTimeDependentColors() end end end -local function correctDouble(number) - return string.format("%.1f", number) -end - local function convertWorldCoordsToMapCoords(x, y) - return round(x / rayEngine.properties.tileWidth), round(y / rayEngine.properties.tileWidth) + return math.round(x / rayEngine.properties.tileWidth), math.round(y / rayEngine.properties.tileWidth) end local function getBlockCoordsByLook(distance) @@ -91,61 +120,40 @@ local function getBlockCoordsByLook(distance) return convertWorldCoordsToMapCoords(rayEngine.player.position.x + distance * math.sin(radRotation) * rayEngine.properties.tileWidth, rayEngine.player.position.y + distance * math.cos(radRotation) * rayEngine.properties.tileWidth) end -function rayEngine.changeWeapon(weaponID) - if rayEngine.weapons[weaponID] then - rayEngine.currentWeapon = { - damage = rayEngine.weapons[weaponID].damage, - weaponTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].weaponTexture), - fireTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].fireTexture), - crosshairTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].crosshairTexture) - } - rayEngine.currentWeapon.xWeapon = buffer.screen.width - rayEngine.currentWeapon.weaponTexture.width + 1 - rayEngine.currentWeapon.yWeapon = buffer.screen.height - rayEngine.currentWeapon.weaponTexture.height + 1 - rayEngine.currentWeapon.xFire = rayEngine.currentWeapon.xWeapon + rayEngine.weapons[weaponID].firePosition.x - rayEngine.currentWeapon.yFire = rayEngine.currentWeapon.yWeapon + rayEngine.weapons[weaponID].firePosition.y - rayEngine.currentWeapon.xCrosshair = math.floor(buffer.screen.width / 2 - rayEngine.currentWeapon.crosshairTexture.width / 2) - rayEngine.currentWeapon.yCrosshair = math.floor(buffer.screen.height / 2 - rayEngine.currentWeapon.crosshairTexture.height / 2) - else - rayEngine.currentWeapon = nil - end -end - ---------------------------------------------------- Работа с файлами ------------------------------------------------------------------ ---Грузим базовый конфиг движка -function rayEngine.loadEngine(pathToRayEnginePropertiesFile) +-- Загрузка параметров движка +function rayEngine.loadEngineProperties(pathToRayEnginePropertiesFile) rayEngine.properties = files.loadTableFromFile(pathToRayEnginePropertiesFile) - rayEngine.properties.raycastQuality = rayEngine.properties.raycastQuality * rayEngine.properties.tileWidth - rayEngine.properties.shadingDistance = math.floor(rayEngine.properties.drawDistance * rayEngine.properties.shadingDistance) end +-- Загрузка конифгурации оружия function rayEngine.loadWeapons(pathToWeaponsFolder) rayEngine.weaponsFolder = pathToWeaponsFolder rayEngine.weapons = files.loadTableFromFile(rayEngine.weaponsFolder .. "Weapons.cfg") rayEngine.changeWeapon(1) end ---Загружаем все конфиг-файлы мира +-- Загрузка конкретного мира function rayEngine.loadWorld(pathToWorldFolder) rayEngine.world = files.loadTableFromFile(pathToWorldFolder .. "/World.cfg") rayEngine.map = files.loadTableFromFile(pathToWorldFolder .. "/Map.cfg") rayEngine.player = files.loadTableFromFile(pathToWorldFolder .. "/Player.cfg") rayEngine.blocks = files.loadTableFromFile(pathToWorldFolder .. "/Blocks.cfg") - --Дополняем карту ее размерами + -- Дополняем карту ее размерами rayEngine.map.width = #rayEngine.map[1] rayEngine.map.height = #rayEngine.map - --Ебашим правильную позицию игрока, основанную на этой ХУЙНЕ, которую ГЛЕБ так ЛЮБИТ + -- Ебашим правильную позицию игрока, основанную на этой ХУЙНЕ, которую ГЛЕБ так ЛЮБИТ rayEngine.player.position.x = rayEngine.properties.tileWidth * rayEngine.player.position.x - rayEngine.properties.tileWidth / 2 rayEngine.player.position.y = rayEngine.properties.tileWidth * rayEngine.player.position.y - rayEngine.properties.tileWidth / 2 - --Рассчитываем стартовые цвета, зависимые от времени - небо, землю, стены - getTimeDependentColors() - --Обнуляем текущее время, если превышен лимит + -- Рассчитываем цвета, зависимые от времени - небо, землю, стены + rayEngine.refreshTimeDependentColors() + -- Обнуляем текущее время, если превышен лимит, а то мало ли какой пидорас начнет править конфиги мира rayEngine.world.dayNightCycle.currentTime = rayEngine.world.dayNightCycle.currentTime > rayEngine.world.dayNightCycle.length and 0 or rayEngine.world.dayNightCycle.currentTime - --Осуществляем базовое получение аптайма пекарни + -- Осуществляем базовое получение аптайма пекарни rayEngine.world.dayNightCycle.lastComputerUptime = computer.uptime() - rayEngine.distanceToProjectionPlane = (buffer.screen.width / 2) / math.tan(math.rad((rayEngine.player.fieldOfView / 2))) - --Шаг, с которым будет изменяться угол рейкаста - rayEngine.properties.raycastStep = rayEngine.player.fieldOfView / buffer.screen.width + -- Рассчитываем необходимые параметры движка + rayEngine.calculateAllParameters() -- rayEngine.wallsTexture = image.load("/heart.pic") -- rayEngine.wallsTexture = image.transform(rayEngine.wallsTexture, rayEngine.properties.tileWidth, rayEngine.properties.tileWidth / 2) @@ -153,6 +161,21 @@ end ---------------------------------------------------- Функции, связанные с игроком ------------------------------------------------------------------ +function rayEngine.changeWeapon(weaponID) + if rayEngine.weapons[weaponID] then + rayEngine.currentWeapon = { + ID = weaponID, + damage = rayEngine.weapons[weaponID].damage, + weaponTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].weaponTexture), + fireTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].fireTexture), + crosshairTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].crosshairTexture) + } + rayEngine.calculateWeaponPosition() + else + rayEngine.currentWeapon = nil + end +end + function rayEngine.move(distanceForward, distanceRight) local forwardRotation = math.rad(rayEngine.player.rotation) local rightRotation = math.rad(rayEngine.player.rotation + 90) @@ -226,6 +249,12 @@ end ---------------------------------------------------- Функции интерфейса ------------------------------------------------------------------ +function rayEngine.drawDebugInformation(x, y, width, transparency, ...) + local lines = {...} + buffer.square(x, y, width, #lines, 0x000000, 0x000000, " ", transparency); x = x + 1 + for line = 1, #lines do buffer.text(x, y, 0xEEEEEE, lines[line]); y = y + 1 end +end + local function drawFieldOfViewAngle(x, y, distance, color) local fieldOfViewHalf = rayEngine.player.fieldOfView / 2 local firstAngle, secondAngle = math.rad(-(rayEngine.player.rotation - fieldOfViewHalf)), math.rad(-(rayEngine.player.rotation + fieldOfViewHalf)) @@ -245,7 +274,7 @@ function rayEngine.drawMap(x, y, width, height, transparency) for i = yMap - yHalf + 1, yMap + yHalf do for j = xMap + xHalf + 1, xMap - xHalf + 2, -1 do if rayEngine.map[i] and rayEngine.map[i][j] then - doubleHeight.set(xPos, yPos, rayEngine.blocks[rayEngine.map[i][j]].color) + buffer.semiPixelSet(xPos, yPos, rayEngine.blocks[rayEngine.map[i][j]].color) end xPos = xPos + 1 end @@ -256,12 +285,7 @@ function rayEngine.drawMap(x, y, width, height, transparency) --Поле зрения if rayEngine.drawFieldOfViewOnMinimap then drawFieldOfViewAngle(xPlayer, yPlayer, 5, 0xCCFFBF) end --Игрок - doubleHeight.set(xPlayer, yPlayer, 0x66FF40) - --Инфа - y = y + yHalf - buffer.square(x, y, width, 1, 0x000000, 0x000000, " ", transparency + 10) - x = x + 1 - buffer.text(x, y, 0xFFFFFF, "POS: " .. correctDouble(rayEngine.player.position.x) .. " x " .. correctDouble(rayEngine.player.position.y)) + buffer.semiPixelSet(xPlayer, yPlayer, 0x66FF40) end function rayEngine.intro() @@ -274,9 +298,9 @@ function rayEngine.intro() buffer.draw() os.sleep(0) end - for i = 20, 100, 20 do draw(i) end + for i = 0, 100, 20 do draw(i) end os.sleep(1.5) - for i = 100, 20, -20 do draw(i) end + for i = 100, 0, -20 do draw(i) end end function rayEngine.compass(x, y) @@ -289,14 +313,14 @@ function rayEngine.compass(x, y) local xScaleFactor = 2.2 local southPoint, northPoint = {}, {} local northAngleRad = math.rad(northAngle) - northPoint.x, northPoint.y = round(x + math.sin(northAngleRad) * distance * xScaleFactor), round(y - math.cos(northAngleRad) * distance) + northPoint.x, northPoint.y = math.round(x + math.sin(northAngleRad) * distance * xScaleFactor), math.round(y - math.cos(northAngleRad) * distance) northAngleRad = math.rad(northAngle + 180) - southPoint.x, southPoint.y = round(x + math.sin(northAngleRad) * distance * xScaleFactor), round(y - math.cos(northAngleRad) * distance) + southPoint.x, southPoint.y = math.round(x + math.sin(northAngleRad) * distance * xScaleFactor), math.round(y - math.cos(northAngleRad) * distance) y = y * 2 doubleHeight.line(x, y, northPoint.x, northPoint.y * 2, 0xFF5555) doubleHeight.line(x, y, southPoint.x, southPoint.y * 2, 0xFFFFFF) - doubleHeight.set(x, y, 0x000000) + buffer.semiPixelSet(x, y, 0x000000) end function rayEngine.watch(x, y) @@ -311,8 +335,8 @@ function rayEngine.watch(x, y) local hourAngle = math.rad(hours * 360 / 12) local minuteAngle = math.rad(minutes * 360) local hourArrowLength, minuteArrowLength = 2.8, 4.5 - local xMinute, yMinute = round(x + math.sin(minuteAngle) * minuteArrowLength * 2), round(y - math.cos(minuteAngle) * minuteArrowLength) - local xHour, yHour = round(x + math.sin(hourAngle) * hourArrowLength * 2), round(y - math.cos(hourAngle) * hourArrowLength) + local xMinute, yMinute = math.round(x + math.sin(minuteAngle) * minuteArrowLength * 2), math.round(y - math.cos(minuteAngle) * minuteArrowLength) + local xHour, yHour = math.round(x + math.sin(hourAngle) * hourArrowLength * 2), math.round(y - math.cos(hourAngle) * hourArrowLength) y = y * 2 doubleHeight.line(x, y, xMinute, yMinute * 2, 0xEEEEEE) @@ -376,7 +400,7 @@ function rayEngine.commandLine(transparency) addItemToChatHistory("Состояние цикла дня и ночи: " .. tostring(rayEngine.world.dayNightCycle.enabled), 0xFFDB40) end elseif words[1] == "setrenderquality" and tonumber(words[2]) then - rayEngine.properties.raycastQuality = rayEngine.properties.tileWidth * tonumber(words[2]) + rayEngine.properties.raycastQuality = tonumber(words[2]) addItemToChatHistory("Качество рендера изменено на: " .. tonumber(words[2]), 0xFFDB40) elseif words[1] == "setdrawdistance" and tonumber(words[2]) then rayEngine.properties.drawDistance = tonumber(words[2]) @@ -385,7 +409,7 @@ function rayEngine.commandLine(transparency) rayEngine.properties.shadingCascades = tonumber(words[2]) addItemToChatHistory("Количество цветов для отрисовки блока изменено на: " .. tonumber(words[2]), 0xFFDB40) elseif words[1] == "setshadingdistance" and tonumber(words[2]) then - rayEngine.properties.shadingDistance = rayEngine.properties.drawDistance * tonumber(words[2]) + rayEngine.properties.shadingDistance = tonumber(words[2]) addItemToChatHistory("Дистация затенения блоков изменена на: " .. tonumber(words[2]), 0xFFDB40) elseif words[1] == "help" then addItemToChatHistory("Доступные команды:", 0xFFDB40) @@ -401,7 +425,7 @@ function rayEngine.commandLine(transparency) addItemToChatHistory("Неизвестная команда. Введите /help для получения списка команд", 0xFF8888) end else - addItemToChatHistory("Вы написали: " .. text, 0xFFFFFF) + addItemToChatHistory("> " .. text, 0xFFFFFF) end end @@ -415,6 +439,10 @@ function rayEngine.toggleMinimap() rayEngine.minimapEnabled = not rayEngine.minimapEnabled end +function rayEngine.toggleDebugInformation() + rayEngine.debugInformationEnabled = not rayEngine.debugInformationEnabled +end + function rayEngine.toggleCompass() rayEngine.compassEnabled = not rayEngine.compassEnabled if not rayEngine.compassEnabled then rayEngine.compassImage = nil end @@ -468,11 +496,22 @@ function rayEngine.drawWorld() buffer.square(1, 1, buffer.screen.width, rayEngine.horizonPosition, rayEngine.world.colors.sky.current) --Сцена local startAngle, endAngle, startX, distanceToTile, tileID, height, startY, tileColor = rayEngine.player.rotation - rayEngine.player.fieldOfView / 2, rayEngine.player.rotation + rayEngine.player.fieldOfView / 2, 1 - for angle = startAngle, endAngle, rayEngine.properties.raycastStep do + for angle = startAngle, endAngle, rayEngine.raycastStep do distanceToTile, tileID = raycast(angle) if distanceToTile then - height = rayEngine.properties.tileWidth / distanceToTile * rayEngine.distanceToProjectionPlane - startY = rayEngine.horizonPosition - height / 2 + -- Получаем цвет стенки + tileColor = getTileColor(rayEngine.blocks[tileID].color, distanceToTile) + + -- Поддержка "высококачественной" doubleHeight-графики + if rayEngine.properties.useSimpleRenderer then + height = rayEngine.properties.tileWidth / distanceToTile * rayEngine.distanceToProjectionPlane + startY = rayEngine.horizonPosition - height / 2 + 1 + buffer.square(math.floor(startX), math.floor(startY), 1, math.floor(height), tileColor, 0x000000, " ") + else + height = rayEngine.properties.tileWidth / distanceToTile * rayEngine.distanceToProjectionPlane * 2 + startY = rayEngine.horizonPosition * 2 - height / 2 + 1 + buffer.semiPixelSquare(math.floor(startX), math.floor(startY), 1, height, tileColor) + end --ТИКСТУРКА)))00 -- local xTexture = startX % rayEngine.properties.tileWidth + 1 @@ -481,17 +520,14 @@ function rayEngine.drawWorld() -- column = image.transform(column, 1, height) -- buffer.image(math.floor(startX), math.floor(startY), column) -- end - - --Кусочек стенки - tileColor = getTileColor(rayEngine.blocks[tileID].color, distanceToTile) - -- doubleHeight.square(math.floor(startX), math.floor(startY), 1, math.floor(height), tileColor) - buffer.square(math.floor(startX), math.floor(startY), 1, math.floor(height), tileColor, 0x000000, " ") end startX = startX + 1 end end function rayEngine.update() + local frameRenderClock = os.clock() + rayEngine.drawWorld() if rayEngine.currentWeapon then rayEngine.drawWeapon() end if rayEngine.minimapEnabled then rayEngine.drawMap(3, 2, 24, 24, 50) end @@ -501,11 +537,27 @@ function rayEngine.update() if rayEngine.watchEnabled then rayEngine.watch(xTools, yTools) end if rayEngine.chatEnabled then rayEngine.chat() end doDayNightCycle() + + if rayEngine.debugInformationEnabled then + rayEngine.drawDebugInformation(3, 2 + (rayEngine.minimapEnabled and 12 or 0), 24, 60, + "renderTime: " .. math.doubleToString((os.clock() - frameRenderClock) * 1000, 2) .. " ms", + "freeRAM: " .. math.doubleToString(computer.freeMemory() / 1024, 2) .. " KB", + "pos: " .. math.doubleToString(rayEngine.player.position.x) .. " x " .. math.doubleToString(rayEngine.player.position.y) + ) + end + buffer.draw() end ---------------------------------------------------------------------------------------------------------------------------------- +function rayEngine.changeResolution(width, height) + buffer.clear(0x000000); buffer.draw() + component.gpu.setResolution(width, height) + buffer.start() + rayEngine.calculateAllParameters() +end + function rayEngine.fire() rayEngine.currentWeapon.needToFire = true rayEngine.update() diff --git a/lib/serialization.lua b/lib/serialization.lua old mode 100644 new mode 100755 index e0f620e1..aaff711a --- a/lib/serialization.lua +++ b/lib/serialization.lua @@ -1,156 +1,25 @@ -local filesystem = require("filesystem") +require("advancedLua") local serialization = {} -------------------------------------------------- Private methods ----------------------------------------------------------------- - -local function doSerialize(array, text, prettyLook, indentationSymbol, oldIndentationSymbol, equalsSymbol) - text = {"{"} - table.insert(text, (prettyLook and "\n" or nil)) - - for key, value in pairs(array) do - local keyType, valueType, stringValue = type(key), type(value), tostring(value) - - if keyType == "number" or keyType == "string" then - table.insert(text, (prettyLook and indentationSymbol or nil)) - table.insert(text, "[") - 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 - table.insert(text, "\"") - table.insert(text, stringValue) - table.insert(text, "\"") - elseif valueType == "table" then - table.insert(text, table.concat(doSerialize(value, text, prettyLook, table.concat({indentationSymbol, indentationSymbol}), table.concat({oldIndentationSymbol, indentationSymbol}), equalsSymbol))) - else - error("Unsupported table value type: " .. valueType) - end - - table.insert(text, ",") - table.insert(text, (prettyLook and "\n" or nil)) - else - error("Unsupported table key type: " .. keyType) - end - end - - table.remove(text, (prettyLook and #text - 1 or #text)) - table.insert(text, (prettyLook and oldIndentationSymbol or nil)) - table.insert(text, "}") - return text -end - ------------------------------------------------- Public methods ----------------------------------------------------------------- -function serialization.serialize(array, prettyLook, indentationWidth, indentUsingTabs) - checkArg(1, array, "table") - indentationWidth = indentationWidth or 2 - local indentationSymbol = indentUsingTabs and " " or " " - indentationSymbol, indentationSymbolHalf = string.rep(indentationSymbol, indentationWidth) - return table.concat(doSerialize(array, {}, prettyLook, indentationSymbol, "", prettyLook and " = " or "=")) +function serialization.serialize(...) + return table.serialize(...) end -function serialization.unserialize(serializedString) - checkArg(1, serializedString, "string") - local success, result = pcall(load("return " .. serializedString)) - if success then return result else return nil, result end +function serialization.unserialize(...) + return table.unserialize(...) end -function serialization.serializeToFile(path, array, prettyLook, indentationWidth, indentUsingTabs, appendToFile) - checkArg(1, path, "string") - checkArg(2, array, "table") - filesystem.makeDirectory(filesystem.path(path) or "") - local file = io.open(path, appendToFile and "a" or "w") - file:write(serialization.serialize(array, prettyLook, indentationWidth, indentUsingTabs)) - file:close() +function serialization.serializeToFile(...) + table.toFile(...) end -function serialization.unserializeFromFile(path) - checkArg(1, path, "string") - if filesystem.exists(path) then - if filesystem.isDirectory(path) then - error("\"" .. path .. "\" is a directory") - else - local file = io.open(path, "r") - local data = serialization.unserialize(file:read("*a")) - file:close() - return data - end - else - error("\"" .. path .. "\" doesn't exists") - end +function serialization.unserializeFromFile(...) + return table.fromFIle(...) end -------------------------------------------------- Playground ----------------------------------------------------------------- - --- local sampleTable = { --- "one", --- "two", --- "three", --- [9] = 9, --- [10] = "ten", --- [11] = "eleven", --- ["test"] = "sucess", --- ["tableTest"] = { --- ["tableInTable"] = { --- [12] = "blah-blah", --- ["hello"] = "world", --- }, --- "cyka", --- "blyad", --- }, --- ["nilTest"] = nil, --- ["booleanTest"] = true, --- } - --- local function fillTable(count) --- print("Filling table with " .. count .. " random values...") --- for i = 1, count do --- table.insert(sampleTable, math.random(1, 100000)) --- end --- end - --- local function executeAndPrintExecutionTime(method, ...) --- local oldTime = os.clock() --- method(...) --- print("Execution time: " .. os.clock() - oldTime .. " seconds") --- end - --- local function compareAlgorithms() --- print(" ") --- fillTable(10000) --- print(" ") --- local oldSerialization = require("openOSSerialization") --- print("Old:") --- executeAndPrintExecutionTime(oldSerialization.serialize, sampleTable) --- print("New:") --- executeAndPrintExecutionTime(serialization.serialize, sampleTable) --- print(" ") --- end - --- compareAlgorithms() - ----------------------------------------------------------------------------------------------------------------------- - --- print("Serializing...") --- local serializedTable = serialization.serialize(sampleTable, true) --- print(" ") --- print(serializedTable) --- print(" ") --- print("Done.") --- print("Unserializing...") --- local unserializedTable = serialization.unserialize(serializedTable) --- print("Done.") --- print("Saving to file...") --- serialization.serializeToFile("serializationTest.lua", sampleTable, true) --- print("Done.") --- print("Loading from file...") --- serialization.unserializeFromFile("serializationTest.lua") --- print("Done.") - ---------------------------------------------------------------------------------------------------------------------- return serialization diff --git a/lib/syntax.lua b/lib/syntax.lua old mode 100644 new mode 100755 index b7e48bde..c8c9b9ac --- a/lib/syntax.lua +++ b/lib/syntax.lua @@ -34,10 +34,10 @@ local currentColorScheme, patterns local function definePatterns() patterns = { --Комментарии - { pattern = "%-%-.*", color = currentColorScheme.comments, cutFromLeft = 0, cutFromRight = 0 }, + { pattern = "%-%-.+", color = currentColorScheme.comments, cutFromLeft = 0, cutFromRight = 0 }, --Строки - { pattern = "\"[^\"\"]*\"", color = currentColorScheme.strings, cutFromLeft = 0, cutFromRight = 0 }, + { pattern = "\"[^\"\"]+\"", color = currentColorScheme.strings, cutFromLeft = 0, cutFromRight = 0 }, --Циклы, условия, объявления { pattern = "while ", color = currentColorScheme.loops, cutFromLeft = 0, cutFromRight = 1 }, @@ -64,9 +64,10 @@ local function definePatterns() { pattern = "nil", color = currentColorScheme.boolean, cutFromLeft = 0, cutFromRight = 0 }, --Функции - { pattern = "%s([%a%d%_%-%.]*)%(", color = currentColorScheme.functions, cutFromLeft = 0, cutFromRight = 1 }, + { pattern = "[%s%=][%a%d%_%-%.]+%(", color = currentColorScheme.functions, cutFromLeft = 0, cutFromRight = 1 }, + { pattern = "^[%a%d%_%-%.%=]+%(", color = currentColorScheme.functions, cutFromLeft = 0, cutFromRight = 1 }, - --And, or, not, break + --Логические выражения { pattern = " and ", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 1 }, { pattern = " or ", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 1 }, { pattern = " not ", color = currentColorScheme.logic, cutFromLeft = 0, cutFromRight = 1 }, @@ -86,13 +87,14 @@ local function definePatterns() { pattern = "%-", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, { pattern = "%*", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, { pattern = "%/", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, - { pattern = "%.%.", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, + { pattern = "%.+", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, { pattern = "%#", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, { pattern = "#^", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, + { pattern = "%%", color = currentColorScheme.compares, cutFromLeft = 0, cutFromRight = 0 }, --Числа - { pattern = "%s(0x)(%w*)", color = currentColorScheme.numbers, cutFromLeft = 0, cutFromRight = 0 }, - { pattern = "(%s)([%d%.]*)", color = currentColorScheme.numbers, cutFromLeft = 0, cutFromRight = 0 }, + { pattern = "[%s%(%,]0x%w+", color = currentColorScheme.numbers, cutFromLeft = 1, cutFromRight = 0 }, + { pattern = "[%s%(%,][%d%.]+", color = currentColorScheme.numbers, cutFromLeft = 1, cutFromRight = 0 }, } end @@ -153,7 +155,7 @@ function syntax.highlightString(x, y, text, fromSymbol, limit) while true do starting, ending = unicode.find(text, patterns[i].pattern, searchFrom) if starting and ending then - buffer.text(x + starting - fromSymbol, y, patterns[i].color, unicode.sub(text, starting, ending - patterns[i].cutFromRight)) + buffer.text(x + starting - fromSymbol + patterns[i].cutFromLeft, y, patterns[i].color, unicode.sub(text, starting + patterns[i].cutFromLeft, ending - patterns[i].cutFromRight)) if ending > limit then break end searchFrom = ending + 1 else diff --git a/lib/windows.lua b/lib/windows.lua new file mode 100755 index 00000000..726ea4a0 --- /dev/null +++ b/lib/windows.lua @@ -0,0 +1,209 @@ + +----------------------------------------- Libraries ----------------------------------------- + +_G.GUI, package.loaded.GUI = nil, nil + +local libraries = { + computer = "computer", + doubleBuffering = "doubleBuffering", + GUI = "GUI", + unicode = "unicode", +} + +for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end; libraries = nil + +----------------------------------------- Main variables ----------------------------------------- + +local windows = {} + +windows.alignment = GUI.alignment + +windows.colors = { + background = 0xEEEEEE, + title = { + background = 0xDDDDDD, + text = 0x262626, + }, + tabBar = { + background = 0xDDDDDD, + text = 0x262626, + selectedTab = { + background = 0xCCCCCC, + text = 0x262626, + } + }, +} + +----------------------------------------- Universal window event handlers ----------------------------------------- + +local function executeObjectMethod(method, ...) + if method then method(...) end +end + +local function buttonHandler(window, object, objectIndex, eventData) + object.pressed = true; window:draw(); buffer.draw() + os.sleep(0.2) + object.pressed = false; window:draw(); buffer.draw() + executeObjectMethod(object.onTouch, object, eventData) +end + +local function tabBarTabHandler(window, object, objectIndex, eventData) + object.parent.parent.selectedTab = objectIndex + window:draw(); buffer:draw() + executeObjectMethod(object.parent.parent.onTabSwitched, object, eventData) +end + +local function inputTextBoxHandler(window, object, objectIndex, eventData) + object:input() + window:draw(); buffer:draw() + executeObjectMethod(object.onInputFinished, object, eventData) +end + +local function textBoxScrollHandler(window, object, objectIndex, eventData) + if eventData[5] == 1 then object:scrollUp(); window:draw(); buffer.draw() else object:scrollDown(); window:draw(); buffer.draw() end +end + +local function horizontalSliderHandler(window, object, objectIndex, eventData) + local clickPosition = eventData[3] - object.x + 1 + object.value = object.minimumValue + (clickPosition * (object.maximumValue - object.minimumValue) / object.width) + window:draw(); buffer:draw() + executeObjectMethod(object.onValueChanged, object, eventData) +end + +local function switchHandler(window, object, objectIndex, eventData) + object.state = not object.state + window:draw(); buffer:draw() + executeObjectMethod(object.onStateChanged, object, eventData) +end + +function windows.handleEventData(window, eventData) + if eventData[1] == "touch" then + local object, objectIndex = window:getClickedObject(eventData[3], eventData[4]) + if object then + if object.type == GUI.objectTypes.button then + buttonHandler(window, object, objectIndex, eventData) + elseif object.type == GUI.objectTypes.tabBarTab then + tabBarTabHandler(window, object, objectIndex, eventData) + elseif object.type == GUI.objectTypes.inputTextBox then + inputTextBoxHandler(window, object, objectIndex, eventData) + elseif object.type == GUI.objectTypes.horizontalSlider then + horizontalSliderHandler(window, object, objectIndex, eventData) + elseif object.type == GUI.objectTypes.switch then + switchHandler(window, object, objectIndex, eventData) + elseif object.onTouch then + executeObjectMethod(object.onTouch, object, eventData) + end + end + elseif eventData[1] == "scroll" then + local object, objectIndex = window:getClickedObject(eventData[3], eventData[4]) + if object then + if object.type == GUI.objectTypes.textBox then + textBoxScrollHandler(window, object, objectIndex, eventData) + elseif object.onScroll then + executeObjectMethod(object.onScroll, object, eventData) + end + end + elseif eventData[1] == "drag" then + local object, objectIndex = window:getClickedObject(eventData[3], eventData[4]) + if object then + if object.type == GUI.objectTypes.horizontalSlider then + horizontalSliderHandler(window, object, objectIndex, eventData) + elseif object.onDrag then + executeObjectMethod(object.onDrag, object, eventData) + end + end + elseif eventData[1] == "key_down" then + executeObjectMethod(window.onKeyDown, eventData) + end +end + +function windows.handleEvents(window) + while true do + window:handleEventData({event.pull()}) + if window.dataToReturn then return table.unpack(window.dataToReturn) end + end +end + +----------------------------------------- Window actions ----------------------------------------- + +function windows.returnData(window, ...) + window.dataToReturn = {...} + computer.pushSignal("windowAction") +end + +function windows.close(window) + windows.returnData(window, nil) +end + +----------------------------------------- Window creation ----------------------------------------- + +function windows.correctWindowCoordinates(x, y, width, height, minimumWidth, minimumHeight) + width = minimumWidth and math.max(width, minimumWidth) or width + height = minimumHeight and math.max(height, minimumHeight) or height + x = (x == "auto" and math.floor(buffer.screen.width / 2 - width / 2)) or x + y = (y == "auto" and math.floor(buffer.screen.height / 2 - height / 2)) or y + + return x, y, width, height +end + +local function drawWindow(window) + if window.onDrawStarted then window.onDrawStarted() end + window:reimplementedDraw() + if window.drawShadow then GUI.windowShadow(window.x, window.y, window.width, window.height, 50) end + if window.onDrawFinished then window.onDrawFinished() end +end + +local function newWindow(x, y, width, height, minimumWidth, minimumHeight) + x, y, width, height = windows.correctWindowCoordinates(x, y, width, height, minimumWidth, minimumHeight) + + local window = GUI.container(x, y, width, height) + window.minimumWidth = minimumWidth + window.minimumHeight = minimumHeight + window.drawShadow = true + window.reimplementedDraw = window.draw + window.draw = drawWindow + window.handleEventData = windows.handleEventData + window.handleEvents = windows.handleEvents + window.close = windows.close + window.returnData = windows.returnData + + return window +end + +----------------------------------------- Window patterns ----------------------------------------- + +function windows.empty(x, y, width, height, minimumWidth, minimumHeight, title) + local window = newWindow(x, y, width, height, minimumWidth, minimumHeight) + window.drawShadow = false + return window +end + +function windows.tabbed(x, y, width, height, minimumWidth, minimumHeight, ...) + local tabs = {...} + local window = newWindow(x, y, width, height, minimumWidth, minimumHeight) + window:addPanel("windowBackgroundPanel", 1, 1, window.width, window.height, 0xEEEEEE).disabled = true + window:addTabBar("tabBar", 1, 1, window.width, 3, 1, 0xDDDDDD, 0x262626, 0xCCCCCC, 0x262626, ...) + window:addWindowActionButtons("windowActionButtons", 2, 1, false) + + return window +end + +----------------------------------------- Playground ----------------------------------------- + +-- buffer.clear(0x262626) +-- buffer.draw(true) + +-- local myWindow = windows.empty(10, 5, 60, 20, 60, 20) +-- myWindow:addPanel("backgroundPanel", 1, 1, myWindow.width, myWindow.height, 0xEEEEEE) +-- myWindow:addLabel("counter", 2, 5, 20, 1, 0x000000, tostring(10)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) +-- myWindow:addHorizontalSlider("slider", 2, 4, 20, 0x880000, 0x000000, 0xFF4444, 0, 100, 10).onValueChanged = function(object) +-- myWindow.counter.text = tostring(object.value) +-- end + +-- myWindow:draw() +-- buffer.draw() +-- myWindow:handleEvents() + +----------------------------------------- End of shit ----------------------------------------- + +return windows