diff --git a/.DS_Store b/.DS_Store index 7b91a38e..b39e5b9b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Applications.txt b/Applications.txt index f4440f3b..d4abeeef 100644 --- a/Applications.txt +++ b/Applications.txt @@ -300,13 +300,13 @@ name="lib/GUI.lua", url="IgorTimofeev/OpenComputers/master/lib/GUI.lua", type="Library", - version=1.28, + version=1.29, }, { name="lib/windows.lua", url="IgorTimofeev/OpenComputers/master/lib/windows.lua", type="Library", - version=1.10, + version=1.11, }, { name="lib/rayEngine.lua", @@ -884,8 +884,8 @@ url="IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/MineCodeIDE.lua", type="Application", icon="IgorTimofeev/OpenComputers/master/Applications/MineCodeIDE/Icon.pic", - createShortcut="desktop", - version=1.06, + createShortcut="dock", + version=1.08, }, { name="MineOS/Applications/Battleship", diff --git a/Applications/.DS_Store b/Applications/.DS_Store index 744927d6..6da5a115 100644 Binary files a/Applications/.DS_Store and b/Applications/.DS_Store differ diff --git a/Applications/MineCodeIDE/MineCodeIDE.lua b/Applications/MineCodeIDE/MineCodeIDE.lua index 1951d4e2..ad4e3f5a 100755 --- a/Applications/MineCodeIDE/MineCodeIDE.lua +++ b/Applications/MineCodeIDE/MineCodeIDE.lua @@ -6,8 +6,8 @@ -- package.loaded.windows = nil -- package.loaded.MineOSCore = nil -local args = {...} require("advancedLua") +local computer = require("computer") local component = require("component") local gpu = component.gpu local fs = require("filesystem") @@ -19,14 +19,40 @@ local event = require("event") local syntax = require("syntax") local unicode = require("unicode") local ecs = require("ECSAPI") +local image = require("image") local keyboard = require("keyboard") ---------------------------------------------------- Constants ---------------------------------------------------- -- "/MineOS/Desktop/MineCode IDE.app/MineCode IDE.lua" +-- "/MineOS/Applications/MineCode IDE.app/MineCode IDE.lua" + +local args = {...} + +local config = { + indentaionWidth = 2, + colorScheme = { + topToolBar = 0xBBBBBB, + topMenu = { + backgroundColor = 0xEEEEEE, + textColor = 0x444444, + backgroundPressedColor = 0x3366CC, + textPressedColor = 0xFFFFFF, + }, + title = { + default = { + background = 0xDDDDDD, + text = 0x444444 + }, + warning = { + background = 0x880000, + text = 0xEEEEEE, + } + } + }, + scrollSpeed = 8, +} -local workPath -local clipboard local cursor = { position = { symbol = 20, @@ -38,23 +64,41 @@ local cursor = { blinkState = false, } +local workPath +local clipboard +local lastErrorLine local mainWindow = {} -local config = { - indentaionWidth = 2, - colorScheme = { - topToolBar = 0xBBBBBB, - topMenu = { - backgroundColor = 0xEEEEEE, - textColor = 0x444444, - backgroundPressedColor = 0x3366CC, - textPressedColor = 0xFFFFFF, - }, - }, - scrollSpeed = 8, -} + +---------------------------------------------------- Safe launch ---------------------------------------------------- + +local function showErrorMessage(text) + mainWindow.errorMessage.errorTextBox.lines = string.wrap({text}, mainWindow.errorMessage.errorTextBox.width) + mainWindow.errorMessage.height = 2 + #mainWindow.errorMessage.errorTextBox.lines + mainWindow.errorMessage.backgroundPanel.height = mainWindow.errorMessage.height + mainWindow.errorMessage.errorTextBox.height = mainWindow.errorMessage.height - 2 + + mainWindow.titleTextBox.colors.background, mainWindow.titleTextBox.colors.text = config.colorScheme.title.warning.background, config.colorScheme.title.warning.text + + for i = 1, 3 do component.computer.beep(1500, 0.08) end + mainWindow.errorMessage.isHidden = false +end + +local function hideErrorMessage() + mainWindow.titleTextBox.colors.background = config.colorScheme.title.default.background + mainWindow.titleTextBox.colors.text = config.colorScheme.title.default.text + mainWindow.errorMessage.isHidden = true +end ---------------------------------------------------- Cursor methods ---------------------------------------------------- +local function deselectLastErrorLine() + if lastErrorLine then mainWindow.codeView.highlights[lastErrorLine] = nil end +end + +local function clearSelection() + mainWindow.codeView.selections[1] = nil +end + local function fixFromLineByCursorPosition() if mainWindow.codeView.fromLine > cursor.position.line then mainWindow.codeView.fromLine = cursor.position.line @@ -92,14 +136,21 @@ local function setCursorPosition(symbol, line) cursor.position.symbol, cursor.position.line = fixCursorPosition(symbol, line) fixFromLineByCursorPosition() fixFromSymbolByCursorPosition() + deselectLastErrorLine() + clearSelection() + hideErrorMessage() end local function convertScreenCoordinatesToCursorPosition(x, y) return x - mainWindow.codeView.codeAreaPosition + mainWindow.codeView.fromSymbol - 1, y - mainWindow.codeView.y + mainWindow.codeView.fromLine end -local function clearSelection() - mainWindow.codeView.selections[1] = nil +local function isClickedOnCodeArea(x, y) + return + x >= mainWindow.codeView.codeAreaPosition and + y >= mainWindow.codeView.y and + x < mainWindow.width and + y < mainWindow.codeView.y + mainWindow.codeView.height - 1 end local function moveCursor(symbolOffset, lineOffset) @@ -118,6 +169,15 @@ local function setCursorPositionToEOF() setCursorPosition(unicode.len(mainWindow.codeView.lines[#mainWindow.codeView.lines]) + 1, #mainWindow.codeView.lines) end +local function gotoLine(line) + mainWindow.codeView.fromLine = math.floor(line - mainWindow.codeView.height / 2) + 1 + if mainWindow.codeView.fromLine < 1 then + mainWindow.codeView.fromLine = 1 + elseif mainWindow.codeView.fromLine > #mainWindow.codeView.lines then + mainWindow.codeView.fromLine = #mainWindow.codeView.lines + end +end + ---------------------------------------------------- File processing methods ---------------------------------------------------- local function loadFile(path) @@ -150,6 +210,7 @@ local function newFile() "end", "" } + workPath = nil setCursorPositionToEOF() end @@ -179,27 +240,42 @@ local function saveAs() ) if data[2] == "OK" then saveFile(data[1]) + workPath = data[1] end end +local function save() + saveFile(workPath) +end + local function run() + deselectLastErrorLine() + local loadSuccess, loadReason = load(table.concat(mainWindow.codeView.lines, "\n")) if loadSuccess then local oldResolutionX, oldResolutionY = gpu.getResolution() gpu.setBackground(0x262626); gpu.setForeground(0xFFFFFF); gpu.fill(1, 1, oldResolutionX, oldResolutionY, " "); require("term").setCursor(1, 1) - local xpcallSuccess, xpcallReason = xpcall(loadSuccess) + local xpcallSuccess, xpcallReason = xpcall(loadSuccess, debug.traceback) if xpcallSuccess then MineOSCore.waitForPressingAnyKey() - gpu.setResolution(oldResolutionX, oldResolutionY) - buffer.start() - mainWindow:draw() - buffer:draw() - else - end - else + gpu.setResolution(oldResolutionX, oldResolutionY) + buffer.start() + mainWindow:draw() + + if not xpcallSuccess then + showErrorMessage(xpcallReason) + end + + buffer:draw() + else + local match = string.match(loadReason, ":(%d+)%:") + lastErrorLine = tonumber(match) + mainWindow.codeView.highlights[lastErrorLine] = 0xFF4444 + gotoLine(lastErrorLine) + showErrorMessage(loadReason) end end @@ -440,17 +516,20 @@ end local function calculateSizes() if mainWindow.topToolBar.isHidden then - mainWindow.codeView.localPosition.y = 2 - mainWindow.codeView.height = mainWindow.height - 1 + mainWindow.codeView.localPosition.y, mainWindow.codeView.height = 2, mainWindow.height - 1 + mainWindow.errorMessage.localPosition.y = 2 else - mainWindow.codeView.localPosition.y = 5 - mainWindow.topToolBar.width = mainWindow.width - mainWindow.topToolBar.backgroundPanel.width = mainWindow.width - mainWindow.titleTextBox.width = math.floor(mainWindow.topToolBar.width * 0.28) - mainWindow.titleTextBox.localPosition.x = math.floor(mainWindow.topToolBar.width / 2 - mainWindow.titleTextBox.width / 2) - mainWindow.codeView.height = mainWindow.height - 4 + mainWindow.codeView.localPosition.y, mainWindow.codeView.height = 5, mainWindow.height - 4 + mainWindow.topToolBar.width, mainWindow.topToolBar.backgroundPanel.width = mainWindow.width, mainWindow.width + mainWindow.errorMessage.localPosition.y = 5 end + mainWindow.titleTextBox.width = math.floor(mainWindow.topToolBar.width * 0.32) + mainWindow.titleTextBox.localPosition.x = math.floor(mainWindow.topToolBar.width / 2 - mainWindow.titleTextBox.width / 2) + + mainWindow.errorMessage.localPosition.x, mainWindow.errorMessage.width = mainWindow.titleTextBox.localPosition.x, mainWindow.titleTextBox.width + mainWindow.errorMessage.backgroundPanel.width, mainWindow.errorMessage.errorTextBox.width = mainWindow.errorMessage.width, mainWindow.errorMessage.width - 4 + mainWindow.topMenu.width = mainWindow.width mainWindow.codeView.width = mainWindow.width end @@ -459,6 +538,12 @@ local function createWindow() mainWindow = windows.fullScreen() mainWindow.codeView = mainWindow:addCodeView(1, 1, 1, 1, {""}, 1, 1, 1, {}, {}, true) + mainWindow.codeView.scrollBars.vertical.onTouch = function() + mainWindow.codeView.fromLine = mainWindow.codeView.scrollBars.vertical.value + end + mainWindow.codeView.scrollBars.horizontal.onTouch = function() + mainWindow.codeView.fromSymbol = mainWindow.codeView.scrollBars.horizontal.value + end mainWindow.topMenu = mainWindow:addMenu(1, 1, 1, config.colorScheme.topMenu.backgroundColor, config.colorScheme.topMenu.textColor, config.colorScheme.topMenu.backgroundPressedColor, config.colorScheme.topMenu.textPressedColor) local item1 = mainWindow.topMenu:addItem("MineCode", 0x0) @@ -467,7 +552,7 @@ local function createWindow() menu:addItem("About", true).onTouch = function() end - menu:addItem("Quit MineCode").onTouch = function() + menu:addItem("Quit MineCode", false, "^W").onTouch = function() mainWindow:close() end menu:show() @@ -476,17 +561,17 @@ local function createWindow() local item2 = mainWindow.topMenu:addItem("File") item2.onTouch = function() local menu = GUI.contextMenu(item2.x, item2.y + 1) - menu:addItem("New").onTouch = function() + menu:addItem("New", false, "^N").onTouch = function() newFile() end - menu:addItem("Open").onTouch = function() + menu:addItem("Open", false, "^O").onTouch = function() open() end menu:addSeparator() - menu:addItem("Save", true).onTouch = function() - + menu:addItem("Save", not workPath, "^S").onTouch = function() + save() end - menu:addItem("Save as").onTouch = function() + menu:addItem("Save as", false, "^⇧S").onTouch = function() saveAs() end menu:show() @@ -495,7 +580,7 @@ local function createWindow() local item3 = mainWindow.topMenu:addItem("View") item3.onTouch = function() local menu = GUI.contextMenu(item3.x, item3.y + 1) - menu:addItem("Togle top toolbar").onTouch = function() + menu:addItem("Toggle top toolbar").onTouch = function() mainWindow.topToolBar.isHidden = not mainWindow.topToolBar.isHidden calculateSizes() end @@ -505,11 +590,12 @@ local function createWindow() -- mainWindow.topMenu:addItem("Properties") mainWindow.topToolBar = mainWindow:addContainer(1, 2, 1, 3) mainWindow.topToolBar.backgroundPanel = mainWindow.topToolBar:addPanel(1, 1, 1, 3, config.colorScheme.topToolBar) - mainWindow.titleTextBox = mainWindow.topToolBar:addTextBox(1, 1, 1, 3, 0xDDDDDD, 0x444444, {}, 1):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) + mainWindow.titleTextBox = mainWindow.topToolBar:addTextBox(1, 1, 1, 3, 0x0, 0x0, {}, 1):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top) mainWindow.runButton = mainWindow.topToolBar:addAdaptiveButton(1, 1, 2, 1, 0x444444, 0xFFFFFF, 0xFFFFFF, 0x444444, "Run") mainWindow.runButton.onTouch = function() run() end + mainWindow.toggleSyntaxHighlightingButton = mainWindow.topToolBar:addAdaptiveButton(8, 1, 2, 1, 0x262626, 0xDDDDDD, 0x262626, 0xDDDDDD, "Syntax") mainWindow.toggleSyntaxHighlightingButton.onTouch = function() mainWindow.codeView.highlightLuaSyntax = not mainWindow.codeView.highlightLuaSyntax @@ -521,12 +607,17 @@ local function createWindow() mainWindow.toggleSyntaxHighlightingButton.colors.pressed.background, mainWindow.toggleSyntaxHighlightingButton.colors.pressed.text = color1, color2 end + mainWindow.errorMessage = mainWindow:addContainer(1, 1, 1, 1) + mainWindow.errorMessage.backgroundPanel = mainWindow.errorMessage:addPanel(1, 1, 1, 1, 0xFFFFFF, 40) + mainWindow.errorMessage.errorTextBox = mainWindow.errorMessage:addTextBox(3, 2, 1, 1, nil, 0x262626, {}, 1) + hideErrorMessage() + mainWindow.onAnyEvent = function(eventData) cursor.blinkState = not cursor.blinkState local oldCursorState = cursor.blinkState cursor.blinkState = true - if eventData[1] == "touch" and mainWindow.codeView:isClicked(eventData[3], eventData[4]) then + if eventData[1] == "touch" and isClickedOnCodeArea(eventData[3], eventData[4]) then if eventData[5] == 1 then local menu = GUI.contextMenu(eventData[3], eventData[4]) menu:addItem("Cut", not mainWindow.codeView.selections[1], "^C").onTouch = function() @@ -544,10 +635,9 @@ local function createWindow() end menu:show() else - clearSelection() setCursorPosition(convertScreenCoordinatesToCursorPosition(eventData[3], eventData[4])) end - elseif eventData[1] == "drag" then + elseif eventData[1] == "drag" and isClickedOnCodeArea(eventData[3], eventData[4]) then if eventData[5] ~= 1 then mainWindow.codeView.selections[1] = mainWindow.codeView.selections[1] or {from = {}, to = {}} mainWindow.codeView.selections[1].from.symbol, mainWindow.codeView.selections[1].from.line = cursor.position.symbol, cursor.position.line @@ -582,7 +672,19 @@ local function createWindow() cut() -- W elseif eventData[4] == 17 then - + mainWindow:close() + -- N + elseif eventData[4] == 49 then + newFile() + -- O + elseif eventData[4] == 24 then + open() + -- S + Shift + elseif eventData[4] == 31 and keyboard.isKeyDown(42) then + saveAs() + -- S + elseif eventData[4] == 31 and workPath then + save() end -- Arrows up, down, left, right elseif eventData[4] == 200 then @@ -664,11 +766,12 @@ mainWindow.drawShadow = false mainWindow:draw() if args[1] == "open" and fs.exists(args[2]) then - loadFile("/lib/GUI.lua") + loadFile(args[2]) else newFile() end +mainWindow:draw() buffer.draw() mainWindow:handleEvents(cursor.blinkDelay) diff --git a/Installer/Installer.lua b/Installer/Installer.lua index e18a576f..4a4add3b 100644 --- a/Installer/Installer.lua +++ b/Installer/Installer.lua @@ -198,8 +198,9 @@ do language = data[1], dockShortcuts = { {path = "/MineOS/Applications/AppMarket.app"}, - {path = "/MineOS/Applications/VK.app"}, + {path = "/MineOS/Applications/MineCode IDE.app"}, {path = "/MineOS/Applications/Photoshop.app"}, + {path = "/MineOS/Applications/VK.app"}, } } diff --git a/lib/GUI.lua b/lib/GUI.lua index 636c9bcd..9cf696a8 100755 --- a/lib/GUI.lua +++ b/lib/GUI.lua @@ -1177,7 +1177,7 @@ 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 + if object.colors.background then buffer.square(object.x, object.y, object.width, object.height, object.colors.background, object.colors.text, " ", object.colors.transparency) end local xPos, yPos = GUI.getAlignmentCoordinates(object, {width = 1, height = object.height - object.offset.vertical * 2}) local lineLimit = object.width - object.offset.horizontal * 2 for line = object.currentLine, object.currentLine + object.height - 1 do diff --git a/lib/windows.lua b/lib/windows.lua index 8fcf273b..5c71fc42 100755 --- a/lib/windows.lua +++ b/lib/windows.lua @@ -105,30 +105,33 @@ local function menuItemHandler(window, object, objectIndex, eventData) end local function scrollBarHandler(window, object, objectIndex, eventData) + local newValue = object.value + 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) + newValue = math.floor((eventData[4] - object.y + 1) / object.height * delta) else - object.value = math.floor((eventData[3] - object.x + 1) / object.width * delta) + newValue = 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 + newValue = object.value - object.onScrollValueIncrement else - object.value = object.minimumValue + newValue = object.minimumValue end else if object.value <= object.maximumValue - object.onScrollValueIncrement then - object.value = object.value + object.onScrollValueIncrement + newValue = object.value + object.onScrollValueIncrement else - object.value = object.maximumValue + newValue = object.maximumValue end end end window:draw() buffer.draw() + object.value = newValue executeObjectMethod(object.onTouch, eventData) end