MineOS/lib/MineOSCore.lua
2017-09-17 22:10:06 +03:00

1574 lines
55 KiB
Lua
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---------------------------------------------- Libraries ------------------------------------------------------------------------
local component = require("component")
local computer = require("computer")
local event = require("event")
local advancedLua = require("advancedLua")
local image = require("image")
local buffer = require("doubleBuffering")
local GUI = require("GUI")
local fs = require("filesystem")
local unicode = require("unicode")
local keyboard = require("keyboard")
----------------------------------------------------------------------------------------------------------------
local MineOSCore = {}
MineOSCore.iconWidth = 12
MineOSCore.iconHeight = 6
MineOSCore.iconClickDelay = 0.2
MineOSCore.iconConfigFileName = ".icons"
MineOSCore.paths = {}
MineOSCore.paths.OS = "/MineOS/"
MineOSCore.paths.system = MineOSCore.paths.OS .. "System/"
MineOSCore.paths.extensionAssociations = MineOSCore.paths.system .. "ExtensionAssociations/"
MineOSCore.paths.localizationFiles = MineOSCore.paths.system .. "Localization/"
MineOSCore.paths.icons = MineOSCore.paths.system .. "Icons/"
MineOSCore.paths.applications = MineOSCore.paths.OS .. "Applications/"
MineOSCore.paths.pictures = MineOSCore.paths.OS .. "Pictures/"
MineOSCore.paths.desktop = MineOSCore.paths.OS .. "Desktop/"
MineOSCore.paths.applicationList = MineOSCore.paths.system .. "Applications.cfg"
MineOSCore.paths.trash = MineOSCore.paths.OS .. "Trash/"
MineOSCore.paths.OSSettings = MineOSCore.paths.system .. "Settings.cfg"
MineOSCore.paths.editor = MineOSCore.paths.applications .. "/MineCode IDE.app/Main.lua"
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 .. MineOSCore.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.createShortcut(where, forWhat)
fs.makeDirectory(fs.path(where))
local file = io.open(where, "w")
file:write(forWhat)
file:close()
end
function MineOSCore.readShortcut(path)
local file = io.open(path, "r")
local data = file:read("*a")
file:close()
return data
end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.saveOSSettings()
table.toFile(MineOSCore.paths.OSSettings, MineOSCore.OSSettings, true)
end
function MineOSCore.loadOSSettings()
MineOSCore.OSSettings = table.fromFile(MineOSCore.paths.OSSettings)
end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.associateExtensionLauncher(extension, pathToLauncher)
MineOSCore.OSSettings.extensionAssociations[extension] = MineOSCore.OSSettings.extensionAssociations[extension] or {}
MineOSCore.OSSettings.extensionAssociations[extension].launcher = pathToLauncher
end
function MineOSCore.associateExtensionIcon(extension, pathToIcon)
MineOSCore.OSSettings.extensionAssociations[extension] = MineOSCore.OSSettings.extensionAssociations[extension] or {}
MineOSCore.OSSettings.extensionAssociations[extension].icon = pathToIcon
end
function MineOSCore.associateExtensionContextMenu(extension, pathToContextMenu)
MineOSCore.OSSettings.extensionAssociations[extension] = MineOSCore.OSSettings.extensionAssociations[extension] or {}
MineOSCore.OSSettings.extensionAssociations[extension].contextMenu = pathToContextMenu
end
function MineOSCore.associateExtension(extension, pathToLauncher, pathToIcon, pathToContextMenu)
MineOSCore.associateExtensionLauncher(extension, pathToLauncher)
MineOSCore.associateExtensionIcon(extension, pathToIcon)
MineOSCore.associateExtensionContextMenu(extension, pathToContextMenu)
end
function MineOSCore.associationsExtensionAutomatically()
local path, extension = MineOSCore.paths.extensionAssociations
for file in fs.list(path) do
if fs.isDirectory(path .. file) then
extension = "." .. unicode.sub(file, 1, -2)
if fs.exists(path .. file .. "ContextMenu.lua") then
MineOSCore.associateExtensionContextMenu(extension, path .. file .. "Context menu.lua")
end
if fs.exists(path .. file .. "Launcher.lua") then
MineOSCore.associateExtensionLauncher(extension, path .. file .. "Launcher.lua")
end
end
end
end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.loadIcon(name, path)
if not MineOSCore.icons[name] then MineOSCore.icons[name] = image.load(path) end
return MineOSCore.icons[name]
end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.clearTerminal()
local gpu = component.gpu
gpu.setBackground(0x1D1D1D)
gpu.setForeground(0xFFFFFF)
local width, height = gpu.getResolution()
gpu.fill(1, 1, width, height, " ")
require("term").setCursor(1, 1)
end
function MineOSCore.waitForPressingAnyKey()
print(" ")
print(MineOSCore.localization.pressAnyKeyToContinue)
while true do
local eventType = event.pull()
if eventType == "key_down" or eventType == "touch" then
break
end
end
end
function MineOSCore.launchScript(path)
MineOSCore.clearTerminal()
if MineOSCore.safeLaunch(path) then
MineOSCore.waitForPressingAnyKey()
end
end
-----------------------------------------------------------------------------------------------------------------------------------
local function iconDraw(icon)
local text = string.limit(MineOSCore.OSSettings.showExtension and fs.name(icon.path) or fs.hideExtension(fs.name(icon.path)), icon.width, "center")
local textLength = unicode.len(text)
local textX, textY = math.floor(icon.x + icon.width / 2 - unicode.len(text) / 2), icon.y + icon.height - 1
if icon.selected then
local x, width = icon.x + 1, icon.width - 2
buffer.text(x, icon.y - 1, icon.colors.selection, string.rep("", width), icon.colors.selectionTransparency)
buffer.square(x, icon.y, width, icon.height - 2, icon.colors.selection, 0x000000, " ", icon.colors.selectionTransparency)
buffer.text(x, icon.y + icon.height - 2, icon.colors.selection, string.rep("", width), icon.colors.selectionTransparency)
buffer.square(textX, textY, textLength, 1, icon.colors.selection, 0x000000, " ", icon.colors.selectionTransparency)
end
buffer.text(textX, textY, icon.colors.text, text)
if icon.cut then
if not icon.semiTransparentImage then
icon.semiTransparentImage = image.copy(icon.image)
for i = 3, #icon.semiTransparentImage, 4 do
icon.semiTransparentImage[i + 2] = icon.semiTransparentImage[i + 2] + 0.6
if icon.semiTransparentImage[i + 2] > 1 then
icon.semiTransparentImage[i + 2] = 1
end
end
end
buffer.image(icon.x + 2, icon.y, icon.semiTransparentImage, true)
else
buffer.image(icon.x + 2, icon.y, icon.image)
end
if icon.isShortcut then
buffer.set(icon.x + 9, icon.y + 3, 0xFFFFFF, 0x000000, "<")
end
if icon.windows then
buffer.text(icon.x + 5, icon.y + 4, 0x66DBFF, "╺╸")
end
end
local function iconEventHandler(mainContainer, object, eventData)
if eventData[1] == "touch" then
object.lastTouchPosition = object.lastTouchPosition or {}
object.lastTouchPosition.x, object.lastTouchPosition.y = eventData[3], eventData[4]
object:moveToFront()
object.selected = true
mainContainer:draw()
buffer.draw()
if eventData[5] == 0 then
object.parent.parent.onLeftClick(object, eventData)
else
object.parent.parent.onRightClick(object, eventData)
object.selected = false
mainContainer:draw()
buffer.draw()
end
elseif eventData[1] == "double_touch" and object:isClicked(eventData[3], eventData[4]) and eventData[5] == 0 then
object.parent.parent.onDoubleClick(object, eventData)
elseif eventData[1] == "drag" and object.parent.parent.iconConfigEnabled and object.lastTouchPosition then
object.localPosition.x = object.localPosition.x + eventData[3] - object.lastTouchPosition.x
object.localPosition.y = object.localPosition.y + eventData[4] - object.lastTouchPosition.y
object.lastTouchPosition.x, object.lastTouchPosition.y = eventData[3], eventData[4]
mainContainer:draw()
buffer.draw()
elseif eventData[1] == "drop" and object.parent.parent.iconConfigEnabled then
object.parent.parent.iconConfig[fs.name(object.path)] = {
x = object.localPosition.x,
y = object.localPosition.y
}
object.parent.parent:saveIconConfig()
end
end
function MineOSCore.icon(x, y, path, textColor, selectionColor)
local icon = GUI.object(x, y, MineOSCore.iconWidth, MineOSCore.iconHeight)
icon.colors = {
text = textColor,
selection = selectionColor,
selectionTransparency = 0.6
}
icon.path = path
icon.isDirectory = fs.isDirectory(icon.path)
icon.extension = fs.extension(icon.path) or "script"
icon.isShortcut = false
icon.selected = false
icon.draw = iconDraw
icon.launchers = table.copy(MineOSCore.iconLaunchers)
icon.analyseExtension = iconAnalyseExtension
return icon
end
local function iconFieldUpdate(iconField)
iconField.backgroundObject.width, iconField.backgroundObject.height = iconField.width, iconField.height
iconField.iconsContainer.width, iconField.iconsContainer.height = iconField.width, iconField.height
iconField.iconCount.horizontal = math.floor((iconField.width - iconField.xOffset) / (MineOSCore.iconWidth + iconField.spaceBetweenIcons.horizontal))
iconField.iconCount.vertical = math.floor((iconField.height - iconField.yOffset) / (MineOSCore.iconHeight + iconField.spaceBetweenIcons.vertical))
iconField.iconCount.total = iconField.iconCount.horizontal * iconField.iconCount.vertical
return iconField
end
local function iconFieldLoadIconConfig(iconField)
if fs.exists(iconField.workpath .. MineOSCore.iconConfigFileName) then
iconField.iconConfig = table.fromFile(iconField.workpath .. MineOSCore.iconConfigFileName)
else
iconField.iconConfig = {}
end
end
local function iconFieldSaveIconConfig(iconField)
table.toFile(iconField.workpath .. MineOSCore.iconConfigFileName, iconField.iconConfig)
end
local function iconFieldDeleteIconConfig(iconField)
iconField.iconConfig = {}
fs.remove(iconField.workpath .. MineOSCore.iconConfigFileName, iconField.iconConfig)
end
-----------------------------------------------------------------------------------------------------------------------------------
MineOSCore.iconLaunchers = {}
function MineOSCore.iconLaunchers.application(icon)
MineOSCore.applicationHelp(MineOSCore.OSMainContainer, icon.path)
end
function MineOSCore.iconLaunchers.directory(icon)
icon.parent.parent:setWorkpath(icon.path)
icon.parent.parent:updateFileList()
icon:getFirstParent():draw()
buffer.draw()
end
function MineOSCore.iconLaunchers.shortcut(icon)
local oldPath = icon.path
icon.path = icon.shortcutPath
icon:shortcutLaunch()
icon.path = oldPath
end
function MineOSCore.iconLaunchers.corrupted(icon)
GUI.error("Application is corrupted")
end
function MineOSCore.iconLaunchers.extension(icon)
MineOSCore.safeLaunch(MineOSCore.OSSettings.extensionAssociations[icon.extension].launcher, icon.path, "-o")
end
function MineOSCore.iconLaunchers.script(icon)
MineOSCore.launchScript(icon.path)
end
function MineOSCore.iconLaunchers.showPackageContent(icon)
icon.parent.parent:setWorkpath(icon.path)
icon.parent.parent:updateFileList()
icon:getFirstParent():draw()
buffer.draw()
end
function MineOSCore.iconLaunchers.showContainingFolder(icon)
icon.parent.parent:setWorkpath(icon.shortcutPath)
icon.parent.parent:updateFileList()
icon:getFirstParent():draw()
buffer.draw()
end
function iconAnalyseExtension(icon)
if icon.isDirectory then
if icon.extension == ".app" then
if MineOSCore.OSSettings.showApplicationIcons then
icon.image = image.load(icon.path .. "/Resources/Icon.pic")
else
icon.image = MineOSCore.icons.application
end
icon.launch = icon.launchers.application
else
icon.image = MineOSCore.icons.folder
icon.launch = icon.launchers.directory
end
else
if icon.extension == ".lnk" then
icon.shortcutPath = MineOSCore.readShortcut(icon.path)
icon.shortcutExtension = fs.extension(icon.shortcutPath)
icon.shortcutIsDirectory = fs.isDirectory(icon.shortcutPath)
icon.isShortcut = true
local shortcutIcon = iconAnalyseExtension({
path = icon.shortcutPath,
extension = icon.shortcutExtension,
isDirectory = icon.shortcutIsDirectory,
iconImage = icon.iconImage,
launchers = icon.launchers
})
icon.image = shortcutIcon.image
icon.shortcutLaunch = shortcutIcon.launch
icon.launch = icon.launchers.shortcut
shortcutIcon = nil
elseif not fs.exists(icon.path) then
icon.image = MineOSCore.icons.fileNotExists
icon.launch = icon.launchers.corrupted
else
if MineOSCore.OSSettings.extensionAssociations[icon.extension] then
icon.launch = icon.launchers.extension
icon.image = MineOSCore.loadIcon(icon.extension, MineOSCore.OSSettings.extensionAssociations[icon.extension].icon)
else
icon.launch = icon.launchers.script
icon.image = MineOSCore.icons.script
end
end
end
return icon
end
-----------------------------------------------------------------------------------------------------------------------------------
local function iconFieldUpdateFileList(iconField)
iconField.fileList = fs.sortedList(iconField.workpath, iconField.sortingMethod, MineOSCore.OSSettings.showHiddenFiles)
iconField:update()
-- Грузим инфу об иконочках
if iconField.iconConfigEnabled then
iconField:loadIconConfig()
end
-- Заполнение дочернего контейнера
iconField.iconsContainer:deleteChildren()
local xPos, yPos, horizontalIconCounter = iconField.xOffset, iconField.yOffset, 1
for i = iconField.fromFile, iconField.fromFile + iconField.iconCount.total - 1 do
if iconField.fileList[i] then
if not iconField.filenameMatcher or string.unicodeFind(unicode.lower(iconField.fileList[i]), unicode.lower(iconField.filenameMatcher)) then
-- Выставление позиций иконок на основании конфига
local xIcon, yIcon, filename = xPos, yPos, fs.name(iconField.fileList[i])
if iconField.iconConfig[filename] then
xIcon, yIcon = iconField.iconConfig[filename].x, iconField.iconConfig[filename].y
else
xPos, horizontalIconCounter = xPos + MineOSCore.iconWidth + iconField.spaceBetweenIcons.horizontal, horizontalIconCounter + 1
if horizontalIconCounter > iconField.iconCount.horizontal then
xPos, horizontalIconCounter = iconField.xOffset, 1
yPos = yPos + MineOSCore.iconHeight + iconField.spaceBetweenIcons.vertical
end
if iconField.iconConfigEnabled then
iconField.iconConfig[filename] = {
x = xIcon,
y = yIcon
}
end
end
local icon = iconField.iconsContainer:addChild(
MineOSCore.icon(
xIcon, yIcon,
iconField.workpath .. iconField.fileList[i],
iconField.colors.text,
iconField.colors.selection
)
)
icon.eventHandler = iconEventHandler
icon.launchers = iconField.launchers
icon:analyseExtension()
end
else
break
end
end
if iconField.iconConfigEnabled then
iconField:saveIconConfig()
end
return iconField
end
local function iconFieldBackgroundObjectEventHandler(mainContainer, object, eventData)
if eventData[1] == "touch" then
if eventData[5] == 0 then
object.parent:deselectAll()
object.parent.selection = {
x1 = eventData[3],
y1 = eventData[4]
}
mainContainer:draw()
buffer.draw()
else
local menu = MineOSCore.contextMenu(eventData[3], eventData[4])
local subMenu = menu:addSubMenu(MineOSCore.localization.create)
subMenu:addItem(MineOSCore.localization.newFile).onTouch = function()
MineOSCore.newFile(MineOSCore.OSMainContainer, MineOSCore.OSMainContainer.iconField.workpath)
end
subMenu:addItem(MineOSCore.localization.newFolder).onTouch = function()
MineOSCore.newFolder(MineOSCore.OSMainContainer, MineOSCore.OSMainContainer.iconField.workpath)
end
subMenu:addItem(MineOSCore.localization.newFileFromURL, not component.isAvailable("internet")).onTouch = function()
MineOSCore.newFileFromURL(MineOSCore.OSMainContainer, MineOSCore.OSMainContainer.iconField.workpath)
end
subMenu:addSeparator()
subMenu:addItem(MineOSCore.localization.newApplication).onTouch = function()
MineOSCore.newApplication(MineOSCore.OSMainContainer, MineOSCore.OSMainContainer.iconField.workpath)
end
menu:addSeparator()
local subMenu = menu:addSubMenu(MineOSCore.localization.view)
subMenu:addItem(MineOSCore.OSSettings.showExtension and MineOSCore.localization.hideExtension or MineOSCore.localization.showExtension).onTouch = function()
MineOSCore.OSSettings.showExtension = not MineOSCore.OSSettings.showExtension
MineOSCore.saveOSSettings()
computer.pushSignal("MineOSCore", "updateFileList")
end
subMenu:addItem(MineOSCore.OSSettings.showHiddenFiles and MineOSCore.localization.hideHiddenFiles or MineOSCore.localization.showHiddenFiles).onTouch = function()
MineOSCore.OSSettings.showHiddenFiles = not MineOSCore.OSSettings.showHiddenFiles
MineOSCore.saveOSSettings()
computer.pushSignal("MineOSCore", "updateFileList")
end
subMenu:addItem(MineOSCore.OSSettings.showApplicationIcons and MineOSCore.localization.hideApplicationIcons or MineOSCore.localization.showApplicationIcons).onTouch = function()
MineOSCore.OSSettings.showApplicationIcons = not MineOSCore.OSSettings.showApplicationIcons
MineOSCore.saveOSSettings()
computer.pushSignal("MineOSCore", "updateFileList")
end
local subMenu = menu:addSubMenu(MineOSCore.localization.sortBy)
subMenu:addItem(MineOSCore.localization.sortByName).onTouch = function()
object.parent:deleteIconConfig()
MineOSCore.OSSettings.sortingMethod = "name"
MineOSCore.saveOSSettings()
MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod
computer.pushSignal("MineOSCore", "updateFileList")
end
subMenu:addItem(MineOSCore.localization.sortByDate).onTouch = function()
object.parent:deleteIconConfig()
MineOSCore.OSSettings.sortingMethod = "date"
MineOSCore.saveOSSettings()
MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod
computer.pushSignal("MineOSCore", "updateFileList")
end
subMenu:addItem(MineOSCore.localization.sortByType).onTouch = function()
object.parent:deleteIconConfig()
MineOSCore.OSSettings.sortingMethod = "type"
MineOSCore.saveOSSettings()
MineOSCore.OSMainContainer.iconField.sortingMethod = MineOSCore.OSSettings.sortingMethod
computer.pushSignal("MineOSCore", "updateFileList")
end
menu:addItem(MineOSCore.localization.sortAutomatically).onTouch = function()
object.parent:deleteIconConfig()
computer.pushSignal("MineOSCore", "updateFileList")
end
menu:addSeparator()
menu:addItem(MineOSCore.localization.paste, not MineOSCore.clipboard).onTouch = function()
local i = 1
while i <= #MineOSCore.clipboard do
if fs.exists(MineOSCore.clipboard[i]) then
i = i + 1
else
table.remove(MineOSCore.clipboard, i)
end
end
MineOSCore.copy(MineOSCore.clipboard, object.parent.workpath)
if MineOSCore.clipboard.cut then
for i = 1, #MineOSCore.clipboard do
fs.remove(MineOSCore.clipboard[i])
end
MineOSCore.clipboard = nil
end
computer.pushSignal("MineOSCore", "updateFileList")
end
menu:show()
end
elseif eventData[1] == "drag" then
if object.parent.selection then
object.parent.selection.x2 = eventData[3]
object.parent.selection.y2 = eventData[4]
object:moveToFront()
mainContainer:draw()
buffer.draw()
end
elseif eventData[1] == "drop" then
object.parent.selection = nil
object:moveToBack()
mainContainer:draw()
buffer.draw()
end
end
local function iconFieldBackgroundObjectDraw(object)
if object.parent.selection and object.parent.selection.x2 then
local x1, y1, x2, y2 = object.parent.selection.x1, object.parent.selection.y1, object.parent.selection.x2, object.parent.selection.y2
if x2 < x1 then
x1, x2 = x2, x1
end
if y2 < y1 then
y1, y2 = y2, y1
end
buffer.square(x1, y1, x2 - x1 + 1, y2 - y1 + 1, object.parent.colors.selection, 0x0, " ", 0.6)
for i = 1, #object.parent.iconsContainer.children do
local xCenter, yCenter = object.parent.iconsContainer.children[i].x + MineOSCore.iconWidth / 2, object.parent.iconsContainer.children[i].y + MineOSCore.iconHeight / 2
object.parent.iconsContainer.children[i].selected =
xCenter >= x1 and
xCenter <= x2 and
yCenter >= y1 and
yCenter <= y2
end
end
end
local function iconFieldDeselectAll(iconField)
for i = 1, #iconField.iconsContainer.children do
iconField.iconsContainer.children[i].selected = false
end
end
local function iconFieldGetSelectedIcons(iconField)
local selectedIcons = {}
for i = 1, #iconField.iconsContainer.children do
if iconField.iconsContainer.children[i].selected then
table.insert(selectedIcons, iconField.iconsContainer.children[i])
end
end
return selectedIcons
end
local function iconFieldSetWorkpath(iconField, path)
iconField.workpath = path
iconField.filenameMatcher = nil
iconField.fromFile = 1
return iconField
end
function MineOSCore.iconField(x, y, width, height, xSpaceBetweenIcons, ySpaceBetweenIcons, xOffset, yOffset, textColor, selectionColor, sortingMethod, workpath)
local iconField = GUI.container(x, y, width, height)
iconField.colors = {
text = textColor,
selection = selectionColor
}
iconField.spaceBetweenIcons = {
horizontal = xSpaceBetweenIcons,
vertical = ySpaceBetweenIcons
}
iconField.iconConfig = {}
iconField.iconCount = {}
iconField.fileList = {}
iconField.fromFile = 1
iconField.iconConfigEnabled = false
iconField.xOffset = xOffset
iconField.yOffset = yOffset
iconField.workpath = workpath
iconField.sortingMethod = sortingMethod
iconField.filenameMatcher = nil
iconField.backgroundObject = iconField:addChild(GUI.object(1, 1, width, height))
iconField.backgroundObject.eventHandler = iconFieldBackgroundObjectEventHandler
iconField.backgroundObject.draw = iconFieldBackgroundObjectDraw
iconField.iconsContainer = iconField:addChild(GUI.container(1, 1, width, height))
iconField.updateFileList = iconFieldUpdateFileList
iconField.update = iconFieldUpdate
iconField.eventHandler = iconFieldEventHandler
iconField.deselectAll = iconFieldDeselectAll
iconField.loadIconConfig = iconFieldLoadIconConfig
iconField.saveIconConfig = iconFieldSaveIconConfig
iconField.deleteIconConfig = iconFieldDeleteIconConfig
iconField.getSelectedIcons = iconFieldGetSelectedIcons
iconField.setWorkpath = iconFieldSetWorkpath
iconField.onLeftClick = MineOSCore.iconLeftClick
iconField.onRightClick = MineOSCore.iconRightClick
iconField.onDoubleClick = MineOSCore.iconDoubleClick
iconField.launchers = table.copy(MineOSCore.iconLaunchers)
return iconField
end
-----------------------------------------------------------------------------------------------------------------------------------
--Функция парсинга Lua-сообщения об ошибке. Конвертирует из строки в массив.
function MineOSCore.parseErrorMessage(error, indentationWidth)
local parsedError = {}
--Замена /r/n и табсов
error = string.gsub(error, "\r\n", "\n")
error = string.gsub(error, " ", string.rep(" ", indentationWidth or 4))
--Удаление энтеров
local searchFrom, starting, ending = 1
for i = 1, unicode.len(error) do
starting, ending = string.find(error, "\n", searchFrom)
if starting then
table.insert(parsedError, unicode.sub(error, searchFrom, starting - 1))
searchFrom = ending + 1
else
break
end
end
--На всякий случай, если сообщение об ошибке без энтеров вообще, т.е. однострочное
if #parsedError == 0 then table.insert(parsedError, error) end
return parsedError
end
function MineOSCore.showErrorWindow(path, errorLine, reason)
buffer.clear(0x0, 0.5)
local mainContainer = GUI.container(1, 1, buffer.width, math.floor(buffer.height * 0.45))
mainContainer.y = math.floor(buffer.height / 2 - mainContainer.height / 2)
mainContainer:addChild(GUI.panel(1, 1, mainContainer.width, 3, 0x383838))
mainContainer:addChild(GUI.label(1, 2, mainContainer.width, 1, 0xFFFFFF, MineOSCore.localization.errorWhileRunningProgram .. "\"" .. fs.name(path) .. "\"")):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)
local actionButtons = mainContainer:addChild(GUI.actionButtons(2, 2, false))
local sendToDeveloperButton = mainContainer:addChild(GUI.adaptiveButton(9, 1, 2, 1, 0x444444, 0xFFFFFF, 0x343434, 0xFFFFFF, MineOSCore.localization.sendFeedback))
local codeView = mainContainer:addChild(GUI.codeView(1, 4, math.floor(mainContainer.width * 0.62), mainContainer.height - 3, {}, 1, 1, 100, {}, {[errorLine] = 0xFF4444}, true, 2))
codeView.scrollBars.horizontal.hidden = true
codeView.fromLine = errorLine - math.floor((mainContainer.height - 3) / 2) + 1
if codeView.fromLine <= 0 then codeView.fromLine = 1 end
local toLine, lineCounter = codeView.fromLine + codeView.height - 1, 1
for line in io.lines(path) do
if lineCounter >= codeView.fromLine and lineCounter <= toLine then
codeView.lines[lineCounter] = string.gsub(line, " ", " ")
elseif lineCounter < codeView.fromLine then
codeView.lines[lineCounter] = " "
elseif lineCounter > toLine then
break
end
lineCounter = lineCounter + 1
end
mainContainer:addChild(GUI.textBox(codeView.width + 1, 4, mainContainer.width - codeView.width, codeView.height, 0xFFFFFF, 0x000000, string.wrap(MineOSCore.parseErrorMessage(reason, 4), mainContainer.width - codeView.width - 2), 1, 1, 0))
actionButtons.close.onTouch = function()
mainContainer:stopEventHandling()
end
mainContainer.eventHandler = function(mainContainer, object, eventData)
if eventData[1] == "key_down" and eventData[4] == 28 then
actionButtons.close.onTouch()
end
end
sendToDeveloperButton.onTouch = function()
if component.isAvailable("internet") then
local url = "https://api.mcmodder.ru/ECS/report.php?path=" .. path .. "&errorMessage=" .. string.optimizeForURLRequests(reason)
local success, reason = component.internet.request(url)
if success then
success:close()
end
sendToDeveloperButton.text = MineOSCore.localization.sendedFeedback
mainContainer:draw()
buffer.draw()
os.sleep(1)
end
actionButtons.close.onTouch()
end
mainContainer:draw()
buffer.draw()
for i = 1, 3 do
component.computer.beep(1500, 0.08)
end
mainContainer:startEventHandling()
end
function MineOSCore.call(method, ...)
local args = {...}
local function launchMethod()
method(table.unpack(args))
end
local function tracebackMethod(xpcallTraceback)
local traceback, info, firstMatch = tostring(xpcallTraceback) .. "\n" .. debug.traceback()
for runLevel = 0, math.huge do
info = debug.getinfo(runLevel)
if info then
if (info.what == "main" or info.what == "Lua") and info.source ~= "=machine" then
if firstMatch then
return {
path = info.source:sub(2, -1),
line = info.currentline,
traceback = traceback
}
else
firstMatch = true
end
end
else
error("Failed to get debug info for runlevel " .. runLevel)
end
end
end
local xpcallSuccess, xpcallReason = xpcall(launchMethod, tracebackMethod)
if type(xpcallReason) == "string" or type(xpcallReason) == "nil" then xpcallReason = {path = "/lib/MineOSCore.lua", line = 1, traceback = "MineOSCore fatal error: " .. tostring(xpcallReason)} end
if not xpcallSuccess and not xpcallReason.traceback:match("^table") and not xpcallReason.traceback:match("interrupted") then
return false, xpcallReason.path, xpcallReason.line, xpcallReason.traceback
end
return true
end
function MineOSCore.safeLaunch(path, ...)
path = path:gsub("/+", "/")
MineOSCore.lastLaunchPath = path
local oldResolutionWidth, oldResolutionHeight = buffer.width, buffer.height
local finalSuccess, finalPath, finalLine, finalTraceback = true
if fs.exists(path) then
local loadSuccess, loadReason = loadfile("/" .. path)
if loadSuccess then
local success, path, line, traceback = MineOSCore.call(loadSuccess, ...)
if not success then
finalSuccess, finalPath, finalLine, finalTraceback = false, path, line, traceback
end
else
local match = string.match(loadReason, ":(%d+)%:")
finalSuccess, finalPath, finalLine, finalTraceback = false, path, tonumber(match) or 1, loadReason
end
else
GUI.error("Failed to safely launch file that doesn't exists: \"" .. path .. "\"")
end
component.screen.setPrecise(false)
buffer.setResolution(oldResolutionWidth, oldResolutionHeight)
if not finalSuccess then
MineOSCore.showErrorWindow(finalPath, finalLine, finalTraceback)
end
return finalSuccess, finalPath, finalLine, finalTraceback
end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.contextMenu(...)
local menu = GUI.contextMenu(...)
menu.colors.transparency.background = MineOSCore.OSSettings.transparencyEnabled and GUI.colors.contextMenu.transparency.background
menu.colors.transparency.shadow = MineOSCore.OSSettings.transparencyEnabled and GUI.colors.contextMenu.transparency.shadow
return menu
end
function MineOSCore.iconLeftClick(icon, eventData)
if not keyboard.isKeyDown(29) and not keyboard.isKeyDown(219) then
icon.parent.parent:deselectAll()
end
icon.selected = true
MineOSCore.OSDraw()
end
function MineOSCore.iconDoubleClick(icon, eventData)
icon:launch()
computer.pushSignal("MineOSCore", "updateFileList")
end
function MineOSCore.iconRightClick(icon, eventData)
icon.selected = true
MineOSCore.OSDraw()
local selectedIcons = icon.parent.parent:getSelectedIcons()
local menu = MineOSCore.contextMenu(eventData[3], eventData[4])
if #selectedIcons == 1 then
if icon.isDirectory then
if icon.extension == ".app" then
menu:addItem(MineOSCore.localization.showPackageContent).onTouch = function()
icon.parent.parent.launchers.showPackageContent(icon)
end
menu:addItem(MineOSCore.localization.launchWithArguments).onTouch = function()
MineOSCore.launchWithArguments(MineOSCore.OSMainContainer, icon.path)
end
end
menu:addItem(MineOSCore.localization.archive).onTouch = function()
require("compressor").pack(fs.path(icon.path) .. fs.hideExtension(fs.name(icon.path)) .. ".pkg", icon.path)
computer.pushSignal("MineOSCore", "updateFileList")
end
menu:addSeparator()
else
if icon.isShortcut then
menu:addItem(MineOSCore.localization.editShortcut).onTouch = function()
MineOSCore.editShortcut(MineOSCore.OSMainContainer, icon.path)
computer.pushSignal("MineOSCore", "updateFileList")
end
menu:addItem(MineOSCore.localization.showContainingFolder).onTouch = function()
icon.parent.parent.launchers.showContainingFolder(icon)
end
menu:addSeparator()
else
if MineOSCore.OSSettings.extensionAssociations[icon.extension] and MineOSCore.OSSettings.extensionAssociations[icon.extension].contextMenu then
pcall(loadfile(MineOSCore.OSSettings.extensionAssociations[icon.extension].contextMenu), icon, menu)
menu:addSeparator()
end
-- local subMenu = menu:addSubMenu(MineOSCore.localization.openWith)
-- local fileList = fs.sortedList(MineOSCore.paths.applications, "name")
-- subMenu:addItem(MineOSCore.localization.select)
-- subMenu:addSeparator()
-- for i = 1, #fileList do
-- subMenu:addItem(fs.hideExtension(fileList[i]))
-- end
end
end
end
if #selectedIcons > 1 then
menu:addItem(MineOSCore.localization.newFolderFromChosen .. " (" .. #selectedIcons .. ")").onTouch = function()
MineOSCore.newFolderFromChosen(MineOSCore.OSMainContainer, selectedIcons)
end
menu:addSeparator()
end
local function cutOrCopy(cut)
for i = 1, #icon.parent.children do
icon.parent.children[i].cut = nil
end
MineOSCore.clipboard = {cut = cut}
for i = 1, #selectedIcons do
selectedIcons[i].cut = cut
table.insert(MineOSCore.clipboard, selectedIcons[i].path)
end
end
menu:addItem(MineOSCore.localization.cut).onTouch = function()
cutOrCopy(true)
end
menu:addItem(MineOSCore.localization.copy).onTouch = function()
cutOrCopy()
end
if not icon.isShortcut or #selectedIcons > 1 then
local subMenu = menu:addSubMenu(MineOSCore.localization.createShortcut)
subMenu:addItem(MineOSCore.localization.inCurrentDirectory).onTouch = function()
for i = 1, #selectedIcons do
if not selectedIcons[i].isShortcut then
MineOSCore.createShortcut(
fs.path(selectedIcons[i].path) .. "/" .. fs.hideExtension(fs.name(selectedIcons[i].path)) .. ".lnk",
selectedIcons[i].path
)
end
end
computer.pushSignal("MineOSCore", "updateFileList")
end
subMenu:addItem(MineOSCore.localization.onDesktop).onTouch = function()
for i = 1, #selectedIcons do
if not selectedIcons[i].isShortcut then
MineOSCore.createShortcut(
MineOSCore.paths.desktop .. "/" .. fs.hideExtension(fs.name(selectedIcons[i].path)) .. ".lnk",
selectedIcons[i].path
)
end
end
computer.pushSignal("MineOSCore", "updateFileList")
end
end
if #selectedIcons == 1 then
menu:addItem(MineOSCore.localization.rename).onTouch = function()
MineOSCore.rename(MineOSCore.OSMainContainer, icon.path)
end
end
menu:addItem(MineOSCore.localization.delete).onTouch = function()
for i = 1, #selectedIcons do
if fs.path(selectedIcons[i].path) == MineOSCore.paths.trash then
fs.remove(selectedIcons[i].path)
else
local newName = MineOSCore.paths.trash .. fs.name(selectedIcons[i].path)
local clearName = fs.hideExtension(fs.name(selectedIcons[i].path))
local repeats = 1
while fs.exists(newName) do
newName, repeats = MineOSCore.paths.trash .. clearName .. string.rep("-copy", repeats) .. selectedIcons[i].extension, repeats + 1
end
fs.rename(selectedIcons[i].path, newName)
end
end
computer.pushSignal("MineOSCore", "updateFileList")
end
menu:addSeparator()
if #selectedIcons == 1 then
menu:addItem(MineOSCore.localization.addToDock).onTouch = function()
MineOSCore.OSMainContainer.dockContainer.addIcon(icon.path).keepInDock = true
MineOSCore.OSMainContainer.dockContainer.saveToOSSettings()
end
end
menu:addItem(MineOSCore.localization.properties).onTouch = function()
for i = 1, #selectedIcons do
MineOSCore.propertiesWindow(eventData[3], eventData[4], 40, selectedIcons[i])
end
end
menu:show()
icon.parent.parent:deselectAll()
MineOSCore.OSDraw()
end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.addUniversalContainer(parentContainer, title)
local container = parentContainer:addChild(GUI.container(1, 1, parentContainer.width, parentContainer.height))
container.panel = container:addChild(GUI.panel(1, 1, container.width, container.height, MineOSCore.OSSettings.transparencyEnabled and 0x0 or (MineOSCore.OSSettings.backgroundColor or 0x0F0F0F), MineOSCore.OSSettings.transparencyEnabled and 0.2))
container.layout = container:addChild(GUI.layout(1, 1, container.width, container.height, 1, 1))
if title then
container.layout:addChild(GUI.label(1, 1, unicode.len(title), 1, 0xEEEEEE, title)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)
end
container.panel.eventHandler = function(mainContainer, object, eventData)
if eventData[1] == "touch" then
container:delete()
mainContainer:draw()
buffer.draw()
end
end
return container
end
-----------------------------------------------------------------------------------------------------------------------------------
local function addUniversalContainerWithInputTextBox(parentWindow, text, title, placeholder)
local container = MineOSCore.addUniversalContainer(parentWindow, title)
container.inputField = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, text, placeholder, false))
container.label = container.layout:addChild(GUI.label(1, 1, 36, 1, 0xFF4940, MineOSCore.localization.file .. " " .. MineOSCore.localization.alreadyExists)):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top)
container.label.hidden = true
return container
end
local function checkFileToExists(container, path)
if fs.exists(path) then
container.label.hidden = false
container.parent:draw()
buffer.draw()
else
container:delete()
fs.makeDirectory(fs.path(path))
return true
end
end
function MineOSCore.newApplication(parentWindow, path)
local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newApplication, MineOSCore.localization.applicationName)
local filesystemChooser = container.layout:addChild(GUI.filesystemChooser(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x444444, 0x999999, nil, MineOSCore.localization.open, MineOSCore.localization.cancel, MineOSCore.localization.iconPath, "/"))
filesystemChooser:addExtensionFilter(".pic")
filesystemChooser:moveBackward()
container.panel.eventHandler = function(mainContainer, object, eventData)
if eventData[1] == "touch" then
container:delete()
if container.inputField.text then
local finalPath = path .. container.inputField.text .. ".app/"
if checkFileToExists(container, finalPath) then
fs.makeDirectory(finalPath .. "/Resources/")
fs.copy(filesystemChooser.path or MineOSCore.paths.icons .. "SampleIcon.pic", finalPath .. "/Resources/Icon.pic")
local file = io.open(finalPath .. "Main.lua", "w")
file:write("require(\"GUI\").error(\"Hello world\")")
file:close()
computer.pushSignal("MineOSCore", "updateFileList")
end
else
parentWindow:draw()
buffer.draw()
end
end
end
parentWindow:draw()
buffer.draw()
end
function MineOSCore.newFile(parentWindow, path)
local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newFile, MineOSCore.localization.fileName)
container.inputField.onInputFinished = function()
if checkFileToExists(container, path .. container.inputField.text) then
local file = io.open(path .. container.inputField.text, "w")
file:close()
MineOSCore.safeLaunch(MineOSCore.paths.editor, path .. container.inputField.text)
computer.pushSignal("MineOSCore", "updateFileList")
end
end
parentWindow:draw()
buffer.draw()
end
function MineOSCore.newFolder(parentWindow, path)
local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newFolder, MineOSCore.localization.folderName)
container.inputField.onInputFinished = function()
if checkFileToExists(container, path .. container.inputField.text) then
fs.makeDirectory(path .. container.inputField.text)
computer.pushSignal("MineOSCore", "updateFileList")
end
end
parentWindow:draw()
buffer.draw()
return container
end
function MineOSCore.newFolderFromChosen(parentWindow, selectedIcons)
local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.newFolderFromChosen .. " (" .. #selectedIcons .. ")", MineOSCore.localization.folderName)
container.inputField.onInputFinished = function()
local path = fs.path(selectedIcons[1].path) .. container.inputField.text
if checkFileToExists(container, path) then
fs.makeDirectory(path)
for i = 1, #selectedIcons do
fs.rename(selectedIcons[i].path, path .. "/" .. fs.name(selectedIcons[i].path))
end
computer.pushSignal("MineOSCore", "updateFileList")
end
end
parentWindow:draw()
buffer.draw()
return container
end
function MineOSCore.rename(parentWindow, path)
local container = addUniversalContainerWithInputTextBox(parentWindow, fs.name(path), MineOSCore.localization.rename, MineOSCore.localization.newName)
container.inputField.onInputFinished = function()
if checkFileToExists(container, fs.path(path) .. container.inputField.text) then
fs.rename(path, fs.path(path) .. container.inputField.text)
computer.pushSignal("MineOSCore", "updateFileList")
end
end
parentWindow:draw()
buffer.draw()
container.inputField:startInput()
end
function MineOSCore.editShortcut(parentWindow, path)
local text = MineOSCore.readShortcut(path)
local container = addUniversalContainerWithInputTextBox(parentWindow, text, MineOSCore.localization.editShortcut, MineOSCore.localization.rename)
container.panel.eventHandler = nil
container.inputField.onInputFinished = function()
if fs.exists(container.inputField.text) then
MineOSCore.createShortcut(path, container.inputField.text)
container:delete()
computer.pushSignal("MineOSCore", "updateFileList")
else
container.label.text = MineOSCore.localization.shortcutIsCorrupted
container.label.hidden = false
MineOSCore.OSDraw()
end
end
parentWindow:draw()
buffer.draw()
container.inputField:startInput()
end
function MineOSCore.launchWithArguments(parentWindow, path)
local container = addUniversalContainerWithInputTextBox(parentWindow, nil, MineOSCore.localization.launchWithArguments)
container.inputField.onInputFinished = function()
local args = {}
if container.inputField.text then
for arg in container.inputField.text:gmatch("[^%s]+") do
table.insert(args, arg)
end
end
container:delete()
MineOSCore.clearTerminal()
if MineOSCore.safeLaunch(path, table.unpack(args)) then
MineOSCore.waitForPressingAnyKey()
end
parentWindow:draw()
buffer.draw(true)
end
end
function MineOSCore.applicationHelp(parentWindow, path)
local pathToAboutFile = path .. "/resources/About/" .. MineOSCore.OSSettings.language .. ".txt"
if MineOSCore.OSSettings.showHelpOnApplicationStart and fs.exists(pathToAboutFile) then
local container = MineOSCore.addUniversalContainer(parentWindow, MineOSCore.localization.applicationHelp .. "\"" .. fs.name(path) .. "\"")
local lines = {}
for line in io.lines(pathToAboutFile) do
table.insert(lines, line)
end
container.layout:addChild(GUI.textBox(1, 1, 50, 1, nil, 0xcccccc, lines, 1, 0, 0, true, true))
local button = container.layout:addChild(GUI.button(1, 1, 30, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.dontShowAnymore))
container.panel.eventHandler = function(mainContainer, object, eventData)
if eventData[1] == "touch" then
container:delete()
MineOSCore.safeLaunch(path .. "/Main.lua")
end
end
button.onTouch = function()
MineOSCore.OSSettings.showHelpOnApplicationStart = false
MineOSCore.saveOSSettings()
container:delete()
MineOSCore.safeLaunch(path .. "/Main.lua")
end
else
MineOSCore.safeLaunch(path .. "/Main.lua")
end
parentWindow:draw()
buffer.draw()
end
function MineOSCore.newFileFromURL(parentWindow, path)
local container = addUniversalContainerWithInputTextBox(parentWindow, nil, "Загрузить файл по URL", MineOSCore.localization.fileName)
container.inputFieldURL = container.layout:addChild(GUI.inputField(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, nil, "URL", false))
container.inputField.onInputFinished = function()
if container.inputField.text then
if fs.exists(path .. container.inputField.text) then
container.label.hidden = false
parentWindow:draw()
buffer.draw()
else
if container.inputFieldURL.text then
local success, reason = require("web").downloadFile(container.inputFieldURL.text, path .. container.inputField.text)
if not success then
GUI.error(reason)
end
container:delete()
computer.pushSignal("MineOSCore", "updateFileList")
end
end
end
end
container.inputFieldURL.onInputFinished = container.inputField.onInputFinished
parentWindow:draw()
buffer.draw()
end
----------------------------------------- Windows patterns -----------------------------------------
local function windowResize(window, width, height)
window.width, window.height = width, height
if window.onResize then window.onResize(width, height) end
return window
end
function MineOSCore.addWindow(window)
window.x = window.x or math.floor(MineOSCore.OSMainContainer.windowsContainer.width / 2 - window.width / 2)
window.y = window.y or math.floor(MineOSCore.OSMainContainer.windowsContainer.height / 2 - window.height / 2)
MineOSCore.OSMainContainer.windowsContainer:addChild(window)
-- Получаем путь исполняемого файла
MineOSCore.lastLaunchPath = MineOSCore.lastLaunchPath or "/OS.lua"
local lastLaunchPathPath = fs.path(MineOSCore.lastLaunchPath)
if fs.extension(lastLaunchPathPath) == ".app" then
MineOSCore.lastLaunchPath = lastLaunchPathPath
end
-- Хуячим иконку в докыч, если такой еще не существует
local dockIcon
for i = 1, #MineOSCore.OSMainContainer.dockContainer.children do
if MineOSCore.OSMainContainer.dockContainer.children[i].path == MineOSCore.lastLaunchPath then
dockIcon = MineOSCore.OSMainContainer.dockContainer.children[i]
break
end
end
dockIcon = dockIcon or MineOSCore.OSMainContainer.dockContainer.addIcon(MineOSCore.lastLaunchPath, window)
-- Ебурим ссылку на окно в иконку
dockIcon.windows = dockIcon.windows or {}
dockIcon.windows[window] = true
window.resize = windowResize
window.close = function(window)
local sameIconExists = false
for i = 1, #MineOSCore.OSMainContainer.dockContainer.children do
if
MineOSCore.OSMainContainer.dockContainer.children[i].path == MineOSCore.lastLaunchPath and
MineOSCore.OSMainContainer.dockContainer.children[i].windows and
table.size(MineOSCore.OSMainContainer.dockContainer.children[i].windows) > 1
then
sameIconExists = true
break
end
end
if not sameIconExists then
dockIcon.windows = nil
if not dockIcon.keepInDock then
dockIcon:delete()
MineOSCore.OSMainContainer.dockContainer.sort()
end
end
window:delete()
MineOSCore.OSDraw()
end
window.maximize = function(window)
if window.maximized then
window.localPosition.x = window.oldGeometry.x
window.localPosition.y = window.oldGeometry.y
window:resize(window.oldGeometry.width, window.oldGeometry.height)
else
window.oldGeometry = {
x = window.localPosition.x,
y = window.localPosition.y,
width = window.width,
height = window.height
}
window.localPosition.x, window.localPosition.y = 1, 1
window:resize(window.parent.width, window.parent.height)
end
window.maximized = not window.maximized
MineOSCore.OSDraw()
end
window.minimize = function(window)
window.hidden = true
MineOSCore.OSDraw()
end
if window.actionButtons then
window.actionButtons.close.onTouch = function()
window.close(window)
end
window.actionButtons.maximize.onTouch = function()
window.maximize(window)
end
window.actionButtons.minimize.onTouch = function()
window.minimize(window)
end
end
MineOSCore.lastLaunchPath = nil
return MineOSCore.OSMainContainer, window
end
-----------------------------------------------------------------------------------------------------------------------------------
local function addKeyAndValue(window, x, y, key, value)
x = x + window:addChild(GUI.label(x, y, unicode.len(key) + 1, 1, 0x333333, key .. ":")).width + 1
return window:addChild(GUI.label(x, y, unicode.len(value), 1, 0x555555, value))
end
function MineOSCore.propertiesWindow(x, y, width, icon)
local mainContainer, window = MineOSCore.addWindow(GUI.titledWindow(x, y, width, 1, package.loaded.MineOSCore.localization.properties))
-- window.backgroundPanel.colors.transparency = 0.25
window:addChild(GUI.image(2, 3, icon.image))
local x, y = 11, 3
addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.type, icon.extension and icon.extension or (icon.isDirectory and package.loaded.MineOSCore.localization.folder or package.loaded.MineOSCore.localization.unknown)); y = y + 1
local fileSizeLabel = addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.size, icon.isDirectory and package.loaded.MineOSCore.localization.calculatingSize or string.format("%.2f", fs.size(icon.path) / 1024) .. " KB"); y = y + 1
addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.date, os.date("%d.%m.%y, %H:%M", math.floor(fs.lastModified(icon.path) / 1000))); y = y + 1
addKeyAndValue(window, x, y, package.loaded.MineOSCore.localization.path, " ")
local textBox = window:addChild(GUI.textBox(17, y, window.width - 18, 1, nil, 0x555555, {icon.path}, 1, 0, 0, true, true))
window.onResize = function(width, height)
window.backgroundPanel.width, window.backgroundPanel.height = width, height
end
window:resize(window.width, textBox.y + textBox.height)
textBox.eventHandler = nil
mainContainer:draw()
buffer.draw()
if icon.isDirectory then
fileSizeLabel.text = string.format("%.2f", fs.directorySize(icon.path) / 1024) .. " KB"
mainContainer:draw()
buffer.draw()
end
end
-----------------------------------------------------------------------------------------------------------------------------------
local function GUICopy(parentContainer, fileList, toPath)
local applyYes, breakRecursion
local container = MineOSCore.addUniversalContainer(parentContainer, MineOSCore.localization.copying)
local textBox = container.layout:addChild(GUI.textBox(1, 1, container.width, 1, nil, 0x777777, {}, 1, 0, 0, true, true):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.top))
local switchAndLabel = container.layout:addChild(GUI.switchAndLabel(1, 1, 37, 8, 0x66DB80, 0x2D2D2D, 0xEEEEEE, 0x777777, MineOSCore.localization.applyToAll .. ":", false))
container.panel.eventHandler = nil
local buttonsLayout = container.layout:addChild(GUI.layout(1, 1, 1, 1, 1, 1))
buttonsLayout:addChild(GUI.button(1, 1, 11, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.yes)).onTouch = function()
applyYes = true
parentContainer:stopEventHandling()
end
buttonsLayout:addChild(GUI.button(1, 1, 11, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.no)).onTouch = function()
parentContainer:stopEventHandling()
end
buttonsLayout:addChild(GUI.button(1, 1, 11, 1, 0xEEEEEE, 0x262626, 0xAAAAAA, 0x262626, MineOSCore.localization.cancel)).onTouch = function()
breakRecursion = true
parentContainer:stopEventHandling()
end
buttonsLayout:setCellDirection(1, 1, GUI.directions.horizontal)
buttonsLayout:setCellSpacing(1, 1, 2)
buttonsLayout:fitToChildrenSize(1, 1)
local function copyOrMove(path, finalPath)
switchAndLabel.hidden = true
buttonsLayout.hidden = true
textBox.lines = {
MineOSCore.localization.copying .. " " .. MineOSCore.localization.faylaBlyad .. " " .. fs.name(path) .. " " .. MineOSCore.localization.toDirectory .. " " .. string.canonicalPath(toPath),
}
textBox.height = #textBox.lines
parentContainer:draw()
buffer.draw()
fs.remove(finalPath)
fs.copy(path, finalPath)
end
local function recursiveCopy(path, toPath)
local finalPath = toPath .. "/" .. fs.name(path)
if fs.isDirectory(path) then
fs.makeDirectory(finalPath)
for file in fs.list(path) do
if breakRecursion then
return
end
recursiveCopy(path .. "/" .. file, finalPath)
end
else
if fs.exists(finalPath) then
if not switchAndLabel.switch.state then
switchAndLabel.hidden = false
buttonsLayout.hidden = false
applyYes = false
textBox.lines = {
MineOSCore.localization.file .. " " .. fs.name(path) .. " " .. MineOSCore.localization.alreadyExists .. " " .. MineOSCore.localization.inDirectory .. " " .. string.canonicalPath(toPath),
MineOSCore.localization.needReplace,
}
textBox.height = #textBox.lines
parentContainer:draw()
buffer.draw()
parentContainer:startEventHandling()
parentContainer:draw()
buffer.draw()
end
if applyYes then
copyOrMove(path, finalPath)
end
else
copyOrMove(path, finalPath)
end
end
end
for i = 1, #fileList do
recursiveCopy(fileList[i], toPath)
end
container:delete()
parentContainer:draw()
buffer.draw()
end
function MineOSCore.copy(what, toPath)
if type(what) == "string" then
what = {what}
end
GUICopy(MineOSCore.OSMainContainer, what, toPath)
end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.init()
MineOSCore.icons = {}
MineOSCore.loadOSSettings()
MineOSCore.localization = table.fromFile(MineOSCore.paths.localizationFiles .. MineOSCore.OSSettings.language .. ".lang")
fs.makeDirectory(MineOSCore.paths.trash)
MineOSCore.OSSettings.extensionAssociations = MineOSCore.OSSettings.extensionAssociations or {}
MineOSCore.loadIcon("folder", MineOSCore.paths.icons .. "Folder.pic")
MineOSCore.loadIcon("fileNotExists", MineOSCore.paths.icons .. "FileNotExists.pic")
MineOSCore.loadIcon("application", MineOSCore.paths.icons .. "Application.pic")
MineOSCore.loadIcon("trash", MineOSCore.paths.icons .. "Trash.pic")
MineOSCore.loadIcon("script", MineOSCore.paths.icons .. "Script.pic")
MineOSCore.associateExtension(".pic", MineOSCore.paths.applications .. "/Photoshop.app/Main.lua", MineOSCore.paths.icons .. "/Image.pic", MineOSCore.paths.extensionAssociations .. "Pic/ContextMenu.lua")
MineOSCore.associateExtension(".txt", MineOSCore.paths.editor, MineOSCore.paths.icons .. "/Text.pic")
MineOSCore.associateExtension(".cfg", MineOSCore.paths.editor, MineOSCore.paths.icons .. "/Config.pic")
MineOSCore.associateExtension(".3dm", MineOSCore.paths.applications .. "/3DPrint.app/Main.lua", MineOSCore.paths.icons .. "/3DModel.pic")
MineOSCore.associateExtension("script", MineOSCore.paths.extensionAssociations .. "Lua/Launcher.lua", MineOSCore.paths.icons .. "/Script.pic", MineOSCore.paths.extensionAssociations .. "Lua/ContextMenu.lua")
MineOSCore.associateExtension(".lua", MineOSCore.paths.extensionAssociations .. "Lua/Launcher.lua", MineOSCore.paths.icons .. "/Lua.pic", MineOSCore.paths.extensionAssociations .. "Lua/ContextMenu.lua")
MineOSCore.associateExtension(".pkg", MineOSCore.paths.extensionAssociations .. "Pkg/Launcher.lua", MineOSCore.paths.icons .. "/Archive.pic")
MineOSCore.saveOSSettings()
end
-----------------------------------------------------------------------------------------------------------------------------------
MineOSCore.init()
-- buffer.clear(0x0)
-- buffer.draw(true)
-- local cykaContainer = GUI.fullScreenContainer()
-- cykaContainer:addChild(GUI.panel(1, 1, cykaContainer.width, cykaContainer.height, 0xFF0000))
-- GUICopy(cykaContainer, "/MineOS/papka/", "/MineOS/mamka/", true)
-----------------------------------------------------------------------------------------------------------------------------------
return MineOSCore