diff --git a/.DS_Store b/.DS_Store index 9ac708fd..a1c6944c 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Applications.txt b/Applications.txt index 311f9fd2..2b37e7b2 100644 --- a/Applications.txt +++ b/Applications.txt @@ -8,7 +8,7 @@ about="IgorTimofeev/OpenComputers/master/MineOS/About/", type="Script", forceDownload=true, - version=3.42, + version=3.43, }, { name="MineOS/Pictures/Raspberry.pic", @@ -253,7 +253,7 @@ name="lib/MineOSCore.lua", url="IgorTimofeev/OpenComputers/master/lib/MineOSCore.lua", type="Library", - version=1.38, + version=1.40, }, { name="lib/advancedLua.lua", @@ -300,13 +300,13 @@ name="lib/GUI.lua", url="IgorTimofeev/OpenComputers/master/lib/GUI.lua", type="Library", - version=1.22, + version=1.24, }, { name="lib/windows.lua", url="IgorTimofeev/OpenComputers/master/lib/windows.lua", type="Library", - version=1.06, + version=1.08, }, { name="lib/rayEngine.lua", @@ -372,7 +372,7 @@ name="lib/doubleBuffering.lua", url="IgorTimofeev/OpenComputers/master/lib/doubleBuffering.lua", type="Library", - version=1.17, + version=1.19, }, { name="lib/archive.lua", @@ -523,7 +523,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/GeoScan2/Icon.pic", createShortcut="desktop", - version=1.01, + version=1.02, resources={ { name="Earth.pic", @@ -629,7 +629,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/Control2/Icon.pic", createShortcut="desktop", - version=1.04, + version=1.05, resources={ { name="LuaLogo.pic", @@ -711,7 +711,7 @@ type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/RayWalk/Icon.pic", createShortcut="desktop", - version=1.58, + version=1.60, resources={ { name="Localization/Russian.lang", @@ -1004,7 +1004,7 @@ icon="IgorTimofeev/OpenComputers/master/Applications/AppMarket/Icon.pic", createShortcut="dock", forceDownload=true, - version=1.48, + version=1.49, resources={ { name="Localization/Russian.lang", diff --git a/Applications/.DS_Store b/Applications/.DS_Store index a4f48780..de42d1c6 100644 Binary files a/Applications/.DS_Store and b/Applications/.DS_Store differ diff --git a/Applications/AppMarket/AppMarket.lua b/Applications/AppMarket/AppMarket.lua index 4266912f..0fafe31b 100755 --- a/Applications/AppMarket/AppMarket.lua +++ b/Applications/AppMarket/AppMarket.lua @@ -75,7 +75,7 @@ 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.inputTextBox(math.floor(sizes.x + sizes.width / 2 - sizes.searchFieldWidth / 2), 1, sizes.searchFieldWidth, 1, 0xEEEEEE, 0x555555, 0xEEEEEE, 0x262626, 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, "", localization.search, true) end local function drawTopBar() @@ -195,14 +195,14 @@ local function drawMain(refreshData) buffer.setDrawLimit(sizes.x, obj.main.y, sizes.width, obj.main.height) - obj.searchTextField.y, obj.searchTextField.invisible = y, false + obj.searchTextField.y, obj.searchTextField.isHidden = y, false obj.searchTextField:draw() y = y + 2 local matchCount = 1 for i = 1, #newApplications do if newApplications[i].type == typeFilters[currentTopBarElement] then - if not obj.searchTextField.text or (string.find(unicode.lower(fs.name(newApplications[i].name)), unicode.lower(obj.searchTextField.text))) then + if obj.searchTextField.text == "" or (string.find(unicode.lower(fs.name(newApplications[i].name)), unicode.lower(obj.searchTextField.text))) then if matchCount >= from and matchCount <= from + limit - 1 then if refreshData and not currentApps[i] then status(localization.downloadingInfoAboutApplication .. " \"" .. newApplications[i].name .. "\"") @@ -246,7 +246,7 @@ end local function updates() clearMainZone() - obj.searchTextField.invisible = true + obj.searchTextField.isHidden = true if #changes > 0 then buffer.setDrawLimit(sizes.x, obj.main.y, sizes.width, obj.main.height) diff --git a/Applications/Control2/Modules/00_LuaConsole.lua b/Applications/Control2/Modules/00_LuaConsole.lua index f3d06cdb..57dacbf1 100644 --- a/Applications/Control2/Modules/00_LuaConsole.lua +++ b/Applications/Control2/Modules/00_LuaConsole.lua @@ -11,6 +11,7 @@ local module = { ---------------------------------------------------------------------------------------------------------------------------- function module.execute(window) + local luaConsoleCommandHistoryLimit = 20 local luaConsoleHistoryLimit = 50 local colors, printColor = { @@ -39,7 +40,8 @@ function module.execute(window) } local consoleTextBox = window.drawingArea:addTextBox(logoPanelWidth + 2, 1, consolePanelWidth - 2, window.drawingArea.height - 3, nil, 0xFFFFFF, lines, 1) - local consoleCommandInputTextBox = window.drawingArea:addInputTextBox(logoPanelWidth + 1, consolePanel.height - 2, consolePanel.width, 3, 0x333333, 0x777777, 0x333333, 0x444444, nil, "print(\"Hello, world!\")") + local consoleCommandInputTextBox = window.drawingArea:addInputTextBox(logoPanelWidth + 1, consolePanel.height - 2, consolePanel.width, 3, 0x333333, 0x777777, 0x333333, 0x444444, "", "print(\"Hello, world!\")") + consoleCommandInputTextBox.eraseTextOnFocus = true consoleCommandInputTextBox.highlightLuaSyntax = true consoleCommandInputTextBox.autocompleteVariables = true @@ -76,34 +78,32 @@ function module.execute(window) -- abc = function(a, b, c) local d = b ^ 2 - 4 * a * c; if d < 0 then error("Сууука!!! D < 0") end; x1 = (-b + math.sqrt(d)) / (2 * a); x2 = (-b - math.sqrt(d)) / (2 * a); return x1, x2 end consoleCommandInputTextBox.onInputFinished = function() - if consoleCommandInputTextBox.text then - -- Подменяем стандартный print() на мой пиздатый - local oldPrint = print - print = reimplementedPrint - -- Пишем, че мы вообще исполняли - addLines({"> " .. consoleCommandInputTextBox.text}, colors.passive) + -- Подменяем стандартный print() на мой пиздатый + local oldPrint = print + print = reimplementedPrint + -- Пишем, че мы вообще исполняли + addLines({"> " .. consoleCommandInputTextBox.text}, colors.passive) - -- Ебашим поддержку = - consoleCommandInputTextBox.text = consoleCommandInputTextBox.text:gsub("^[%s+]?%=[%s+]?", "return ") - local loadSuccess, loadReason = load(consoleCommandInputTextBox.text) - if loadSuccess then - local xpcallResult = {xpcall(loadSuccess, debug.traceback)} - if xpcallResult[1] then - table.remove(xpcallResult, 1) - reimplementedPrint(table.unpack(xpcallResult)) - else - addLines({xpcallResult[2]}, colors.error) - end + -- Ебашим поддержку = + consoleCommandInputTextBox.text = consoleCommandInputTextBox.text:gsub("^[%s+]?%=[%s+]?", "return ") + local loadSuccess, loadReason = load(consoleCommandInputTextBox.text) + if loadSuccess then + local xpcallResult = {xpcall(loadSuccess, debug.traceback)} + if xpcallResult[1] then + table.remove(xpcallResult, 1) + reimplementedPrint(table.unpack(xpcallResult)) else - addLines({loadReason}, colors.error) + addLines({xpcallResult[2]}, colors.error) end - - consoleCommandInputTextBox.text = nil - print = oldPrint - - window:draw() - buffer.draw() + else + addLines({loadReason}, colors.error) end + + consoleCommandInputTextBox.text = "" + print = oldPrint + + window:draw() + buffer.draw() end end diff --git a/Applications/GeoScan2/GeoScan2.lua b/Applications/GeoScan2/GeoScan2.lua index 19780fa9..aa5520cd 100644 --- a/Applications/GeoScan2/GeoScan2.lua +++ b/Applications/GeoScan2/GeoScan2.lua @@ -1,11 +1,11 @@ local component = require("component") -local MineOSCore = require("MineOSCore") +local colorlib = require("colorlib") +local image = require("image") +local buffer = require("doubleBuffering") local GUI = require("GUI") local windows = require("windows") -local image = require("image") -local colorlib = require("colorlib") -local buffer = require("doubleBuffering") +local MineOSCore = require("MineOSCore") -------------------------------------------------------------------------------------------------------------------- @@ -15,10 +15,7 @@ buffer.start() local resourcesDirectory = MineOSCore.getCurrentApplicationResourcesDirectory() local earthImage = image.load(resourcesDirectory .. "Earth.pic") -local glasses, geolyzer, projector -if component.isAvailable("glasses") then glasses = component.glasses end -if component.isAvailable("geolyzer") then geolyzer = component.geolyzer else GUI.error("This program requires a geolyzer to work!"); return end -if component.isAvailable("hologram") then projector = component.hologram end +if not component.isAvailable("geolyzer") then GUI.error("This program requires a geolyzer to work!"); return end local onScreenDataXOffset, onScreenDataYOffset = math.floor(buffer.screen.width / 2), buffer.screen.height local onProjectorDataYOffset = 0 @@ -33,7 +30,7 @@ local function getOpenGLValidColorChannels(color) end local function createCube(x, y, z, color, isVisThrObj) - local cube = glasses.addCube3D() + local cube = component.glasses.addCube3D() cube.set3DPos(x, y, z) cube.setVisibleThroughObjects(isVisThrObj) cube.setColor(getOpenGLValidColorChannels(color)) @@ -45,7 +42,7 @@ local function glassesCreateCube(x, y, z, color, text) local cube = createCube(x, y, z, color, true) cube.setVisibleThroughObjects(true) - local floatingText = glasses.addFloatingText() + local floatingText = component.glasses.addFloatingText() floatingText.set3DPos(x + 0.5, y + 0.5, z + 0.5) floatingText.setColor(1, 1, 1) floatingText.setAlpha(0.6) @@ -53,12 +50,8 @@ local function glassesCreateCube(x, y, z, color, text) floatingText.setScale(0.015) end -local function createDick() - local chance = math.random(1, 100) <= 100 - if chance then - local range = 48 - local isVisThrObj = true - local x, y, z = math.random(-range, range), math.random(-range, range), math.random(-range, range) +local function createDick(x, y, z, chance, isVisThrObj) + if math.random(1, 100) <= chance then createCube(x, y, z, 0xFFFFFF, isVisThrObj) createCube(x + 1, y, z, 0xFFFFFF, isVisThrObj) createCube(x + 2, y, z, 0xFFFFFF, isVisThrObj) @@ -81,11 +74,8 @@ local function updateData(onScreen, onProjector, onGlasses) local projectorAvailable = component.isAvailable("hologram") if onScreen then buffer.clear(0xEEEEEE) end - if onProjector and projectorAvailable then - projector.clear() - projector.setScale(window.projectorScaleSlider.value) - end - if onGlasses and glassesAvailable then glasses.removeAll() end + if onProjector and projectorAvailable then component.hologram.clear() end + if onGlasses and glassesAvailable then component.glasses.removeAll() end local min, max = tonumber(window.minimumHardnessTextBox.text), tonumber(window.maximumHardnessTextBox.text) local horizontalRange, verticalRange = math.floor(window.horizontalScanRangeSlider.value), math.floor(window.verticalScanRangeSlider.value) @@ -98,7 +88,7 @@ local function updateData(onScreen, onProjector, onGlasses) buffer.semiPixelSet(onScreenDataXOffset + x, onScreenDataYOffset + 32 - y, 0x454545) end if onProjector and window.projectorUpdateSwitch.state and projectorAvailable then - projector.set(horizontalRange + x, math.floor(window.projectorYOffsetSlider.value) + y - 32, horizontalRange + z, 1) + component.hologram.set(horizontalRange + x, math.floor(window.projectorYOffsetSlider.value) + y - 32, horizontalRange + z, 1) end if onGlasses and window.glassesUpdateSwitch.state and glassesAvailable then glassesCreateCube(x, y - 32, z, window.glassesOreColorButton.colors.default.background, "Hardness: " .. string.format("%.2f", scanResult[x][z][y])) @@ -136,16 +126,19 @@ objectY = objectY + 4 window:addLabel(buttonX, objectY, buttonWidth, 1, 0xFFFFFF, "Rendering properties"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) objectY = objectY + 2 -window.minimumHardnessTextBox = window:addInputTextBox(buttonX, objectY, 12, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, 2.7, nil, nil, true) +window.minimumHardnessTextBox = window:addInputTextBox(buttonX, objectY, 12, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(2.7), nil, true) window.minimumHardnessTextBox.validator = function(text) if tonumber(text) then return true end end -window.maximumHardnessTextBox = window:addInputTextBox(buttonX + 14, objectY, 12, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, 10, nil, nil, true) +window.maximumHardnessTextBox = window:addInputTextBox(buttonX + 14, objectY, 12, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(10), nil, true) window.maximumHardnessTextBox.validator = function(text) if tonumber(text) then return true end end objectY = objectY + 3 window:addLabel(buttonX, objectY, buttonWidth, 1, 0xBBBBBB, "Hardness min Hardness max"):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) objectY = objectY + 2 -window.projectorScaleSlider = window:addHorizontalSlider(buttonX, objectY, buttonWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xBBBBBB, 0.33, 3, projector.getScale(), false, "Projection scale: ") +window.projectorScaleSlider = window:addHorizontalSlider(buttonX, objectY, buttonWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xBBBBBB, 0.33, 3, component.hologram.getScale(), false, "Projection scale: ") +window.projectorScaleSlider.onValueChanged = function() + component.hologram.setScale(window.projectorScaleSlider.value) +end objectY = objectY + 3 window.projectorYOffsetSlider = window:addHorizontalSlider(buttonX, objectY, buttonWidth, 0xFFDB80, 0x000000, 0xFFDB40, 0xBBBBBB, 0, 64, 4, false, "Projection Y offset: ") window.projectorYOffsetSlider.roundValues = true @@ -158,10 +151,10 @@ local function setButtonColorFromPalette(button) end local function updateProjectorColors() - projector.setPaletteColor(1, window.color1Button.colors.default.background) + component.hologram.setPaletteColor(1, window.color1Button.colors.default.background) end -local color1, color2, color3 = projector.getPaletteColor(1), projector.getPaletteColor(2), projector.getPaletteColor(3) +local color1, color2, color3 = component.hologram.getPaletteColor(1), component.hologram.getPaletteColor(2), component.hologram.getPaletteColor(3) window.color1Button = window:addButton(buttonX, objectY, buttonWidth, 1, color1, 0xBBBBBB, 0xEEEEEE, 0x262626, "Projector color"); objectY = objectY + 1 window.color1Button.onTouch = function() setButtonColorFromPalette(window.color1Button) @@ -182,7 +175,7 @@ objectY = objectY + 2 window:addButton(buffer.screen.width, 1, 1, 1, nil, 0xEEEEEE, nil, 0xFF2222, "X").onTouch = function() window:close() - createDick() + createDick(math.random(-48, 48), math.random(1, 32), math.random(-48, 48), 100, false) end window:addButton(panelX, buffer.screen.height - 5, panelWidth, 3, 0x353535, 0xEEEEEE, 0xAAAAAA, 0x262626, "Update").onTouch = function() @@ -198,7 +191,7 @@ window.scanButton.onTouch = function() for x = -horizontalRange, horizontalRange do scanResult[x] = {} for z = -horizontalRange, horizontalRange do - scanResult[x][z] = geolyzer.scan(x, z) + scanResult[x][z] = component.geolyzer.scan(x, z) current = current + 1 progressReport(math.ceil(current / total * 100), "Scan progress: ") buffer.draw() @@ -212,6 +205,7 @@ end -------------------------------------------------------------------------------------------------------------------- +buffer.clear(0x0) window:draw() buffer.draw() window:handleEvents() diff --git a/Applications/RayWalk/RayWalk.lua b/Applications/RayWalk/RayWalk.lua index baf0d04c..d8629ac8 100755 --- a/Applications/RayWalk/RayWalk.lua +++ b/Applications/RayWalk/RayWalk.lua @@ -1,5 +1,5 @@ -package.loaded.rayEngine, package.loaded.GUI, package.loaded.windows, _G.rayEngine, _G.GUI, _G.windows = nil, nil, nil, nil, nil, nil, nil, nil +-- package.loaded.rayEngine, package.loaded.GUI, package.loaded.windows, _G.rayEngine, _G.GUI, _G.windows = nil, nil, nil, nil, nil, nil, nil, nil local fs = require("filesystem") local component = require("component") @@ -34,9 +34,9 @@ local function settings() window:addLabel(1, y, window.width, 1, 0xFFFFFF, localization.rayEngineProperties):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top); y = y + 3 - local resolutionTextBoxWidth = window:addInputTextBox(x, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, buffer.screen.width, nil, nil, true) + local resolutionTextBoxWidth = window:addInputTextBox(x, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(buffer.screen.width), nil, true) window:addLabel(x + textBoxWidth + 2, y + 1, 1, 1, 0xFFFFFF, "X") - local resolutionTextBoxHeight = window:addInputTextBox(x + textBoxWidth + 5, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, buffer.screen.height, nil, nil, true); y = y + 4 + local resolutionTextBoxHeight = window:addInputTextBox(x + textBoxWidth + 5, y, textBoxWidth, 3, 0x262626, 0xBBBBBB, 0x262626, 0xFFFFFF, tostring(buffer.screen.height), nil, true); y = y + 4 window:addLabel(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 @@ -164,7 +164,7 @@ 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() +-- rayEngine.intro() menu() rayEngine.update() diff --git a/MineOS/OS.lua b/MineOS/OS.lua index 7a8e8b96..dee3cf88 100755 --- a/MineOS/OS.lua +++ b/MineOS/OS.lua @@ -1,5 +1,5 @@ --- package.loaded.MineOSCore, package.loaded.GUI, package.loaded.windows = nil, nil, nil +package.loaded.MineOSCore, package.loaded.GUI, package.loaded.windows = nil, nil, nil ---------------------------------------------- Копирайт, епта ------------------------------------------------------------------------ diff --git a/lib/GUI.lua b/lib/GUI.lua index 51dafb56..41374ebe 100755 --- a/lib/GUI.lua +++ b/lib/GUI.lua @@ -80,7 +80,8 @@ GUI.objectTypes = enum( "switch", "progressBar", "chart", - "comboBox" + "comboBox", + "scrollBar" ) ----------------------------------------- Primitive objects ----------------------------------------- @@ -338,6 +339,11 @@ local function addMenuObjectToContainer(container, ...) return GUI.addChildToContainer(container, GUI.menu(...), GUI.objectTypes.menu) end +-- Add Menu object to container +local function addScrollBarObjectToContainer(container, ...) + return GUI.addChildToContainer(container, GUI.scrollBar(...), GUI.objectTypes.scrollBar) +end + -- Recursively draw container's content including all children container's content local function drawContainerContent(container) for objectIndex = 1, #container.children do @@ -394,6 +400,7 @@ function GUI.container(x, y, width, height) container.addChart = addChartObjectToContainer container.addComboBox = addComboBoxObjectToContainer container.addMenu = addMenuObjectToContainer + container.addScrollBar = addScrollBarObjectToContainer return container end @@ -974,167 +981,169 @@ local function autocompleteVariables(sourceText) end end --- local inputProperties = { --- --Метод, получающий на вход текущий текст и проверяющий вводимые данные. В случае успеха должен возвращать true --- validator = function(text) if string.match(text, "^%d+$") then return true end --- -- Автоматически очищает текстовое поле при начале ввода информации в него. --- -- Если при окончании ввода тексет не будет соответствовать методу validator, указанному выше, --- -- то будет возвращено исходное значение текста (не очищенное) --- eraseTextWhenInputBegins = true --- --Отключает символ многоточия при выходе за пределы текстового поля --- disableDots = true, --- --Попросту отрисовывает всю необходимую информацию без активации нажатия на клавиши --- justDrawNotEvent = true, --- --Задержка между миганимем курсора --- cursorBlinkDelay = 1.5, --- --Цвет курсора --- cursorColor = 0xFF7777, --- --Символ, используемый для отрисовки курсора --- cursorSymbol = "▌", --- --Символ-маскировщик, на который будет визуально заменен весь вводимый текст. Полезно для полей ввода пароля --- maskTextWithSymbol = "*", --- --Активация подсветки Lua-синтаксиса --- highlightLuaSyntax = true, --- -- Активация автозаполнения названий переменных по нажатию клавиши Tab --- autocompleteVariables = true, --- } - -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 = 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 function inputFieldDraw(inputField) + if inputField.oldPixels then + buffer.paste(inputField.x, inputField.y, inputField.oldPixels) + else + inputField.oldPixels = buffer.copy(inputField.x, inputField.y, inputField.width, 1) + end - local oldPixels = {}; for i = x, x + width - 1 do table.insert(oldPixels, { buffer.get(i, y) }) end - - local function drawOldPixels() - for i = 1, #oldPixels do buffer.set(x + i - 1, y, oldPixels[i][1], oldPixels[i][2], oldPixels[i][3]) end + if inputField.highlightLuaSyntax then + require("syntax").highlightString(inputField.x, inputField.y, inputField.text, inputField.textCutFrom, inputField.width) + else + buffer.text( + inputField.x, + inputField.y, + inputField.colors.text, + unicode.sub( + inputField.textMask and string.rep(inputField.textMask, unicode.len(inputField.text)) or inputField.text, + inputField.textCutFrom, + inputField.textCutFrom + inputField.width - 1 + ) + ) end - local function getTextLength() - textLength = unicode.len(text) + if inputField.cursorBlinkState then + buffer.text(inputField.x + inputField.cursorPosition - inputField.textCutFrom, inputField.y, inputField.cursorColor, inputField.cursorSymbol) end - local function textFormat() - local formattedText = text + return inputField +end - if inputProperties.maskTextWithSymbol then - formattedText = string.rep(inputProperties.maskTextWithSymbol or "*", textLength) - end - - if textLength > width then - if inputProperties.disableDots then - formattedText = unicode.sub(formattedText, -width, -1) - else - formattedText = "…" .. unicode.sub(formattedText, -width + 1, -1) - end - end - - return formattedText +local function inputFieldSetCursorPosition(inputField, newPosition) + if newPosition < 1 then + newPosition = 1 + elseif newPosition > unicode.len(inputField.text) + 1 then + newPosition = unicode.len(inputField.text) + 1 end - local function draw() - drawOldPixels() - 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 - local bg = buffer.get(cursorPosition, y) - buffer.set(cursorPosition, y, bg, cursorColor, cursorSymbol) - end - - if not inputProperties.justDrawNotEvent then buffer.draw() end + if newPosition > inputField.textCutFrom + inputField.width - 1 then + inputField.textCutFrom = inputField.textCutFrom + newPosition - (inputField.textCutFrom + inputField.width - 1) + elseif newPosition < inputField.textCutFrom then + inputField.textCutFrom = newPosition end - local function backspace() - if unicode.len(text) > 0 then text = unicode.sub(text, 1, -2); getTextLength(); draw() end - end + inputField.cursorPosition = newPosition - local function quit() - cursorBlinkState = false - if inputProperties.validator and not inputProperties.validator(text) then - text = startText - draw() - return startText - end - draw() - return text - end + return inputField +end - draw() - - if inputProperties.justDrawNotEvent then return startText end +local function inputFieldBeginInput(inputField) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() while true do - local e = { event.pull(cursorBlinkDelay) } - if e[1] == "key_down" then - if e[4] == 14 then - backspace() - elseif e[4] == 28 then - return quit() - elseif e[4] == 15 then - if inputProperties.autocompleteVariables then - text = autocompleteVariables(text); getTextLength(); draw() - end + local e = { event.pull(inputField.cursorBlinkDelay) } + if e[1] == "touch" or e[1] == "drag" then + if inputField:isClicked(e[3], e[4]) then + inputField:setCursorPosition(inputField.textCutFrom + e[3] - inputField.x) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() + else + inputField.cursorBlinkState = false; inputField:draw(); buffer.draw() + return inputField + end + elseif e[1] == "key_down" then + if e[4] == 28 then + inputField.cursorBlinkState = false; inputField:draw(); buffer.draw() + return inputField + elseif e[4] == 15 then + if inputField.autocompleteVariables then + inputField.text = autocompleteVariables(inputField.text) + inputField:setCursorPosition(unicode.len(inputField.text) + 1) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() + end + elseif e[4] == 203 then + inputField:setCursorPosition(inputField.cursorPosition - 1) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() + elseif e[4] == 205 then + inputField:setCursorPosition(inputField.cursorPosition + 1) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() + elseif e[4] == 14 then + inputField.text = unicode.sub(unicode.sub(inputField.text, 1, inputField.cursorPosition - 1), 1, -2) .. unicode.sub(inputField.text, inputField.cursorPosition, -1) + inputField:setCursorPosition(inputField.cursorPosition - 1) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() else - local symbol = unicode.char(e[3]) if not keyboard.isControl(e[3]) then - text = text .. symbol - getTextLength() - draw() + inputField.text = unicode.sub(inputField.text, 1, inputField.cursorPosition - 1) .. unicode.char(e[3]) .. unicode.sub(inputField.text, inputField.cursorPosition, -1) + inputField:setCursorPosition(inputField.cursorPosition + 1) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() end end elseif e[1] == "clipboard" then - text = text .. e[3] - getTextLength() - draw() - elseif e[1] == "touch" then - return quit() + inputField.text = unicode.sub(inputField.text, 1, inputField.cursorPosition - 1) .. e[3] .. unicode.sub(inputField.text, inputField.cursorPosition, -1) + inputField:setCursorPosition(inputField.cursorPosition + unicode.len(e[3])) + inputField.cursorBlinkState = true; inputField:draw(); buffer.draw() else - cursorBlinkState = not cursorBlinkState - draw() + inputField.cursorBlinkState = not inputField.cursorBlinkState; inputField:draw(); buffer.draw() end end end +function GUI.inputField(x, y, width, textColor, text, textMask, highlightLuaSyntax, autocompleteVariables) + local inputField = GUI.object(x, y, width, 1) + + inputField.textCutFrom = 1 + inputField.cursorPosition = 1 + inputField.cursorColor = 0x00A8FF + inputField.cursorSymbol = "┃" + inputField.cursorBlinkDelay = 0.4 + inputField.cursorBlinkState = false + + inputField.colors = {text = textColor} + inputField.text = text + inputField.textMask = textMask + inputField.highlightLuaSyntax = highlightLuaSyntax + inputField.autocompleteVariables = autocompleteVariables + + inputField.setCursorPosition = inputFieldSetCursorPosition + inputField.draw = inputFieldDraw + inputField.input = inputFieldBeginInput + + inputField:setCursorPosition(unicode.len(inputField.text) + 1) + + return inputField +end + ----------------------------------------- Input Text Box object ----------------------------------------- -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 "") +local function drawInputTextBox(inputTextBox) + local background = inputTextBox.isFocused and inputTextBox.colors.focused.background or inputTextBox.colors.default.background + local foreground = inputTextBox.isFocused and inputTextBox.colors.focused.text or inputTextBox.colors.default.text + local y = math.floor(inputTextBox.y + inputTextBox.height / 2) + local text = inputTextBox.isFocused and (inputTextBox.eraseTextOnFocus and "" or inputTextBox.text) or (inputTextBox.text ~= "" and inputTextBox.text or inputTextBox.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 + if background then + buffer.square(inputTextBox.x, inputTextBox.y, inputTextBox.width, inputTextBox.height, background, foreground, " ") + end + + if inputTextBox.isFocused then + local inputField = GUI.inputField(inputTextBox.x + 1, y, inputTextBox.width - 2, foreground, text, inputTextBox.textMask, inputTextBox.highlightLuaSyntax, inputTextBox.autocompleteVariables) + inputField:input() + + if inputTextBox.validator then + if inputTextBox.validator(inputField.text) then + inputTextBox.text = inputField.text + end + else + inputTextBox.text = inputField.text + end + else + GUI.inputField(inputTextBox.x + 1, y, inputTextBox.width - 2, foreground, text, inputTextBox.textMask, false, inputTextBox.autocompleteVariables):draw() + end + + return inputTextBox end -local function inputTextBoxBeginInput(object) - drawInputTextBox(object, true) - if object.text == "" then object.text = nil; drawInputTextBox(object, false); buffer.draw() end +local function inputTextBoxBeginInput(inputTextBox) + inputTextBox.isFocused = true + inputTextBox:draw() + inputTextBox.isFocused = false + + return inputTextBox end -function GUI.inputTextBox(x, y, width, height, inputTextBoxColor, textColor, inputTextBoxFocusedColor, textFocusedColor, text, placeholderText, maskTextWithSymbol, eraseTextOnFocus) - local object = GUI.object(x, y, width, height) - object.colors = { +function GUI.inputTextBox(x, y, width, height, inputTextBoxColor, textColor, inputTextBoxFocusedColor, textFocusedColor, text, placeholderText, eraseTextOnFocus, textMask, highlightLuaSyntax, autocompleteVariables) + local inputTextBox = GUI.object(x, y, width, height) + inputTextBox.colors = { default = { background = inputTextBoxColor, text = textColor @@ -1144,14 +1153,14 @@ function GUI.inputTextBox(x, y, width, height, inputTextBoxColor, textColor, inp text = textFocusedColor } } - object.text = text - object.placeholderText = placeholderText - object.isClicked = isObjectClicked - object.draw = drawInputTextBox - object.input = inputTextBoxBeginInput - object.eraseTextOnFocus = eraseTextOnFocus - object.textMask = maskTextWithSymbol - return object + inputTextBox.text = text + inputTextBox.placeholderText = placeholderText + inputTextBox.draw = drawInputTextBox + inputTextBox.input = inputTextBoxBeginInput + inputTextBox.eraseTextOnFocus = eraseTextOnFocus + inputTextBox.textMask = textMask + + return inputTextBox end ----------------------------------------- Text Box object ----------------------------------------- @@ -1407,10 +1416,75 @@ function GUI.comboBox(x, y, width, height, backgroundColor, textColor, arrowBack return object end +----------------------------------------- Scrollbar object ----------------------------------------- + +local function scrollBarDraw(scrollBar) + local isVertical = scrollBar.height > scrollBar.width + local valuesDelta = scrollBar.maximumValue - scrollBar.minimumValue + 1 + local part = scrollBar.value / valuesDelta + local barSize = math.ceil(scrollBar.shownValueCount / valuesDelta * scrollBar.height) + local halfBarSize = math.floor(barSize / 2) + + buffer.square(scrollBar.x, scrollBar.y, scrollBar.width, scrollBar.height, scrollBar.colors.background, 0x0, " ") + + if isVertical then + scrollBar.ghostPosition.x = scrollBar.x + scrollBar.ghostPosition.y = scrollBar.y + halfBarSize + scrollBar.ghostPosition.width = scrollBar.width + scrollBar.ghostPosition.height = scrollBar.height - barSize + + buffer.square( + scrollBar.ghostPosition.x, + math.floor(scrollBar.ghostPosition.y + part * scrollBar.ghostPosition.height - halfBarSize), + scrollBar.ghostPosition.width, + barSize, + scrollBar.colors.foreground, 0x0, " " + ) + else + scrollBar.ghostPosition.x = scrollBar.x + halfBarSize + scrollBar.ghostPosition.y = scrollBar.y + scrollBar.ghostPosition.width = scrollBar.width - barSize + scrollBar.ghostPosition.height = scrollBar.height + + buffer.square( + math.floor(scrollBar.ghostPosition.x + part * scrollBar.ghostPosition.width - halfBarSize), + scrollBar.ghostPosition.y, + barSize, + scrollBar.ghostPosition.height, + scrollBar.colors.foreground, 0x0, " " + ) + end + + return scrollBar +end + +function GUI.scrollBar(x, y, width, height, backgroundColor, foregroundColor, minimumValue, maximumValue, value, shownValueCount, onScrollValueIncrement, horizontalThin) + local scrollBar = GUI.object(x, y, width, height) + + scrollBar.maximumValue = maximumValue + scrollBar.minimumValue = minimumValue + scrollBar.value = value + scrollBar.onScrollValueIncrement = onScrollValueIncrement + scrollBar.shownValueCount = shownValueCount + scrollBar.thin = horizontalThin + scrollBar.colors = { + background = backgroundColor, + foreground = foregroundColor, + } + scrollBar.ghostPosition = {} + scrollBar.draw = scrollBarDraw + + return scrollBar +end + -------------------------------------------------------------------------------------------------------------------------------- --- buffer.start() --- buffer.clear(0x1b1b1b) +buffer.start() +buffer.clear(0x1b1b1b) + +-- GUI.scrollBar(1, 5, 1, 20, 0x444444, 0x00DBFF, 1, 100, 50, 20, 1, true):draw() + +-- buffer.draw() -- local comboBox = GUI.comboBox(2, 2, 30, 1, 0xFFFFFF, 0x262626, 0xDDDDDD, 0x262626, {"PIC", "RAW", "PNG", "JPG"}) -- comboBox:selectItem() @@ -1432,7 +1506,6 @@ end -- GUI.contextMenu(2, 2, {"Hello"}, {"World"}, "-", {"You are the"}, {"Best of best", false, "^S"}, {"And bestest yopta"}):show() - -------------------------------------------------------------------------------------------------------------------------------- return GUI diff --git a/lib/MineOSCore.lua b/lib/MineOSCore.lua index dafe3529..0d458e49 100755 --- a/lib/MineOSCore.lua +++ b/lib/MineOSCore.lua @@ -585,7 +585,7 @@ function MineOSCore.safeLaunch(path, ...) end local function tracebackMethod(xpcallTraceback) - local traceback, info, firstMatch = xpcallTraceback .. "\n" .. debug.traceback() + local traceback, info, firstMatch = tostring(xpcallTraceback) .. "\n" .. debug.traceback() for runLevel = 0, math.huge do info = debug.getinfo(runLevel) if info then @@ -607,7 +607,7 @@ function MineOSCore.safeLaunch(path, ...) end local runSuccess, runReason = xpcall(launchMethod, tracebackMethod) - if not runSuccess and not string.find(runReason.traceback, "interrupted", 1, 15) then + if not runSuccess and not string.match(runReason.traceback, "^table") and not string.find(runReason.traceback, "interrupted", 1, 15) then finalSuccess, finalPath, finalLine, finalTraceback = false, runReason.path, runReason.line, runReason.traceback end else diff --git a/lib/doubleBuffering.lua b/lib/doubleBuffering.lua index 1805017a..a5a24f95 100755 --- a/lib/doubleBuffering.lua +++ b/lib/doubleBuffering.lua @@ -149,12 +149,12 @@ end --Скопировать область изображения и вернуть ее в виде массива function buffer.copy(x, y, width, height) local copyArray = { - ["width"] = width, - ["height"] = height, + width = width, + height = height, } if x < 1 or y < 1 or x + width - 1 > buffer.screen.width or y + height - 1 > buffer.screen.height then - error("Область копирования выходит за пределы экрана.") + error("Copy field is out of screen range") end local index diff --git a/lib/windows.lua b/lib/windows.lua index 42b37578..65c63349 100755 --- a/lib/windows.lua +++ b/lib/windows.lua @@ -104,6 +104,34 @@ local function menuItemHandler(window, object, objectIndex, eventData) buffer.draw() end +local function scrollBarHandler(window, object, objectIndex, eventData) + if eventData[1] == "touch" or eventData[1] == "drag" then + local delta = object.maximumValue - object.minimumValue + 1 + if object.height > object.width then + object.value = math.floor((eventData[4] - object.y + 1) / object.height * delta) + else + object.value = math.floor((eventData[3] - object.x + 1) / object.width * delta) + end + elseif eventData[1] == "scroll" then + if eventData[5] == 1 then + if object.value >= object.minimumValue + object.onScrollValueIncrement then + object.value = object.value - object.onScrollValueIncrement + else + object.value = object.minimumValue + end + else + if object.value <= object.maximumValue - object.onScrollValueIncrement then + object.value = object.value + object.onScrollValueIncrement + else + object.value = object.maximumValue + end + end + end + window:draw() + buffer.draw() + executeObjectMethod(object.onTouch, eventData) +end + function windows.handleEventData(window, eventData) if eventData[1] == "touch" then local object, objectIndex = window:getClickedObject(eventData[3], eventData[4]) @@ -123,6 +151,8 @@ function windows.handleEventData(window, eventData) comboBoxHandler(window, object, objectIndex, eventData) elseif object.type == GUI.objectTypes.menuItem then menuItemHandler(window, object, objectIndex, eventData) + elseif object.type == GUI.objectTypes.scrollBar then + scrollBarHandler(window, object, objectIndex, eventData) elseif object.onTouch then executeObjectMethod(object.onTouch, eventData) end @@ -134,6 +164,8 @@ function windows.handleEventData(window, eventData) if object then if object.type == GUI.objectTypes.textBox then textBoxScrollHandler(window, object, objectIndex, eventData) + elseif object.type == GUI.objectTypes.scrollBar then + scrollBarHandler(window, object, objectIndex, eventData) elseif object.onScroll then executeObjectMethod(object.onScroll, eventData) end @@ -145,6 +177,8 @@ function windows.handleEventData(window, eventData) if object then if object.type == GUI.objectTypes.horizontalSlider then horizontalSliderHandler(window, object, objectIndex, eventData) + elseif object.type == GUI.objectTypes.scrollBar then + scrollBarHandler(window, object, objectIndex, eventData) elseif object.onDrag then executeObjectMethod(object.onDrag, eventData) end @@ -247,6 +281,12 @@ end -- buffer.clear(0x262626) -- buffer.draw(true) +-- local myWindow = windows.empty(2, 2, 60, 20, 60, 20) +-- myWindow:addScrollBar(1, 1, 1, 20, 0x444444, 0x00DBFF, 1, 100, 50, 20, 4, true) +-- myWindow:draw() +-- buffer.draw() +-- myWindow:handleEvents() + -- local myWindow = windows.empty(10, 5, 60, 20, 60, 20) -- myWindow:addPanel(1, 1, myWindow.width, myWindow.height, 0xEEEEEE) -- myWindow:addLabel(2, 5, 20, 1, 0x000000, tostring(10)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)