41 Commits

Author SHA1 Message Date
kepler155c@gmail.com
d17162b49d can now use named colors 2020-04-21 22:32:53 -06:00
kepler155c@gmail.com
949c485539 changes for deprecated ui methods - recolor milo - make turtle scripts run again - mob rancher improvements 2020-04-17 20:41:58 -06:00
kepler155c@gmail.com
3246579ab1 cleanup 2020-04-16 23:11:59 -06:00
kepler155c@gmail.com
6b429a26e4 editor path issues 2020-04-14 14:12:44 -06:00
kepler155c@gmail.com
ef6cde3013 editor recent/peripherals/redo + cleanup 2020-04-12 18:46:04 -06:00
kepler155c@gmail.com
569dd5572d cleanup + undo overhaul 2020-04-10 22:51:56 -06:00
kepler155c@gmail.com
3321866ba3 cleanup + editor additions 2020-04-09 16:08:04 -06:00
kepler155c@gmail.com
1cbe87033d completions + refactor 2020-04-06 00:10:22 -06:00
kepler155c@gmail.com
0a7ec352cc more editor work 2020-04-04 20:55:29 -06:00
kepler155c@gmail.com
f655cc5965 more tweaks 2020-04-03 18:56:55 -06:00
kepler155c@gmail.com
6bb4149113 editor 2.0 2020-04-02 21:29:28 -06:00
kepler155c@gmail.com
e2aac13e8f Merge remote-tracking branch 'origin/develop-1.8' into ui-enhancements-2.0 2020-03-31 10:14:04 -06:00
kepler155c@gmail.com
cdea6e4aed canvas overhaul 2020-03-31 10:08:07 -06:00
Anavrins
d287e3fe91 Merge pull request #27 from Lemmmy/patch-1
Temporary patch for #20
2020-03-27 15:11:20 -04:00
Drew Lemmy
b08a0f225e Temporary patch for #20
A more comprehensive fix should be found in the future
2020-03-27 17:09:04 +00:00
Anavrins
408601f0d2 Swshop: whoops 2020-03-24 00:17:35 -04:00
Anavrins
996b8c1cd3 Swshop: Configurable lamp side 2020-03-24 00:09:51 -04:00
Anavrins
2dc74d80ea Milo: Bump max request amount to 9999 2020-03-23 23:41:16 -04:00
Anavrins
afcbfd1b04 Added a "Level Emitter" to Milo 2020-02-24 21:10:30 -05:00
Anavrins
301f531a4a Fix getFuelLimit and getFuelLevel 2020-02-14 01:13:43 -05:00
Anavrins
d971448c9a Fix swshop
Fixes a number transform issue which caused swshop to crash without giving the bought item.
2020-02-08 00:01:36 -05:00
Anavrins
48f142accc swshop helpfile and updates 2020-01-29 23:14:38 -05:00
Anavrins
a9c613164c Merge pull request #23 from LDDestroier/patch-2
Updated list URL
2020-01-19 21:24:17 -05:00
LDDestroier
62951067ae Updated list URL 2020-01-19 20:48:41 -05:00
Anavrins
3f19c94e0f GPS overhaul 2019-12-27 01:18:09 -05:00
kepler155c@gmail.com
79c8c4beae builder help update 2019-12-16 18:02:25 -07:00
kepler155c@gmail.com
83452a2be0 experimental terminal window manager 2019-12-15 19:12:36 -07:00
kepler155c@gmail.com
ddb699db7e Merge branch 'develop-1.8' of https://github.com/kepler155c/opus-apps into develop-1.8 2019-12-08 13:50:26 -07:00
kepler155c@gmail.com
14e6fd57a7 cash tweaks 2019-12-08 13:50:22 -07:00
Anavrins
a85e14e94d ores.lua: Load ore lists from config file and damage value support 2019-12-07 22:32:40 -05:00
kepler155c@gmail.com
7b45348710 oops 2019-12-05 15:34:20 -07:00
kepler155c@gmail.com
6831de37a3 compression read missing 2019-12-05 13:27:14 -07:00
kepler155c@gmail.com
e0960bd930 cash alternative shell added 2019-12-05 11:39:55 -07:00
kepler155c@gmail.com
8a826543d0 Merge branch 'develop-1.8' of https://github.com/kepler155c/opus-apps into develop-1.8 2019-12-05 11:37:37 -07:00
kepler155c@gmail.com
a2c8f0c655 cash alternative shell added 2019-12-05 11:37:31 -07:00
Anavrins
824685fc07 speakerView fix 2019-12-05 00:18:55 -05:00
kepler155c@gmail.com
aeec3c688e move scripts back for turtles program 2019-11-25 15:29:25 -07:00
kepler155c@gmail.com
df8c80e4db crafting fix 2019-11-25 15:24:11 -07:00
Anavrins
d8f33b9cb7 multiMiner.lua Move abort button to avoid accidental clicking 2019-11-18 15:03:02 -05:00
kepler155c@gmail.com
922c391bf2 cleanup + example start 2019-11-17 18:21:48 -07:00
kepler155c@gmail.com
64ec8c82d3 properly handle empty text entry fields (including transformations) 2019-11-13 14:24:54 -07:00
81 changed files with 2638 additions and 1344 deletions

View File

@@ -236,10 +236,7 @@ function substitutionPage.info:draw()
end end
self:clear() self:clear()
self:setCursorPos(1, 1) self:print(' Replace ' .. inName .. '\n' .. ' With ' .. outName)
self:print(' Replace ' .. inName .. '\n')
--self:print(' ' .. sub.id .. ':' .. sub.dmg .. '\n', nil, colors.yellow)
self:print(' With ' .. outName)
end end
function substitutionPage:enable() function substitutionPage:enable()
@@ -276,7 +273,7 @@ function substitutionPage:eventHandler(event)
self.info:draw() self.info:draw()
elseif event.type == 'text_change' then elseif event.type == 'text_change' then
local text = event.text local text = event.text or ''
if #text == 0 then if #text == 0 then
self.grid.values = self.allItems self.grid.values = self.allItems
else else
@@ -536,7 +533,7 @@ local startPage = UI.Page {
event = 'setStartLevel', event = 'setStartLevel',
cancelEvent = 'slide_hide', cancelEvent = 'slide_hide',
text = UI.Text { text = UI.Text {
x = 5, y = 1, width = 20, x = 5, y = 1, width = 10,
textColor = colors.gray, textColor = colors.gray,
}, },
textEntry = UI.TextEntry { textEntry = UI.TextEntry {
@@ -554,7 +551,7 @@ local startPage = UI.Page {
event = 'setStartBlock', event = 'setStartBlock',
cancelEvent = 'slide_hide', cancelEvent = 'slide_hide',
text = UI.Text { text = UI.Text {
x = 2, y = 1, width = 20, x = 2, y = 1, width = 13,
textColor = colors.gray, textColor = colors.gray,
}, },
textEntry = UI.TextEntry { textEntry = UI.TextEntry {
@@ -727,8 +724,7 @@ function startPage:eventHandler(event)
Builder:begin() Builder:begin()
elseif event.type == 'quit' then elseif event.type == 'quit' then
UI.term:reset() UI:quit()
Event.exitPullEvents()
end end
return UI.Page.eventHandler(self, event) return UI.Page.eventHandler(self, event)
@@ -772,5 +768,4 @@ UI:setPages({
}) })
UI:setPage('start') UI:setPage('start')
UI:start()
UI:pullEvents()

View File

@@ -27,7 +27,7 @@ Copy a schematic file to the turtle/command computer (see downloading instructio
Building Building
======== ========
Run: Run:
> builder <schematic file> > builder <schematic file or url>
The first time you run the program, you must select a wrench. Place a wrench into the chest. Go to the supplies list and double-click the SelectAWrench item. Select the wrench and apply. The first time you run the program, you must select a wrench. Place a wrench into the chest. Go to the supplies list and double-click the SelectAWrench item. Select the wrench and apply.
@@ -47,9 +47,13 @@ Simply copy a schematic file into the computer's folder.
Multiplayer Multiplayer
----------- -----------
Option 1: Use wget if the schematic is available for download (unreliable). Option 1: Pass the url of the schematic.
Option 2: Transferring via pastebin (reliable) > builder <url>
Option 2: Use wget if the schematic is available for download (unreliable).
Option 3: Transferring via pastebin (reliable)
To create a base64 file from a command line, do: To create a base64 file from a command line, do:
* linux / max: * linux / max:

31
cash/.package Normal file
View File

@@ -0,0 +1,31 @@
{
title = 'ComputerCraft Advanced Shell',
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/cash',
description = [[A Bourne-compatible shell for ComputerCraft.
Features
Bash/sh-style command line
Tab completion (defaulting to file names where not supported)
Customizable prompts (including ANSI support)
Local & environment variables
Argument quoting
Multiple commands on one line with semicolons
Many built-in functions (including in-line Lua commands)
Arithmetic expansion
If, while, for statements
Function support
Shell scripting/shebangs
Background jobs
rc files
Restorable history
Partial CCKernel2 support
Full compatibility with CraftOS shell.lua]],
license = 'MIT',
install = [[
require('opus.alternate').set('shell', 'packages/cash/cash.lua')
require('opus.util').writeFile('.cashrc', 'set TERMINATE_QUIT=yes')
]],
uninstall = [[
require('opus.alternate').remove('shell', 'packages/cash/cash.lua')
]],
}

7
cash/etc/apps.db Normal file
View File

@@ -0,0 +1,7 @@
{
[ "16323efd4cb1f1f639d67b94161c2ef37a905517e" ] = {
title = "Cash",
category = "Apps",
run = "packages/cash/cash.lua",
},
}

1
cash/etc/fstab Normal file
View File

@@ -0,0 +1 @@
packages/cash/cash.lua urlfs https://raw.githubusercontent.com/MCJack123/cash/master/cash.lua

12
ccemux/etc/apps.db Normal file
View File

@@ -0,0 +1,12 @@
{
[ "87e89abb4c1c551fe08d355d097f18b8de78edca5f556997085681662fce8eed" ] = {
title = "Config",
category = "CCEmuX",
run = "emu config",
},
[ "cec3a9b89b2e391393d0f68e4bc12a9fa6cf358b3cdf79496dc442d52b8dd528" ] = {
title = "Data",
category = "CCEmuX",
run = "emu data",
},
}

View File

@@ -9,7 +9,7 @@ local tab = UI.Tab {
tabTitle = 'CCEmuX', tabTitle = 'CCEmuX',
description = 'CCEmuX peripherals', description = 'CCEmuX peripherals',
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 1, ey = 4, x = 2, ex = -2, y = 2, ey = 5,
values = { values = {
side = 'bottom', side = 'bottom',
type = 'wireless_modem', type = 'wireless_modem',
@@ -28,20 +28,21 @@ local tab = UI.Tab {
}, },
}, },
drive_id = UI.TextEntry { drive_id = UI.TextEntry {
x = 20, y = 3, x = 19, y = 3,
formKey = 'drive_id', formKey = 'drive_id',
shadowText = 'id', shadowText = 'id',
width = 5, width = 5,
limit = 3, limit = 3,
transform = 'number',
}, },
add = UI.Button { add = UI.Button {
x = 28, y = 3, x = -6, y = 3, width = 5,
text = 'Add', event = 'form_ok', text = 'Add', event = 'form_ok',
help = 'Add items to turtle to add to filter', help = 'Add items to turtle to add to filter',
}, },
}, },
grid = UI.Grid { grid = UI.Grid {
x = 3, ex = -3, y = 6, ey = -2, x = 2, ex = -2, y = 7, ey = -2,
columns = { columns = {
{ heading = 'Side', key = 'side', width = 8 }, { heading = 'Side', key = 'side', width = 8 },
{ heading = 'Type', key = 'type' }, { heading = 'Type', key = 'type' },
@@ -78,23 +79,27 @@ end
function tab:eventHandler(event) function tab:eventHandler(event)
if event.type == 'form_complete' then if event.type == 'form_complete' then
ccemux.detach(event.values.side) if event.values.type == 'disk_drive' and not event.values.drive_id then
ccemux.attach(event.values.side, event.values.type) self:emit({ type = 'error_message', message = 'Invalid drive ID' })
else
ccemux.detach(event.values.side)
ccemux.attach(event.values.side, event.values.type)
local config = Config.load('ccemux') local config = Config.load('ccemux')
config[event.values.side] = { config[event.values.side] = {
type = event.values.type type = event.values.type
}
if event.values.type == 'disk_drive' and tonumber(event.values.drive_id) then
config[event.values.side].args = {
id = tonumber(event.values.drive_id)
} }
end if event.values.type == 'disk_drive' then
Config.update('ccemux', config) config[event.values.side].args = {
self:updatePeripherals(config) id = event.values.drive_id
self.grid:draw() }
end
Config.update('ccemux', config)
self:updatePeripherals(config)
self.grid:draw()
self:emit({ type = 'success_message', message = 'Attached' }) self:emit({ type = 'success_message', message = 'Attached' })
end
elseif event.type == 'choice_change' then elseif event.type == 'choice_change' then
if event.element == self.form.ptype then if event.element == self.form.ptype then

View File

@@ -8,10 +8,10 @@ local http = _G.http
local multishell = _ENV.multishell local multishell = _ENV.multishell
local os = _G.os local os = _G.os
local shell = _ENV.shell local shell = _ENV.shell
local colors = _G.colors
local REGISTRY_DIR = 'usr/.registry' local REGISTRY_DIR = 'usr/.registry'
-- FIX SOMEDAY -- FIX SOMEDAY
local function registerApp(app, key) local function registerApp(app, key)
app.key = SHA.compute(key) app.key = SHA.compute(key)
@@ -27,7 +27,6 @@ local function unregisterApp(key)
end end
end end
local sandboxEnv = Util.shallowCopy(_ENV) local sandboxEnv = Util.shallowCopy(_ENV)
setmetatable(sandboxEnv, { __index = _G }) setmetatable(sandboxEnv, { __index = _G })
@@ -36,21 +35,10 @@ UI:configure('Appstore', ...)
local APP_DIR = 'usr/apps' local APP_DIR = 'usr/apps'
local sources = { local source = {
text = "STD Default",
{ text = "STD Default", event = 'source',
event = 'source', url = "https://github.com/LDDestroier/STD-GUI/raw/master/list.lua",
url = "http://pastebin.com/raw/zVws7eLq" }, --stock
--[[
{ text = "Discover",
event = 'source',
generateName = true,
url = "http://pastebin.com/raw/9bXfCz6M" }, --owned by dannysmc95
{ text = "Opus",
event = 'source',
url = "http://pastebin.com/raw/ajQ91Rmn" },
]]
} }
shell.setDir(APP_DIR) shell.setDir(APP_DIR)
@@ -87,14 +75,14 @@ local function runApp(app, checkExists, ...)
error('Failed to download') error('Failed to download')
end end
local fn = loadstring(program, app.name) fn = _G.loadstring(program, app.name)
if not fn then if not fn then
error('Failed to download') error('Failed to download')
end end
setfenv(fn, sandboxEnv) _G.setfenv(fn, sandboxEnv)
fn(unpack(args)) fn(table.unpack(args))
end end
end end
@@ -134,16 +122,16 @@ local viewApp = function(app)
return true return true
end end
local getSourceListing = function(source) local getSourceListing = function()
local contents = http.get(source.url) local contents = http.get(source.url)
if contents then if contents then
local fn = loadstring(contents.readAll(), source.text) local fn = _G.loadstring(contents.readAll(), source.text)
contents.close() contents.close()
local env = { std = { } } local env = { std = { } }
setmetatable(env, { __index = _G }) setmetatable(env, { __index = _G })
setfenv(fn, env) _G.setfenv(fn, env)
fn() fn()
if env.contextualGet then if env.contextualGet then
@@ -172,9 +160,28 @@ local getSourceListing = function(source)
end end
end end
getSourceListing()
if not source.storeURLs then
error('Unable to download application list')
end
local buttons = { }
for k,v in Util.spairs(source.storeCatagoryNames,
function(a, b) return a:lower() < b:lower() end) do
if v ~= 'Operating System' then
table.insert(buttons, {
text = v,
event = 'category',
index = k,
})
end
end
source.index, source.name = Util.first(source.storeCatagoryNames)
local appPage = UI.Page { local appPage = UI.Page {
menuBar = UI.MenuBar { menuBar = UI.MenuBar {
-- showBackButton = not pocket,
buttons = { buttons = {
{ text = '\027', event = 'back' }, { text = '\027', event = 'back' },
{ text = 'Install', event = 'install' }, { text = 'Install', event = 'install' },
@@ -204,16 +211,14 @@ function appPage.container.viewport:draw()
Ansi.yellow .. app.description .. Ansi.reset) Ansi.yellow .. app.description .. Ansi.reset)
self:clear() self:clear()
self:setCursorPos(1, 1)
self:print(str) self:print(str)
self.ymax = self.cursorY
if appPage.notification.enabled then if appPage.notification.enabled then
appPage.notification:draw() appPage.notification:draw()
end end
end end
function appPage:enable(source, app) function appPage:enable(app)
self.source = source self.source = source
self.app = app self.app = app
UI.Page.enable(self) UI.Page.enable(self)
@@ -293,8 +298,7 @@ end
local categoryPage = UI.Page { local categoryPage = UI.Page {
menuBar = UI.MenuBar { menuBar = UI.MenuBar {
buttons = { buttons = {
{ text = 'Catalog', dropdown = sources }, { text = 'Category', name = 'categoryButton', dropdown = buttons },
{ text = 'Category', name = 'categoryButton', dropdown = { } },
}, },
}, },
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
@@ -309,62 +313,21 @@ local categoryPage = UI.Page {
l = 'lua', l = 'lua',
[ 'control-q' ] = 'quit', [ 'control-q' ] = 'quit',
}, },
source = source,
} }
function categoryPage:setCategory(source, name, index) function categoryPage:setCategory(name, index)
self.grid.values = { } self.grid.values = { }
for _,v in pairs(source.storeURLs) do for _,v in pairs(source.storeURLs) do
if index == 0 or index == v.catagory then if index == 0 or index == v.catagory then
table.insert(self.grid.values, v) table.insert(self.grid.values, v)
end end
end end
self.statusBar:setStatus(string.format('%s: %s', source.text, name)) self.statusBar:setStatus(string.format('%s: %s', self.source.text or '', name))
self.grid:update() self.grid:update()
self.grid:setIndex(1) self.grid:setIndex(1)
end end
function categoryPage:setSource(source)
if not source.categoryMenu then
self.statusBar:setStatus('Loading...')
self.statusBar:draw()
self:sync()
getSourceListing(source)
if not source.storeURLs then
error('Unable to download application list')
end
local buttons = { }
for k,v in Util.spairs(source.storeCatagoryNames,
function(a, b) return a:lower() < b:lower() end) do
if v ~= 'Operating System' then
table.insert(buttons, {
text = v,
event = 'category',
index = k,
})
end
end
source.categoryMenu = UI.DropMenu({
buttons = buttons,
})
source.index, source.name = Util.first(source.storeCatagoryNames)
categoryPage.menuBar.categoryButton:add({
categoryMenu = source.categoryMenu
})
end
self.source = source
self.menuBar.categoryButton.dropmenu = source.categoryMenu
categoryPage:setCategory(source, source.name, source.index)
end
function categoryPage.grid:sortCompare(a, b) function categoryPage.grid:sortCompare(a, b)
return a.ltitle < b.ltitle return a.ltitle < b.ltitle
end end
@@ -377,12 +340,11 @@ function categoryPage.grid:getRowTextColor(row, selected)
end end
function categoryPage:eventHandler(event) function categoryPage:eventHandler(event)
if event.type == 'grid_select' or event.type == 'select' then if event.type == 'grid_select' or event.type == 'select' then
UI:setPage(appPage, self.source, self.grid:getSelected()) UI:setPage(appPage, self.grid:getSelected())
elseif event.type == 'category' then elseif event.type == 'category' then
self:setCategory(self.source, event.button.text, event.button.index) self:setCategory(event.button.text, event.button.index)
self:setFocus(self.grid) self:setFocus(self.grid)
self:draw() self:draw()
@@ -392,7 +354,7 @@ function categoryPage:eventHandler(event)
self:draw() self:draw()
elseif event.type == 'quit' then elseif event.type == 'quit' then
UI:exitPullEvents() UI:quit()
else else
return UI.Page.eventHandler(self, event) return UI.Page.eventHandler(self, event)
@@ -401,8 +363,7 @@ function categoryPage:eventHandler(event)
end end
print("Retrieving catalog list") print("Retrieving catalog list")
categoryPage:setSource(sources[1]) categoryPage:setCategory(source.name, source.index)
UI:setPage(categoryPage) UI:setPage(categoryPage)
UI:pullEvents() UI:start()
UI.term:reset()

View File

@@ -1,11 +1,8 @@
_G.requireInjector(_ENV)
local Ansi = require('opus.ansi') local Ansi = require('opus.ansi')
local Event = require('opus.event') local Event = require('opus.event')
local UI = require('opus.ui') local UI = require('opus.ui')
local Util = require('opus.util') local Util = require('opus.util')
local colors = _G.colors
local peripheral = _G.peripheral local peripheral = _G.peripheral
--[[ -- PeripheralsPage -- ]] -- --[[ -- PeripheralsPage -- ]] --
@@ -18,6 +15,20 @@ local peripheralsPage = UI.Page {
}, },
sortColumn = 'type', sortColumn = 'type',
autospace = true, autospace = true,
enable = function(self)
local sides = peripheral.getNames()
Util.clear(self.values)
for _,side in pairs(sides) do
table.insert(self.values, {
type = peripheral.getType(side),
side = side
})
end
self:update()
self:adjustWidth()
UI.Grid.enable(self)
end,
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
values = 'Select peripheral', values = 'Select peripheral',
@@ -25,52 +36,35 @@ local peripheralsPage = UI.Page {
accelerators = { accelerators = {
[ 'control-q' ] = 'quit', [ 'control-q' ] = 'quit',
}, },
updatePeripherals = function(self)
if UI:getCurrentPage() == self then
self.grid:draw()
self:sync()
end
end,
eventHandler = function(self, event)
if event.type == 'quit' then
UI:quit()
elseif event.type == 'grid_select' then
UI:setPage('methods', event.selected)
end
return UI.Page.eventHandler(self, event)
end,
} }
function peripheralsPage.grid:draw()
local sides = peripheral.getNames()
Util.clear(self.values)
for _,side in pairs(sides) do
table.insert(self.values, {
type = peripheral.getType(side),
side = side
})
end
self:update()
self:adjustWidth()
UI.Grid.draw(self)
end
function peripheralsPage:updatePeripherals()
if UI:getCurrentPage() == self then
self.grid:draw()
self:sync()
end
end
function peripheralsPage:eventHandler(event)
if event.type == 'quit' then
Event.exitPullEvents()
elseif event.type == 'grid_select' then
UI:setPage('methods', event.selected)
end
return UI.Page.eventHandler(self, event)
end
--[[ -- MethodsPage -- ]] -- --[[ -- MethodsPage -- ]] --
local methodsPage = UI.Page { local methodsPage = UI.Page {
backgroundColor = colors.black,
doc = UI.TextArea { doc = UI.TextArea {
backgroundColor = colors.black, backgroundColor = 'black',
x = 2, y = 2, ex = -1, ey = -7, ey = -7,
marginLeft = 1, marginTop = 1,
}, },
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
y = -6, ey = -2, y = -6, ey = -2,
columns = { columns = {
{ heading = 'Name', key = 'name', width = UI.term.width } { heading = 'Name', key = 'name' }
}, },
sortColumn = 'name', sortColumn = 'name',
}, },
@@ -84,7 +78,6 @@ local methodsPage = UI.Page {
} }
function methodsPage:enable(p) function methodsPage:enable(p)
self.peripheral = p or self.peripheral self.peripheral = p or self.peripheral
p = peripheral.wrap(self.peripheral.side) p = peripheral.wrap(self.peripheral.side)
@@ -136,7 +129,6 @@ function methodsPage:eventHandler(event)
end end
function methodsPage:getDocumentation() function methodsPage:getDocumentation()
local method = self.grid:getSelected() local method = self.grid:getSelected()
if method.noext then -- computercraft docs if method.noext then -- computercraft docs
@@ -202,4 +194,4 @@ UI:setPages({
methods = methodsPage, methods = methodsPage,
}) })
UI:pullEvents() UI:start()

View File

@@ -122,7 +122,6 @@ function page:drawInfo(drive, textArea)
return isValid(drive) and fs.getFreeSpace(drive.getMountPath()) or 0 return isValid(drive) and fs.getFreeSpace(drive.getMountPath()) or 0
end end
textArea:setCursorPos(1, 1)
textArea:print(string.format('Drive: %s%s%s\nLabel: %s%s%s\nUsed: %s%s%s\nFree: %s%s%s', textArea:print(string.format('Drive: %s%s%s\nLabel: %s%s%s\nUsed: %s%s%s\nFree: %s%s%s',
Ansi.yellow, drive.name, Ansi.reset, Ansi.yellow, drive.name, Ansi.reset,
isValid(drive) and Ansi.yellow or Ansi.orange, getLabel():sub(1, 10), Ansi.reset, isValid(drive) and Ansi.yellow or Ansi.orange, getLabel():sub(1, 10), Ansi.reset,
@@ -138,6 +137,7 @@ function page:scan()
self.copyButton.inactive = not valid self.copyButton.inactive = not valid
self:draw() self:draw()
self.progress:clear()
self.progress:centeredWrite(1, 'Analyzing Disks..') self.progress:centeredWrite(1, 'Analyzing Disks..')
self.progress:sync() self.progress:sync()
@@ -167,6 +167,7 @@ function page:copy()
throttle() throttle()
end end
self.progress:clear()
self.progress:centeredWrite(1, 'Computing..') self.progress:centeredWrite(1, 'Computing..')
self.progress:sync() self.progress:sync()
@@ -211,6 +212,8 @@ function page:copy()
self.progress:clear() self.progress:clear()
rawCopy(sdrive.getMountPath(), tdrive.getMountPath()) rawCopy(sdrive.getMountPath(), tdrive.getMountPath())
cleanup() cleanup()
self.progress:clear()
self.progress:centeredWrite(1, 'Copy Complete', colors.lime, colors.black) self.progress:centeredWrite(1, 'Copy Complete', colors.lime, colors.black)
self.progress:sync() self.progress:sync()
@@ -270,4 +273,4 @@ Event.onTimeout(.2, function()
end) end)
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()

View File

@@ -27,6 +27,26 @@ local page = UI.Page {
}, },
autospace = true, autospace = true,
disableHeader = true, disableHeader = true,
getDisplayValues = function(_, row)
row = Util.shallowCopy(row)
local function tovalue(s)
if type(s) == 'table' then
return 'table'
end
return s
end
for k,v in pairs(row) do
row[k] = tovalue(v)
end
return row
end,
draw = function(self)
self:adjustWidth()
UI.Grid.draw(self)
end,
}, },
accelerators = { accelerators = {
f = 'filter', f = 'filter',
@@ -36,81 +56,48 @@ local page = UI.Page {
[ 'control-q' ] = 'quit', [ 'control-q' ] = 'quit',
}, },
filtered = { }, filtered = { },
} eventHandler = function(self, event)
if event.type == 'filter' then
local entry = self.grid:getSelected()
self.filtered[entry.event] = true
function page:eventHandler(event) elseif event.type == 'toggle' then
self.paused = not self.paused
if self.paused then
self.menuBar.pauseButton.text = 'Resume'
else
self.menuBar.pauseButton.text = 'Pause '
end
self.menuBar:draw()
if event.type == 'filter' then elseif event.type == 'grid_select' then
local entry = self.grid:getSelected() multishell.openTab({
self.filtered[entry.event] = true path = 'sys/apps/Lua.lua',
args = { event.selected },
focused = true,
})
elseif event.type == 'toggle' then elseif event.type == 'reset' then
self.paused = not self.paused self.filtered = { }
if self.paused then self.grid:setValues({ })
self.menuBar.pauseButton.text = 'Resume' self.grid:draw()
else if self.paused then
self.menuBar.pauseButton.text = 'Pause '
end
self.menuBar:draw()
elseif event.type == 'grid_select' then
multishell.openTab({
path = 'sys/apps/Lua.lua',
args = { event.selected },
focused = true,
})
elseif event.type == 'reset' then
self.filtered = { }
self.grid:setValues({ })
self.grid:draw()
if self.paused then
self:emit({ type = 'toggle' })
end
elseif event.type == 'clear' then
self.grid:setValues({ })
self.grid:draw()
elseif event.type == 'quit' then
UI:exitPullEvents()
--[[
elseif event.type == 'focus_change' then
if event.focused == self.grid then
if not self.paused then
self:emit({ type = 'toggle' }) self:emit({ type = 'toggle' })
end end
elseif event.type == 'clear' then
self.grid:setValues({ })
self.grid:draw()
elseif event.type == 'quit' then
UI:quit()
else
return UI.Page.eventHandler(self, event)
end end
--]] return true
end,
else }
return UI.Page.eventHandler(self, event)
end
return true
end
function page.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
local function tovalue(s)
if type(s) == 'table' then
return 'table'
end
return s
end
for k,v in pairs(row) do
row[k] = tovalue(v)
end
return row
end
function page.grid:draw()
self:adjustWidth()
UI.Grid.draw(self)
end
local updated = false local updated = false
local timerId = os.startTimer(1) local timerId = os.startTimer(1)
@@ -150,6 +137,6 @@ end
kernel.hook('*', hookFunction) kernel.hook('*', hookFunction)
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()
kernel.unhook('*', hookFunction) kernel.unhook('*', hookFunction)

View File

@@ -42,7 +42,6 @@ local page = UI.Page {
}, },
range = UI.SlideOut { range = UI.SlideOut {
y = -7, height = 7, y = -7, height = 7,
backgroundColor = colors.cyan,
titleBar = UI.TitleBar { titleBar = UI.TitleBar {
event = 'cancel', event = 'cancel',
title = 'Enter range', title = 'Enter range',
@@ -239,6 +238,6 @@ Event.addRoutine(function()
end) end)
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()
swarm:stop() swarm:stop()

View File

@@ -5,13 +5,13 @@ local Util = require('opus.util')
local peripheral = _G.peripheral local peripheral = _G.peripheral
if not peripheral.find('speaker') then if not peripheral.find('speaker') then
error('No speaker attached') error('No speaker attached')
end end
local rawSounds = Util.readLines('packages/games/etc/sounds.txt') or error('Unable to read sounds file') local rawSounds = Util.readLines('packages/common/etc/sounds.txt') or error('Unable to read sounds file')
local sounds = { } local sounds = { }
for _, s in pairs(rawSounds) do for _, s in pairs(rawSounds) do
table.insert(sounds, { name = s }) table.insert(sounds, { name = s })
end end
UI:configure('SoundPlayer', ...) UI:configure('SoundPlayer', ...)
@@ -25,21 +25,21 @@ local page = UI.Page {
x = 10, y = 2, ex = -3, x = 10, y = 2, ex = -3,
limit = 32, limit = 32,
}, },
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
y = 4, y = 4,
columns = { columns = {
{ heading = 'Name', key = 'name' }, { heading = 'Name', key = 'name' },
}, },
values = sounds, values = sounds,
}, },
} }
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'grid_select' then if event.type == 'grid_select' then
Sound.play(event.selected.name) Sound.play(event.selected.name)
elseif event.type == 'text_change' then elseif event.type == 'text_change' then
if #event.text == 0 then if not event.text then
self.grid.values = sounds self.grid.values = sounds
else else
self.grid.values = { } self.grid.values = { }
@@ -51,13 +51,13 @@ function page:eventHandler(event)
end end
self.grid:update() self.grid:update()
self.grid:setIndex(1) self.grid:setIndex(1)
self.grid:draw() self.grid:draw()
else else
return UI.Page.eventHandler(self, event) return UI.Page.eventHandler(self, event)
end end
return true return true
end end
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()

View File

@@ -2,7 +2,6 @@ local Config = require('opus.config')
local Event = require('opus.event') local Event = require('opus.event')
local itemDB = require('core.itemDB') local itemDB = require('core.itemDB')
local Socket = require('opus.socket') local Socket = require('opus.socket')
local Terminal = require('opus.terminal')
local UI = require('opus.ui') local UI = require('opus.ui')
local Util = require('opus.util') local Util = require('opus.util')
@@ -11,10 +10,7 @@ local fs = _G.fs
local multishell = _ENV.multishell local multishell = _ENV.multishell
local network = _G.network local network = _G.network
local os = _G.os local os = _G.os
local shell = _ENV.shell
local term = _G.term
--UI.Button.defaults.focusIndicator = ' '
UI:configure('Turtles', ...) UI:configure('Turtles', ...)
local config = { } local config = { }
@@ -31,13 +27,26 @@ local options = {
local SCRIPTS_PATH = 'packages/common/etc/scripts' local SCRIPTS_PATH = 'packages/common/etc/scripts'
local nullTerm = Terminal.getNullTerm(term.current()) local socket, turtle, page
local socket
local page = UI.Page { page = UI.Page {
coords = UI.Window { coords = UI.Window {
backgroundColor = colors.black, backgroundColor = colors.black,
height = 3, height = 3,
marginTop = 1, marginLeft = 1,
draw = function(self)
local t = turtle
self:clear()
if t then
self:setCursorPos(2, 2)
local ind = 'GPS'
if not t.point.gps then
ind = 'REL'
end
self:print(string.format('%s : %d,%d,%d',
ind, t.point.x, t.point.y, t.point.z))
end
end,
}, },
tabs = UI.Tabs { tabs = UI.Tabs {
x = 1, y = 4, ey = -2, x = 1, y = 4, ey = -2,
@@ -50,6 +59,23 @@ local page = UI.Page {
disableHeader = true, disableHeader = true,
sortColumn = 'label', sortColumn = 'label',
autospace = true, autospace = true,
draw = function(self)
Util.clear(self.values)
local files = fs.list(SCRIPTS_PATH)
for _,path in pairs(files) do
table.insert(self.values, { label = path, path = fs.combine(SCRIPTS_PATH, path) })
end
self:update()
UI.ScrollingGrid.draw(self)
end,
eventHandler = function(self, event)
if event.type == 'grid_select' then
page:runScript(event.selected.label)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end,
}, },
turtles = UI.ScrollingGrid { turtles = UI.ScrollingGrid {
tabTitle = 'Select', tabTitle = 'Select',
@@ -63,6 +89,41 @@ local page = UI.Page {
disableHeader = true, disableHeader = true,
sortColumn = 'label', sortColumn = 'label',
autospace = true, autospace = true,
getDisplayValues = function(_, row)
row = Util.shallowCopy(row)
if row.fuel then
row.fuel = Util.toBytes(row.fuel)
end
if row.distance then
row.distance = Util.round(row.distance, 1)
end
return row
end,
draw = function(self)
Util.clear(self.values)
for _,v in pairs(network) do
if v.fuel then
table.insert(self.values, v)
end
end
self:update()
UI.ScrollingGrid.draw(self)
end,
eventHandler = function(self, event)
if event.type == 'grid_select' then
turtle = event.selected
config.id = event.selected.id
Config.update('Turtles', config)
multishell.setTitle(multishell.getCurrent(), turtle.label)
if socket then
socket:close()
socket = nil
end
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end,
}, },
inventory = UI.ScrollingGrid { inventory = UI.ScrollingGrid {
backgroundColor = colors.cyan, backgroundColor = colors.cyan,
@@ -70,10 +131,58 @@ local page = UI.Page {
columns = { columns = {
{ heading = '', key = 'index', width = 2 }, { heading = '', key = 'index', width = 2 },
{ heading = '', key = 'count', width = 2 }, { heading = '', key = 'count', width = 2 },
{ heading = 'Inventory', key = 'key', width = UI.term.width - 7 }, { heading = 'Inventory', key = 'key' },
}, },
disableHeader = true, disableHeader = true,
sortColumn = 'index', sortColumn = 'index',
getRowTextColor = function(self, row, selected)
if turtle and row.selected then
return colors.yellow
end
return UI.ScrollingGrid.getRowTextColor(self, row, selected)
end,
draw = function(self)
local t = turtle
Util.clear(self.values)
if t then
for k,v in pairs(t.inv or { }) do -- new method (less data)
local index, count = k:match('(%d+),(%d+)')
v = {
index = tonumber(index),
key = v,
count = tonumber(count),
}
table.insert(self.values, v)
end
for _,v in pairs(t.inventory or { }) do
if v.count > 0 then
table.insert(self.values, v)
end
end
for _,v in pairs(self.values) do
if v.index == t.slotIndex then
v.selected = true
end
if v.key then
v.key = itemDB:getName(v.key)
end
end
end
self:adjustWidth()
self:update()
UI.ScrollingGrid.draw(self)
end,
eventHandler = function(self, event)
if event.type == 'grid_select' then
local fn = string.format('turtle.select(%d)', event.selected.index)
page:runFunction(fn)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end,
}, },
--[[ --[[
policy = UI.ScrollingGrid { policy = UI.ScrollingGrid {
@@ -134,6 +243,15 @@ local page = UI.Page {
{ key = 'distance', width = 6 }, { key = 'distance', width = 6 },
{ key = 'fuel', width = 6 }, { key = 'fuel', width = 6 },
}, },
draw = function(self)
local t = turtle
if t then
self.values.status = t.status
self.values.distance = t.distance and Util.round(t.distance, 2)
self.values.fuel = Util.toBytes(t.fuel)
end
UI.StatusBar.draw(self)
end,
}, },
notification = UI.Notification(), notification = UI.Notification(),
accelerators = { accelerators = {
@@ -141,15 +259,10 @@ local page = UI.Page {
}, },
} }
function page:enable(turtle)
self.turtle = turtle
UI.Page.enable(self)
end
function page:runFunction(script, nowrap) function page:runFunction(script, nowrap)
for _ = 1, 2 do for _ = 1, 2 do
if not socket then if not socket then
socket = Socket.connect(self.turtle.id, 161) socket = Socket.connect(turtle.id, 161)
end end
if socket then if socket then
@@ -170,149 +283,52 @@ function page:runFunction(script, nowrap)
end end
function page:runScript(scriptName) function page:runScript(scriptName)
if self.turtle then if turtle then
self.notification:info('Connecting') self.notification:info('Connecting')
self:sync() self:sync()
local cmd = string.format('Script %d %s', self.turtle.id, scriptName) local script = Util.readFile(fs.combine(SCRIPTS_PATH, scriptName))
local ot = term.redirect(nullTerm) if not script then
pcall(function() shell.run(cmd) end) print('Unable to read script file')
term.redirect(ot)
self.notification:success('Sent')
end
end
function page.coords:draw()
local t = self.parent.turtle
self:clear()
if t then
self:setCursorPos(2, 2)
local ind = 'GPS'
if not t.point.gps then
ind = 'REL'
end end
self:print(string.format('%s : %d,%d,%d',
ind, t.point.x, t.point.y, t.point.z))
end
end
--[[ Inventory Tab ]]-- local function processVariables()
function page.tabs.inventory:getRowTextColor(row, selected) local variables = {
if page.turtle and row.selected then COMPUTER_ID = os.getComputerID,
return colors.yellow GPS = function()
end local pt = require('opus.gps').getPoint()
return UI.ScrollingGrid.getRowTextColor(self, row, selected) if not pt then
end error('Unable to determine location')
end
function page.tabs.inventory:draw() return _G.textutils.serialize(pt)
local t = page.turtle end,
Util.clear(self.values)
if t then
for k,v in pairs(t.inv or { }) do -- new method (less data)
local index, count = k:match('(%d+),(%d+)')
v = {
index = tonumber(index),
key = v,
count = tonumber(count),
} }
table.insert(self.values, v) for k,v in pairs(variables) do
end local token = string.format('{%s}', k)
if script:find(token, 1, true) then
for _,v in pairs(t.inventory or { }) do local s, m = pcall(v)
if v.count > 0 then if not s then
table.insert(self.values, v) self.notification:error(m)
return
end
script = script:gsub(token, m)
end
end end
return true
end end
for _,v in pairs(self.values) do if processVariables(script) then
if v.index == t.slotIndex then local socket = Socket.connect(turtle.id, 161)
v.selected = true if not socket then
self.notification:error('Unable to connect')
return
end end
if v.key then socket:write({ type = 'script', args = script })
v.key = itemDB:getName(v.key)
end
end
end
self:adjustWidth()
self:update()
UI.ScrollingGrid.draw(self)
end
function page.tabs.inventory:eventHandler(event)
if event.type == 'grid_select' then
local fn = string.format('turtle.select(%d)', event.selected.index)
page:runFunction(fn)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end
function page.tabs.scripts:draw()
Util.clear(self.values)
local files = fs.list(SCRIPTS_PATH)
for _,path in pairs(files) do
table.insert(self.values, { label = path, path = fs.combine(SCRIPTS_PATH, path) })
end
self:update()
UI.ScrollingGrid.draw(self)
end
function page.tabs.scripts:eventHandler(event)
if event.type == 'grid_select' then
page:runScript(event.selected.label)
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end
function page.tabs.turtles:getDisplayValues(row)
row = Util.shallowCopy(row)
if row.fuel then
row.fuel = Util.toBytes(row.fuel)
end
if row.distance then
row.distance = Util.round(row.distance, 1)
end
return row
end
function page.tabs.turtles:draw()
Util.clear(self.values)
for _,v in pairs(network) do
if v.fuel then
table.insert(self.values, v)
end
end
self:update()
UI.ScrollingGrid.draw(self)
end
function page.tabs.turtles:eventHandler(event)
if event.type == 'grid_select' then
page.turtle = event.selected
config.id = event.selected.id
Config.update('Turtles', config)
multishell.setTitle(multishell.getCurrent(), page.turtle.label)
if socket then
socket:close() socket:close()
socket = nil
end
else
return UI.ScrollingGrid.eventHandler(self, event)
end
return true
end
function page.statusBar:draw() self.notification:success('Sent')
local t = self.parent.turtle end
if t then
self.values.status = t.status
self.values.distance = t.distance and Util.round(t.distance, 2)
self.values.fuel = Util.toBytes(t.fuel)
end end
UI.StatusBar.draw(self)
end end
function page:showBlocks() function page:showBlocks()
@@ -335,7 +351,7 @@ end
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'quit' then if event.type == 'quit' then
UI:exitPullEvents() UI:quit()
elseif event.type == 'tab_select' then elseif event.type == 'tab_select' then
config.tab = event.button.text config.tab = event.button.text
@@ -354,19 +370,14 @@ function page:eventHandler(event)
return true return true
end end
function page:enable()
UI.Page.enable(self)
-- self.tabs:activateTab(page.tabs.turtles)
end
if not Util.getOptions(options, { ... }, true) then if not Util.getOptions(options, { ... }, true) then
return return
end end
if options.turtle.value >= 0 then if options.turtle.value >= 0 then
for _ = 1, 10 do for _ = 1, 10 do
page.turtle = _G.network[options.turtle.value] turtle = _G.network[options.turtle.value]
if page.turtle then if turtle then
break break
end end
os.sleep(1) os.sleep(1)
@@ -374,9 +385,9 @@ if options.turtle.value >= 0 then
end end
Event.onInterval(1, function() Event.onInterval(1, function()
if page.turtle then if turtle then
local t = _G.network[page.turtle.id] --local t = _G.network[turtle.id]
page.turtle = t --turtle = t
page:draw() page:draw()
page:sync() page:sync()
end end
@@ -387,5 +398,4 @@ if config.tab then
end end
UI:setPage(page) UI:setPage(page)
UI:start()
UI:pullEvents()

File diff suppressed because it is too large Load Diff

View File

@@ -57,6 +57,25 @@
category = "Apps", category = "Apps",
requires = "advancedComputer", requires = "advancedComputer",
iconExt = "\030 \031 \128\030d\159\030 \031d\140\030d\031 \155\030 \0315\140\0305\031 \155\030 \128\010\030 \031d\136\145\0315\136\145\031d\153\031 \128\0315\153\010\030 \031 \128\031d\130\140\134\0315\140\134\031 \128", iconExt = "\030 \031 \128\030d\159\030 \031d\140\030d\031 \155\030 \0315\140\0305\031 \155\030 \128\010\030 \031d\136\145\0315\136\145\031d\153\031 \128\0315\153\010\030 \031 \128\031d\130\140\134\0315\140\134\031 \128",
run = "packages/common/hexedit.lua", run = "fileui --exec=hexedit.lua",
},
[ "fb1c39e9f4f3c2628ad173ab401a6e4e4baf783d" ] = {
title = "Sounds",
category = "System",
run = "SoundPlayer",
iconExt = "\030 \031 \128\0307\159\129\030 \0317\149\0310\144\0300\031 \155\030 \0310\137\144\010\0307\0317\128\128\128\030 \149\0300\031 \149\030 \128\0310\149\0300\031 \149\010\030 \031 \128\0317\130\0307\031 \144\030 \0317\149\0310\129\134\152\129",
},
[ "464c4ffd019e1e9691dcf0537c797353ef2b1c1d4833d3d463e5b74ae4547344" ] = {
title = "Editor",
category = "Apps",
run = "edit",
iconExt = "7\
¨¨¨¨f€0¨\
¨¨f€0¨¨f€",
},
[ "3f00927a719345edd4a8316599d3b328857987547f8884306861161ffa09647e" ] = {
title = "Write",
category = "Apps",
run = "write",
}, },
} }

View File

@@ -2,3 +2,5 @@ packages/common/ascii.lua urlfs http://pastebin.com/raw/u3kcnyjd
packages/common/hexedit.lua urlfs https://pastebin.com/raw/Ds9ajsp4 packages/common/hexedit.lua urlfs https://pastebin.com/raw/Ds9ajsp4
packages/common/colors.lua urlfs https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/ignore/colors.lua packages/common/colors.lua urlfs https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/ignore/colors.lua
packages/common/cowsay.lua urlfs https://pastebin.com/raw/n00VQJsw packages/common/cowsay.lua urlfs https://pastebin.com/raw/n00VQJsw
packages/common/calc.lua urlfs https://pastebin.com/raw/nAinUn1h
packages/common/write.lua urlfs https://pastebin.com/raw/RSyhCjqv

View File

@@ -1,5 +1,5 @@
_G.requireInjector(_ENV) _G.requireInjector(_ENV)
local config = require('config').load('gps') local config = require('opus.config').load('gps')
if config.home then if config.home then
if turtle.enableGPS() then if turtle.enableGPS() then
return turtle.pathfind(config.home) return turtle.pathfind(config.home)

View File

@@ -1,29 +0,0 @@
turtle.run(function()
_G.requireInjector(_ENV)
local GPS = require('gps')
local Socket = require('socket')
local id = {COMPUTER_ID}
if not turtle.enableGPS() then
error('turtle: No GPS found')
end
local socket = Socket.connect(id, 161)
if not socket then
error('turtle: Unable to connect to ' .. id)
end
socket:write({ type = 'gps' })
local pt = socket:read(3)
if not pt then
error('turtle: No GPS response')
end
if not turtle.pathfind(pt) then
error('Unable to go to location')
end
end)

View File

@@ -0,0 +1,17 @@
local turtle = _G.turtle
turtle.run(function()
_G.requireInjector(_ENV)
local GPS = require('opus.gps')
if not turtle.enableGPS() then
error('turtle: No GPS found')
end
local pt = {GPS}
if not turtle.pathfind(pt) then
error('Unable to go to location')
end
end)

View File

@@ -1,5 +1,5 @@
_G.requireInjector(_ENV) _G.requireInjector(_ENV)
local Config = require('config') local Config = require('opus.config')
local pt = turtle.enableGPS() local pt = turtle.enableGPS()
if pt then if pt then
local config = Config.load('gps', { }) local config = Config.load('gps', { })

View File

@@ -2,9 +2,9 @@ local function summon(id)
_G.requireInjector(_ENV) _G.requireInjector(_ENV)
local GPS = require('gps') local GPS = require('opus.gps')
local Point = require('point') local Point = require('opus.point')
local Socket = require('socket') local Socket = require('opus.socket')
turtle.setStatus('GPSing') turtle.setStatus('GPSing')
turtle.setPoint({ x = 0, y = 0, z = 0, heading = 0 }) turtle.setPoint({ x = 0, y = 0, z = 0, heading = 0 })

View File

@@ -351,8 +351,8 @@ local page = UI.Page {
menuBar = UI.MenuBar { menuBar = UI.MenuBar {
buttons = { buttons = {
{ text = 'Scan', event = 'scan' }, { text = 'Scan', event = 'scan' },
{ text = 'Abort', event = 'abort' },
pauseResume[1], pauseResume[1],
{ text = 'Abort', event = 'abort', x = -7 },
}, },
}, },
tabs = UI.Tabs { tabs = UI.Tabs {

View File

@@ -19,10 +19,14 @@ local Util = require('opus.util')
local multishell = _ENV.multishell local multishell = _ENV.multishell
local os = _G.os local os = _G.os
local recTerm, oldTerm, arg, showInput, skipLast, lastDelay, curInput = {}, Util.shallowCopy(multishell.term), {...}, false, false, 2, "" local colours = _G.colors
local args, options = Util.parse(...)
local oldTerm, showInput, skipLast, lastDelay, curInput = Util.shallowCopy(multishell.term), false, false, 2, ""
local curBlink, oldBlink, tTerm, buffer, colourNum, xPos, yPos, oldXPos, oldYPos, tCol, bCol, xSize, ySize = false, false, {}, {}, {}, 1, 1, 1, 1, colours.white, colours.black, oldTerm.getSize() local curBlink, oldBlink, tTerm, buffer, colourNum, xPos, yPos, oldXPos, oldYPos, tCol, bCol, xSize, ySize = false, false, {}, {}, {}, 1, 1, 1, 1, colours.white, colours.black, oldTerm.getSize()
local greys, buttons = {["0"] = true, ["7"] = true, ["8"] = true, ["f"] = true}, {"l", "r", "m"} local greys, buttons = {["0"] = true, ["7"] = true, ["8"] = true, ["f"] = true}, {"l", "r", "m"}
local charW, charH, chars, resp local charW, charH, chars
local calls = { } local calls = { }
local curCalls = { delay = 0 } local curCalls = { delay = 0 }
@@ -32,38 +36,44 @@ local callCount = 0
local function showSyntax() local function showSyntax()
print('Gif Recorder by Bomb Bloke\n') print('Gif Recorder by Bomb Bloke\n')
print('Syntax: recGif [-i] [-s] [-ld:<delay>] filename') print('Syntax: recGif [-i] [-s] [-ld:<delay>] filename')
print(' -i : show input') print(' --showInput : show input')
print(' -s : skip last') print(' --skipLast : skip last')
print(' -ld : last delay') print(' --lastDelay : last delay')
print(' --noResize : dont resize')
end end
for i = #arg, 1, -1 do if options.showInput then
local curArg = arg[i]:lower() showInput, ySize = true, ySize + 1
if curArg == "-i" then
showInput, ySize = true, ySize + 1
table.remove(arg, i)
elseif curArg == "-s" then
skipLast = true
table.remove(arg, i)
elseif curArg:sub(1, 4) == "-ld:" then
curArg = tonumber(curArg:sub(5))
if curArg then lastDelay = curArg end
table.remove(arg, i)
elseif curArg == '-?' then
showSyntax()
return
elseif i ~= #arg then
showSyntax()
printError('\nInvalid argument')
return
end
end end
print('Gif Recorder by Bomb Bloke\n') if options.skipLast then
print('Press control-p to stop recording') skipLast = true
end
local filename = arg[#arg] if options.lastDelay then
lastDelay = options.lastDelay
end
if options.help then
showSyntax()
return
end
if options.daemon then
device.keyboard.addHotkey('control-P', function()
multishell.openTab({
path = 'sys/apps/shell.lua',
args = { arg[0], '--noResize', '--rawOutput', 'recorder.gif' },
})
end)
return
end
print('Gif Recorder by Bomb Bloke')
print(version)
print('\nPress control-p to stop recording')
local filename = args[1]
if not filename then if not filename then
print('Enter file name:') print('Enter file name:')
filename = read() filename = read()
@@ -131,37 +141,34 @@ end
-- Build a terminal that records stuff: -- Build a terminal that records stuff:
recTerm = multishell.term local recTerm = multishell.term
for key, func in pairs(oldTerm) do for key, func in pairs(oldTerm) do
recTerm[key] = function(...) if type(func) == 'function' then
local result = { func(...) } recTerm[key] = function(...)
local result = { func(...) }
if callCount == 0 then if callCount == 0 then
os.queueEvent('capture_frame') os.queueEvent('capture_frame')
end
callCount = callCount + 1
curCalls[callCount] = { key, ... }
return unpack(result)
end end
callCount = callCount + 1
curCalls[callCount] = { key, ... }
return unpack(result)
end end
end end
local tabId = multishell.getCurrent() local tabId = multishell.getCurrent()
multishell.hideTab(tabId)
if not options.noResize then
os.queueEvent('term_resize')
end
_G.device.keyboard.addHotkey('control-p', function() _G.device.keyboard.addHotkey('control-p', function()
os.queueEvent('recorder_stop') os.queueEvent('recorder_stop')
end) end)
local tabs = multishell.getTabs()
for _,tab in pairs(tabs) do
if tab.isOverview then
multishell.hideTab(tabId)
multishell.setFocus(tab.tabId)
os.queueEvent('term_resize')
break
end
end
local curTime = os.clock() - 1 local curTime = os.clock() - 1
while true do while true do
@@ -200,8 +207,12 @@ if skipLast and #calls > 1 then calls[#calls] = nil end
calls[#calls].delay = lastDelay calls[#calls].delay = lastDelay
if options.rawOutput then
Util.writeTable('tmp/raw.txt', calls)
return
end
print(string.format("Encoding %d frames...", #calls)) print(string.format("Encoding %d frames...", #calls))
--Util.writeTable('tmp/raw.txt', calls)
-- Perform a quick re-parse of the recorded data (adding frames for when the cursor blinks): -- Perform a quick re-parse of the recorded data (adding frames for when the cursor blinks):

View File

@@ -17,12 +17,6 @@
run = "Pipes", run = "Pipes",
iconExt = "\030 \031 \128\0300\0310\128\030 \031 \128\0310\143\0300\031 \130\030 \128\0300\0310\128\010\0300\031 \131\0310\128\031 \131\131\030 \0310\159\031 \128\0310\143\010\030 \031 \128\0315\143\031 \128\128\128\128\0300\131", iconExt = "\030 \031 \128\0300\0310\128\030 \031 \128\0310\143\0300\031 \130\030 \128\0300\0310\128\010\0300\031 \131\0310\128\031 \131\131\030 \0310\159\031 \128\0310\143\010\030 \031 \128\0315\143\031 \128\128\128\128\0300\131",
}, },
[ "fb1c39e9f4f3c2628ad173ab401a6e4e4baf783d" ] = {
title = "Sounds",
category = "System",
run = "SoundPlayer",
iconExt = "\030 \031 \128\0307\159\129\030 \0317\149\0310\144\0300\031 \155\030 \0310\137\144\010\0307\0317\128\128\128\030 \149\0300\031 \149\030 \128\0310\149\0300\031 \149\010\030 \031 \128\0317\130\0307\031 \144\030 \0317\149\0310\129\134\152\129",
},
[ "a2accffe95b2c8be30e8a05e0c6ab7e8f5966f43" ] = { [ "a2accffe95b2c8be30e8a05e0c6ab7e8f5966f43" ] = {
title = "Strafe", title = "Strafe",
category = "Games", category = "Games",

View File

@@ -6,7 +6,6 @@ local Event = require('opus.event')
local colors = _G.colors local colors = _G.colors
local fs = _G.fs local fs = _G.fs
local gps = _G.gps
local os = _G.os local os = _G.os
local peripheral = _G.peripheral local peripheral = _G.peripheral
local read = _G.read local read = _G.read
@@ -200,7 +199,7 @@ local function server(mode)
error('Modem is not activated or connected: ' .. k) error('Modem is not activated or connected: ' .. k)
end end
if mode == 'gps' then if mode == 'gps' then
modem.open(gps.CHANNEL_GPS) modem.open(GPS.CHANNEL_GPS)
elseif mode == 'snmp' then elseif mode == 'snmp' then
modem.open(999) modem.open(999)
end end
@@ -254,9 +253,9 @@ local function server(mode)
Event.on('modem_message', function(_, side, channel, computerId, message, distance) Event.on('modem_message', function(_, side, channel, computerId, message, distance)
if distance and modems[side] then if distance and modems[side] then
if mode == 'gps' and channel == gps.CHANNEL_GPS and message == "PING" then if mode == 'gps' and channel == GPS.CHANNEL_GPS and message == "PING" then
for _, modem in pairs(modems) do for _, modem in pairs(modems) do
modem.transmit(computerId, gps.CHANNEL_GPS, { modem.x, modem.y, modem.z }) modem.transmit(computerId, GPS.CHANNEL_GPS, { modem.x, modem.y, modem.z })
end end
getPosition(computerId, modems[side], distance) getPosition(computerId, modems[side], distance)
end end
@@ -314,4 +313,4 @@ else
end end
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()

View File

@@ -250,5 +250,3 @@ turtle.setStatus('Jamming')
UI:pullEvents() UI:pullEvents()
turtle.setStatus('idle') turtle.setStatus('idle')
page:play(false) page:play(false)
UI.term:reset()

174
ignore/passthrough.lua Normal file
View File

@@ -0,0 +1,174 @@
local _rep = string.rep
local _sub = string.sub
local colors = _G.colors
local palette = { }
for n = 1, 16 do
palette[2 ^ (n - 1)] = _sub("0123456789abcdef", n, n)
end
local swindow = { }
function swindow.createPassthrough(parent, wx, wy, width, height)
local window = { }
local cx, cy = 1, 1
local blink = false
local fg = colors.white
local bg = colors.black
local function crop(text, x)
local w = #text
if x < 1 then
text = _sub(text, 2 - x)
w = w + x - 1
x = 1
end
if x + w - 1 > width then
text = _sub(text, 1, width - x + 1)
end
return text
end
local function blit(text, fg, bg)
parent.setCursorPos(cx + wx - 1, cy + wy - 1)
parent.blit(text, fg, bg)
cx = cx + #text
end
function window.write(text)
if cy > 0 and cy <= height then
text = crop(tostring(text), cx)
if #text > 0 then
--parent.setCursorPos(cx + wx - 1, cy + wy - 1)
blit(text, _rep(palette[fg], #text), _rep(palette[bg], #text))
end
end
end
function window.blit(text, fg, bg)
if cy > 0 and cy <= height then
text = crop(tostring(text), cx)
if #text > 0 then
blit(text, crop(tostring(fg), cx), crop(tostring(bg), cx))
end
end
end
function window.clear()
local filler = _rep(' ', width)
for i = 1, height do
parent.setCursorPos(wx, i + wy - 1)
parent.write(filler)
end
end
function window.clearLine()
if cy > 0 and cy <= height then
local filler = _rep(' ', width)
parent.setCursorPos(cx + wx - 1, cy + wy - 1)
parent.write(filler)
end
end
function window.getCursorPos()
return cx, cy
end
function window.setCursorPos(x, y)
cx = math.floor(x)
cy = math.floor(y)
parent.setCursorPos(cx + wx - 1, cy + wy - 1)
end
function window.setCursorBlink(b)
blink = b
parent.setCursorBlink(b)
end
function window.getCursorBlink()
return blink
end
window.isColor = parent.isColor
window.isColour = parent.isColour
window.setPaletteColour = parent.setPaletteColour
window.setPaletteColor = parent.setPaletteColor
window.getPaletteColour = parent.getPaletteColour
window.getPaletteColor = parent.getPaletteColour
window.setBackgroundColor = parent.setBackgroundColor
window.setBackgroundColour = parent.setBackgroundColor
window.getBackgroundColor = parent.getBackgroundColor
window.getBackgroundColour = parent.getBackgroundColor
window.setVisible = parent.setVisible
window.redraw = function() end --parent.redraw
function window.getTextColor()
return fg
end
window.getTextColour = window.getTextColor
function window.setTextColor(textColor)
fg = textColor
parent.setTextColor(fg)
end
window.setTextColour = window.setTextColor
function window.restoreCursor()
parent.setCursorPos(cx + wx - 1, cy + wy - 1)
parent.setTextColor(fg)
parent.setCursorBlink(blink)
end
function window.getSize()
return width, height
end
function window.scroll( n )
if n ~= 0 then
local lines = { }
for i = 1, height do
lines[i] = { parent.getLine(wy + i - 1) }
end
for newY = 1, height do
local y = newY + n
parent.setCursorPos(wx, wy + newY - 1)
if y >= 1 and y <= height then
parent.blit(table.unpack(lines[y]))
else
parent.blit(
_rep(' ', width),
_rep(palette[fg], width),
_rep(palette[bg], width))
end
end
parent.setCursorPos(cx + wx - 1, cy + wy - 1)
end
end
function window.getLine(y)
local t, tc, bc = parent.getLine(y + cy - 1)
return t:sub(1, width), tc:sub(1, width), bc:sub(1, width)
end
function window.getPosition()
return wx, wy
end
function window.reposition(nNewX, nNewY, nNewWidth, nNewHeight, newParent)
wx = nNewX
wy = nNewY
width = nNewWidth
height = nNewHeight
window.restoreCursor()
end
return window
end
return swindow

441
ignore/twm.lua Normal file
View File

@@ -0,0 +1,441 @@
local Terminal = require('opus.terminal')
local trace = require('opus.trace')
local Util = require('opus.util')
local colors = _G.colors
local os = _G.os
local printError = _G.printError
local term = _G.term
local window = _G.window
local UID = 0
local multishell = { }
local processes = { }
local parentTerm = term.current()
local sessionFile = 'usr/config/twm'
local running
local parentMon = term.current()
local defaultEnv = Util.shallowCopy(_ENV)
defaultEnv.multishell = multishell
local monDim, termDim = { }, { }
monDim.width, monDim.height = parentMon.getSize()
termDim.width, termDim.height = parentTerm.getSize()
-- even though the monitor window is set to visible
-- the canvas is not (possibly change default in terminal.lua)
-- canvas is not visible so that redraws
-- are done once in the event loop
local monitor = Terminal.window(parentMon, 1, 1, monDim.width, monDim.height, true)
monitor.setBackgroundColor(colors.gray)
monitor.clear()
local function nextUID()
UID = UID + 1
return UID
end
local function xprun(env, path, ...)
setmetatable(env, { __index = _G })
local fn, m = loadfile(path, env)
if fn then
return trace(fn, ...)
end
return fn, m
end
local function write(win, x, y, text)
win.setCursorPos(x, y)
win.write(text)
end
local function redraw()
monitor.canvas:dirty()
monitor.canvas:clear(colors.gray)
for _, process in ipairs(processes) do
process.container.canvas:dirty()
end
end
local function getProcessAt(x, y)
for k = #processes, 1, -1 do
local process = processes[k]
if x >= process.x and
y >= process.y and
x <= process.x + process.width - 1 and
y <= process.y + process.height - 1 then
return k, process
end
end
end
--[[ A runnable process ]]--
local Process = { }
function Process:new(args)
args.env = args.env or Util.shallowCopy(defaultEnv)
args.width = args.width or math.floor(termDim.width * .75)
args.height = args.height or math.floor(termDim.height * .75)
-- TODO: randomize start position
local self = setmetatable({
uid = nextUID(),
x = args.x or 1,
y = args.y or 1,
width = args.width,
height = args.height + 1,
path = args.path,
args = args.args or { },
title = args.title or 'shell',
timestamp = os.clock(),
isMoving = false,
isResizing = false,
}, { __index = Process })
self:adjustDimensions()
if not args.x then
self.x = math.random(1, monDim.width - self.width + 1)
self.y = math.random(1, monDim.height - self.height + 1)
end
self.container = Terminal.window(monitor, self.x, self.y, self.width, self.height, true)
self.window = window.create(self.container, 1, 2, args.width, args.height, true)
self.terminal = self.window
self.container.canvas.parent = monitor.canvas
table.insert(monitor.canvas.layers, 1, self.container.canvas)
self.container.canvas:setVisible(true)
--self.container.getSize = self.window.getSize
self.co = coroutine.create(function()
local result, err
if args.fn then
result, err = Util.runFunction(args.env, args.fn, table.unpack(self.args))
elseif args.path then
result, err = xprun(args.env, args.path, table.unpack(self.args))
end
if not result and err and err ~= 'Terminated' then
printError('\n' .. tostring(err))
os.pullEventRaw('terminate')
end
multishell.removeProcess(self)
end)
self:focus(false)
return self
end
function Process:focus(focused)
self.container.setBackgroundColor(focused and colors.yellow or colors.lightGray)
self.container.setTextColor(colors.black)
write(self.container, 1, 1, string.rep(' ', self.width))
write(self.container, 2, 1, self.title)
write(self.container, self.width - 1, 1, '*')
write(self.container, self.width - 3, 1, '\029')
end
function Process:drawSizers()
self.container.setBackgroundColor(colors.black)
self.container.setTextColor(colors.yellow)
local str = string.format('%d x %d', self.width - 2, self.height - 3)
write(self.container, (self.width - #str) / 2, 1, str)
end
function Process:adjustDimensions()
self.width = math.min(self.width, monDim.width)
self.height = math.min(self.height, monDim.height)
self.x = math.max(1, self.x)
self.y = math.max(1, self.y)
self.x = math.min(self.x, monDim.width - self.width + 1)
self.y = math.min(self.y, monDim.height - self.height + 1)
end
function Process:reposition(resizing)
self:adjustDimensions()
self.container.reposition(self.x, self.y, self.width, self.height)
self.window.reposition(1, 2, self.width, self.height - 1)
if self.window ~= self.terminal then
if self.terminal.reposition then -- ??
self.terminal.reposition(1, 1, self.width, self.height - 1)
end
end
if resizing then
self:focus(self == processes[#processes])
end
redraw()
end
function Process:click(x, y, rx, ry)
if y == 1 then -- title bar
if x == self.width - 1 then
self:resume('terminate')
elseif x == self.width - 3 then
self.isResizing = { x = rx, y = ry, h = self.height, w = self.width }
else
self.isMoving = { x = rx, y = ry, ox = self.x, oy = self.y }
end
else
if self.isMoving then
self.isMoving = false
end
self:resume('mouse_click', 1, x, y - 1)
self:resume('mouse_up', 1, x, y - 1)
end
end
function Process:resize(x, y)
self.height = y - self.isResizing.y + self.isResizing.h
self.width = x - self.isResizing.x + self.isResizing.w
self:reposition(true)
self:resume('term_resize')
self:drawSizers()
multishell.saveSession(sessionFile)
end
function Process:resume(event, ...)
if coroutine.status(self.co) == 'dead' then
return
end
if not self.filter or self.filter == event or event == "terminate" then
--term.redirect(self.terminal)
local previousTerm = term.redirect(self.terminal)
local previous = running
running = self -- stupid shell set title
local ok, result = coroutine.resume(self.co, event, ...)
running = previous
self.terminal = term.current()
term.redirect(previousTerm)
if ok then
self.filter = result
else
printError(result)
end
return ok, result
end
end
--[[ Install a multishell manager for the monitor ]]--
function multishell.getFocus()
return processes[#processes].uid
end
function multishell.setFocus(uid)
local process = Util.find(processes, 'uid', uid)
if process then
local lastFocused = processes[#processes]
if lastFocused ~= process then
if lastFocused then
lastFocused:focus(false)
end
Util.removeByValue(processes, process)
table.insert(processes, process)
process.container.canvas:raise()
process:focus(true)
process.container.canvas:dirty()
process.window.restoreCursor()
end
return true
end
return false
end
function multishell.getTitle(uid)
local process = Util.find(processes, 'uid', uid)
if process then
return process.title
end
end
function multishell.setTitle(uid, title)
local process = Util.find(processes, 'uid', uid)
if process then
process.title = title or ''
process:focus(process == processes[#processes])
end
end
function multishell.getCurrent()
if running then
return running.uid
end
end
function multishell.getCount()
return #processes
end
function multishell.getTabs()
return processes
end
function multishell.launch(env, file, ...)
return multishell.openTab({
path = file,
env = env,
title = 'shell',
args = { ... },
})
end
function multishell.openTab(tabInfo)
local process = Process:new(tabInfo)
table.insert(processes, 1, process)
--local previousTerm = term.current()
process:resume()
--term.redirect(previousTerm)
multishell.saveSession(sessionFile)
return process.uid
end
function multishell.removeProcess(process)
Util.removeByValue(processes, process)
process.container.canvas:removeLayer()
multishell.saveSession(sessionFile)
redraw()
end
function multishell.saveSession(filename)
local t = { }
for _,process in ipairs(processes) do
if process.path then
table.insert(t, {
x = process.x,
y = process.y,
width = process.width,
height = process.height - 1,
path = process.path,
args = process.args,
})
end
end
Util.writeTable(filename, t)
end
function multishell.loadSession(filename)
local config = Util.readTable(filename)
if config then
for k = #config, 1, -1 do
multishell.openTab(config[k])
end
end
end
function multishell.stop()
multishell._stop = true
end
function multishell.start()
while not multishell._stop do
local event = { os.pullEventRaw() }
if event[1] == 'terminate' then
local focused = processes[#processes]
if focused then
focused:resume('terminate')
if #processes == 0 then
break
end
end
elseif event[1] == 'monitor_touch' or event[1] == 'mouse_click' then --or event[1] == 'mouse_up' then
local x, y = event[3], event[4]
local key, process = getProcessAt(x, y)
if process then
if key ~= #processes then
multishell.setFocus(process.uid)
multishell.saveSession(sessionFile)
end
process:click(x - process.x + 1, y - process.y + 1, x, y)
end
elseif event[1] == 'mouse_up' then
local focused = processes[#processes]
if focused and (focused.isResizing or focused.isMoving) then
multishell.saveSession(sessionFile)
if focused.isResizing then
focused:focus(true)
end
end
if focused then
focused.isResizing = nil
focused.isMoving = false
end
elseif event[1] == 'mouse_drag' then
local focused = processes[#processes]
if focused then
if focused.isResizing then
focused:resize(event[3], event[4])
elseif focused.isMoving then
focused.x = event[3] - focused.isMoving.x + focused.isMoving.ox
focused.y = event[4] - focused.isMoving.y + focused.isMoving.oy
focused:reposition(false)
end
end
elseif event[1] == 'char' or
event[1] == 'key' or
event[1] == 'key_up' or
event[1] == 'paste' or
event[1] == 'mouse_scroll' then
local focused = processes[#processes]
if focused then
focused:resume(table.unpack(event))
end
else
for _,process in pairs(Util.shallowCopy(processes)) do
process:resume(table.unpack(event))
end
end
monitor.canvas:render(parentMon)
local focused = processes[#processes]
if focused then
focused.window.restoreCursor()
end
end
end
multishell.loadSession(sessionFile)
if #processes == 0 then
multishell.openTab({
path = 'sys/apps/shell.lua',
title = 'shell',
})
end
processes[#processes]:focus(true)
multishell.start()
term.redirect(parentTerm)
parentTerm.clear()
parentTerm.setCursorPos(1, 1)

View File

@@ -180,7 +180,14 @@ function fs.open(fname, flags)
local ctr = 0 local ctr = 0
local lines local lines
return { return {
readLine = function() read = function()
if not lines then
lines = decompress(f.readAll())
end
ctr = ctr + 1
return lines:sub(ctr, ctr)
end,
readLine = function()
if not lines then if not lines then
lines = split(decompress(f.readAll())) lines = split(decompress(f.readAll()))
end end

View File

@@ -16,16 +16,19 @@ local config = Config.load('lzwfs', {
local tab = UI.Tab { local tab = UI.Tab {
tabTitle = 'Compression', tabTitle = 'Compression',
description = 'Disk compression', description = 'Disk compression',
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 6,
},
label1 = UI.Text { label1 = UI.Text {
x = 2, y = 2, x = 3, y = 3,
value = 'Enable compression', value = 'Enable compression',
}, },
checkbox = UI.Checkbox { checkbox = UI.Checkbox {
x = 20, y = 2, x = 21, y = 3,
value = config.enabled value = config.enabled
}, },
entry = UI.TextEntry { entry = UI.TextEntry {
x = 2, y = 4, ex = -2, x = 3, y = 5 , ex = -3,
limit = 256, limit = 256,
shadowText = 'enter new path', shadowText = 'enter new path',
accelerators = { accelerators = {
@@ -34,7 +37,7 @@ local tab = UI.Tab {
help = 'add a new path', help = 'add a new path',
}, },
grid = UI.Grid { grid = UI.Grid {
x = 2, ex = -2, y = 6, ey = -5, x = 2, ex = -2, y = 8, ey = -5,
disableHeader = true, disableHeader = true,
columns = { { key = 'value' } }, columns = { { key = 'value' } },
autospace = true, autospace = true,
@@ -45,7 +48,7 @@ local tab = UI.Tab {
}, },
}, },
button = UI.Button { button = UI.Button {
x = -9, ex = -2, y = -3, x = -8, ex = -2, y = -3,
text = 'Apply', text = 'Apply',
event = 'apply', event = 'apply',
}, },
@@ -85,7 +88,7 @@ local function rewriteFiles(p)
end end
function tab:eventHandler(event) function tab:eventHandler(event)
if event.type == 'add_path' then if event.type == 'add_path' and self.entry.value then
table.insert(self.grid.values, { table.insert(self.grid.values, {
value = self.entry.value, value = self.entry.value,
}) })

View File

@@ -216,7 +216,7 @@ _G._syslog = function(...)
end end
local s, m = pcall(function() local s, m = pcall(function()
UI:pullEvents() UI:start()
end) end)
turtle.setStatus('idle') turtle.setStatus('idle')

View File

@@ -1,6 +1,6 @@
local Config = require('opus.config') local Config = require('opus.config')
local Event = require('opus.event') local Event = require('opus.event')
local fuzzy = require('milo.fuzzyMatch') local fuzzy = require('opus.fuzzy')
local Sound = require('opus.sound') local Sound = require('opus.sound')
local Socket = require('opus.socket') local Socket = require('opus.socket')
local sync = require('opus.sync').sync local sync = require('opus.sync').sync
@@ -60,11 +60,11 @@ local page = UI.Page {
statusBar = UI.Window { statusBar = UI.Window {
y = -1, y = -1,
filter = UI.TextEntry { filter = UI.TextEntry {
x = 1, ex = -12, x = 1, ex = -13,
limit = 50, limit = 50,
shadowText = 'filter', shadowText = 'filter',
backgroundColor = colors.cyan, backgroundColor = 'primary',
backgroundFocusColor = colors.cyan, backgroundFocusColor = 'primary',
accelerators = { accelerators = {
[ 'enter' ] = 'eject', [ 'enter' ] = 'eject',
[ 'up' ] = 'grid_up', [ 'up' ] = 'grid_up',
@@ -73,8 +73,8 @@ local page = UI.Page {
}, },
}, },
amount = UI.TextEntry { amount = UI.TextEntry {
x = -11, ex = -7, x = -12, ex = -7,
limit = 3, limit = 4,
shadowText = '1', shadowText = '1',
shadowTextColor = colors.gray, shadowTextColor = colors.gray,
backgroundColor = colors.black, backgroundColor = colors.black,
@@ -169,7 +169,7 @@ end
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'quit' then if event.type == 'quit' then
UI:exitPullEvents() UI:quit()
elseif event.type == 'setup' then elseif event.type == 'setup' then
self.setup.form:setValues(context.state) self.setup.form:setValues(context.state)
@@ -246,7 +246,7 @@ function page:eventHandler(event)
Config.update('miloRemote', context.state) Config.update('miloRemote', context.state)
elseif event.type == 'text_change' and event.element == self.statusBar.filter then elseif event.type == 'text_change' and event.element == self.statusBar.filter then
self.filter = event.text self.filter = event.text or ''
if #self.filter == 0 then if #self.filter == 0 then
self.filter = nil self.filter = nil
end end
@@ -517,14 +517,14 @@ local function loadDirectory(dir)
}) })
end end
end end
page.menuBar.config:add({ dropmenu = UI.DropMenu { buttons = dropdown } }) page.menuBar.config.dropdown = dropdown
end end
local programDir = fs.getDir(shell.getRunningProgram()) local programDir = fs.getDir(shell.getRunningProgram())
loadDirectory(fs.combine(programDir, 'plugins/remote')) loadDirectory(fs.combine(programDir, 'plugins/remote'))
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()
if context.socket then if context.socket then
context.socket:close() context.socket:close()

View File

@@ -309,7 +309,7 @@ function Craft.craftRecipeInternal(recipe, count, storage, origItem, path)
local function maxBatch() local function maxBatch()
local max = 64 local max = 64
for _, i in Craft.ingredients(recipe) do for _, i in Craft.ingredients(recipe) do
max = math.min(max, math.floor(64 / i.count)) max = math.min(max, math.floor(itemDB:getMaxCount(i.key) / i.count))
end end
return max return max
end end

View File

@@ -1,19 +0,0 @@
-- Based on Squid's fuzzy search
-- https://github.com/SquidDev-CC/artist/blob/vnext/artist/lib/match.lua
--
-- not very fuzzy anymore
local SCORE_WEIGHT = 1000
local LEADING_LETTER_PENALTY = -3
local LEADING_LETTER_PENALTY_MAX = -9
local _find = string.find
local _max = math.max
return function(str, pattern)
local start = _find(str, pattern, 1, true)
if start then
-- All letters before the current one are considered leading, so add them to our penalty
return SCORE_WEIGHT + _max(LEADING_LETTER_PENALTY * (start - 1), LEADING_LETTER_PENALTY_MAX)
end
end

View File

@@ -1,53 +0,0 @@
local class = require('opus.class')
local itemDB = require('core.itemDB')
local Mini = require('milo.miniAdapter')
local os = _G.os
local Adapter = class(Mini)
function Adapter:init(args)
Mini.init(self, args)
self._rawList = self.list
function self.list()
-- wait for up to 1 sec until any items that have been inserted
-- into interface are added to the system
for _ = 0, 20 do
if #self._rawList() == 0 then
break
end
os.sleep(0)
end
local list = { }
for _, v in pairs(self.listAvailableItems()) do
list[itemDB:makeKey(v)] = v
end
return list
end
function self.getItemMeta(key)
local item = self.findItem(itemDB:splitKey(key))
if item and item.getMetadata then
return item.getMetadata()
end
end
function self.pushItems(target, key, amount, slot)
local item = self.findItem(itemDB:splitKey(key))
if item and item.export then
return item.export(target, amount, slot)
end
return 0
end
function self.pullItems(target, key, amount, slot)
_G._syslog({target, key, amount, slot })
return 0
end
end
return Adapter

View File

@@ -1,6 +1,6 @@
local Craft = require('milo.craft2') local Craft = require('milo.craft2')
local Event = require('opus.event') local Event = require('opus.event')
local fuzzy = require('milo.fuzzyMatch') local fuzzy = require('opus.fuzzy')
local Milo = require('milo') local Milo = require('milo')
local Sound = require('opus.sound') local Sound = require('opus.sound')
local UI = require('opus.ui') local UI = require('opus.ui')
@@ -50,12 +50,12 @@ local page = UI.Page {
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
filter = UI.TextEntry { filter = UI.TextEntry {
x = 1, ex = -17, x = 1, ex = -18,
limit = 50, limit = 50,
shadowText = 'filter', shadowText = 'filter',
shadowTextColor = colors.gray, shadowTextColor = colors.gray,
backgroundColor = colors.cyan, backgroundColor = 'primary',
backgroundFocusColor = colors.cyan, backgroundFocusColor = 'primary',
accelerators = { accelerators = {
[ 'enter' ] = 'eject', [ 'enter' ] = 'eject',
[ 'up' ] = 'grid_up', [ 'up' ] = 'grid_up',
@@ -64,14 +64,14 @@ local page = UI.Page {
}, },
}, },
storageStatus = UI.Text { storageStatus = UI.Text {
x = -16, ex = -9, x = -17, ex = -10,
textColor = colors.lime, textColor = colors.lime,
backgroundColor = colors.cyan, backgroundColor = 'primary',
value = '', value = '',
}, },
amount = UI.TextEntry { amount = UI.TextEntry {
x = -8, ex = -4, x = -9, ex = -4,
limit = 3, limit = 4,
shadowText = '1', shadowText = '1',
shadowTextColor = colors.gray, shadowTextColor = colors.gray,
backgroundColor = colors.black, backgroundColor = colors.black,
@@ -208,7 +208,7 @@ end
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'quit' then if event.type == 'quit' then
UI:exitPullEvents() UI:quit()
elseif event.type == 'eject' or event.type == 'grid_select' then elseif event.type == 'eject' or event.type == 'grid_select' then
self:eject(1) self:eject(1)
@@ -272,7 +272,7 @@ function page:eventHandler(event)
end end
elseif event.type == 'text_change' and event.element == self.statusBar.filter then elseif event.type == 'text_change' and event.element == self.statusBar.filter then
self.filter = event.text self.filter = event.text or ''
if #self.filter == 0 then if #self.filter == 0 then
self.filter = nil self.filter = nil
end end

View File

@@ -7,7 +7,6 @@ local Util = require('opus.util')
local colors = _G.colors local colors = _G.colors
local device = _G.device local device = _G.device
local turtle = _G.turtle
local context = Milo:getContext() local context = Milo:getContext()
@@ -22,8 +21,8 @@ local networkPage = UI.Page {
y = -2, x = 1, ex = -9, y = -2, x = 1, ex = -9,
limit = 50, limit = 50,
shadowText = 'filter', shadowText = 'filter',
backgroundColor = colors.cyan, backgroundColor = 'primary',
backgroundFocusColor = colors.cyan, backgroundFocusColor = 'primary',
}, },
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
y = 2, ey = -3, y = 2, ey = -3,
@@ -195,7 +194,6 @@ nodeWizard = UI.Page {
pages = { pages = {
general = UI.WizardPage { general = UI.WizardPage {
index = 1, index = 1,
backgroundColor = colors.cyan,
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 1, ey = 3, x = 2, ex = -2, y = 1, ey = 3,
manualControls = true, manualControls = true,
@@ -236,11 +234,11 @@ The settings will take effect immediately!]],
}, },
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
backgroundColor = colors.cyan, backgroundColor = 'primary',
}, },
notification = UI.Notification { }, notification = UI.Notification { },
filter = UI.SlideOut { filter = UI.SlideOut {
backgroundColor = colors.cyan, noFill = true,
menuBar = UI.MenuBar { menuBar = UI.MenuBar {
buttons = { buttons = {
{ text = 'Save', event = 'save' }, { text = 'Save', event = 'save' },
@@ -248,7 +246,8 @@ The settings will take effect immediately!]],
}, },
}, },
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
x = 2, ex = -6, y = 2, ey = -6, x = 2, ex = -6, y = 3, ey = -7,
disableHeader = true,
columns = { columns = {
{ heading = 'Name', key = 'displayName' }, { heading = 'Name', key = 'displayName' },
}, },
@@ -262,7 +261,7 @@ The settings will take effect immediately!]],
text = '-', event = 'remove_entry', help = 'Remove', text = '-', event = 'remove_entry', help = 'Remove',
}, },
form = UI.Form { form = UI.Form {
x = 2, y = -4, height = 3, x = 2, y = -5, height = 3,
margin = 1, margin = 1,
manualControls = true, manualControls = true,
[1] = UI.Checkbox { [1] = UI.Checkbox {
@@ -290,7 +289,7 @@ The settings will take effect immediately!]],
}, },
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
backgroundColor = colors.cyan, backgroundColor = 'primary',
}, },
}, },
} }

View File

@@ -17,7 +17,6 @@ Right-clicking on the activity monitor will reset the totals.]]
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Activity Monitor', title = 'Activity Monitor',
index = 2, index = 2,
backgroundColor = colors.cyan,
[1] = UI.TextArea { [1] = UI.TextArea {
x = 2, ex = -2, y = 2, ey = 6, x = 2, ex = -2, y = 2, ey = 6,
marginRight = 0, marginRight = 0,

View File

@@ -3,7 +3,6 @@ local Event = require('opus.event')
local Milo = require('milo') local Milo = require('milo')
local UI = require('opus.ui') local UI = require('opus.ui')
local colors = _G.colors
local device = _G.device local device = _G.device
local fs = _G.fs local fs = _G.fs
local os = _G.os local os = _G.os
@@ -23,7 +22,6 @@ Backup configuration files each minecraft day.
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Backup Drive', title = 'Backup Drive',
index = 2, index = 2,
backgroundColor = colors.cyan,
[1] = UI.TextArea { [1] = UI.TextArea {
x = 2, ex = -2, y = 2, ey = -2, x = 2, ex = -2, y = 2, ey = -2,
value = string.format(template, Ansi.yellow, Ansi.reset), value = string.format(template, Ansi.yellow, Ansi.reset),

View File

@@ -18,7 +18,6 @@ Note that you do not need to import items from the brewing stand or export blaze
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Brewing Stand', title = 'Brewing Stand',
index = 2, index = 2,
backgroundColor = colors.cyan,
[1] = UI.TextArea { [1] = UI.TextArea {
x = 2, ex = -2, y = 2, ey = -2, x = 2, ex = -2, y = 2, ey = -2,
value = string.format(template, Ansi.yellow, Ansi.reset), value = string.format(template, Ansi.yellow, Ansi.reset),

View File

@@ -0,0 +1,29 @@
local itemDB = require('core.itemDB')
local Milo = require('milo')
local device = _G.device
local EmitterTask = {
name = 'emitter',
priority = 5,
}
local function filter(a)
return a.emitter
end
function EmitterTask:cycle(context)
for node in context.storage:filterActive('emitter', filter) do
local config = node.emitter
local item = Milo:getItem(itemDB:splitKey(config.item))
config.signal = not not config.signal
if item and item.count >= config.amount then
device[node.name].setOutput(config.side, config.signal)
else
device[node.name].setOutput(config.side, not config.signal)
end
end
end
Milo:registerTask(EmitterTask)

View File

@@ -0,0 +1,107 @@
local Milo = require('milo')
local UI = require('opus.ui')
local itemDB = require('core.itemDB')
local colors = _G.colors
local device = _G.device
local wizardPage = UI.WizardPage {
title = 'Level Emitter',
index = 2,
[1] = UI.TextArea {
x = 2, y = 1,
height = 2,
textColor = colors.yellow,
value = 'Emit a redstone signal if an\nitem amount if over a threshold',
},
form = UI.Form {
x = 1, ex = -1, y = 3, ey = -1,
manualControls = true,
itemName = UI.TextEntry {
formLabel = 'Item', formKey = 'item', formIndex = 1,
help = 'Item to monitor',
required = true,
},
side = UI.Chooser {
formLabel = 'Side', formKey = 'side', formIndex = 2,
width = 10,
choices = {
{name = 'Down', value = 'down'},
{name = 'Up', value = 'up'},
{name = 'North', value = 'north'},
{name = 'South', value = 'south'},
{name = 'West', value = 'west'},
{name = 'East', value = 'east'},
},
required = true,
},
amount = UI.TextEntry {
formLabel = 'Amount', formKey = 'amount', formIndex = 3,
width = 7,
transform = 'number',
help = 'Threshold value',
required = true,
},
signal = UI.Checkbox {
formLabel = 'Signal', formKey = 'signal', formIndex = 4,
help = 'Enable redstone signal when over threshold',
},
scanItem = UI.Button {
x = 15, y = 6,
text = 'Scan item', event = 'scan_turtle',
help = 'Scan an item from the turtle inventory',
},
},
}
function wizardPage:setNode(node)
self.node = node
if not self.node.emitter then
self.node.emitter = {
signal = { value = true }
}
end
self.form:setValues(self.node.emitter)
end
function wizardPage:validate()
return self.form:save()
end
function wizardPage:isValidType(node)
local m = device[node.name]
return m and m.type == 'redstone_integrator' and {
name = 'Level Emitter',
value = 'emitter',
category = 'custom',
help = 'Emit redstone signals',
}
end
function wizardPage:isValidFor(node)
return node.mtype == 'emitter'
end
function wizardPage:enable()
Milo:pauseCrafting({ key = 'gridInUse', msg = 'Crafting paused' })
UI.WizardPage.enable(self)
end
function wizardPage:disable()
Milo:resumeCrafting({ key = 'gridInUse' })
UI.WizardPage.disable(self)
end
function wizardPage:eventHandler(event)
if event.type == 'scan_turtle' then
local inventory = Milo:getTurtleInventory()
for _,item in pairs(inventory) do
self.form.itemName.value = itemDB:makeKey(item)
break
end
self:draw()
Milo:emptyInventory()
end
end
UI:getPage('nodeWizard').wizard:add({ emiter = wizardPage })

View File

@@ -1,7 +1,6 @@
local Ansi = require('opus.ansi') local Ansi = require('opus.ansi')
local UI = require('opus.ui') local UI = require('opus.ui')
local colors = _G.colors
local device = _G.device local device = _G.device
--[[ Configuration Screen ]] --[[ Configuration Screen ]]
@@ -14,7 +13,6 @@ Any items placed in this chest will be imported into storage.
local inputChestWizardPage = UI.WizardPage { local inputChestWizardPage = UI.WizardPage {
title = 'Input Chest', title = 'Input Chest',
index = 2, index = 2,
backgroundColor = colors.cyan,
[1] = UI.TextArea { [1] = UI.TextArea {
x = 2, ex = -2, y = 2, ey = -2, x = 2, ex = -2, y = 2, ey = -2,
value = string.format(template, Ansi.yellow, Ansi.reset), value = string.format(template, Ansi.yellow, Ansi.reset),

View File

@@ -41,7 +41,6 @@ function page:eventHandler(event)
elseif event.type == 'focus_change' then elseif event.type == 'focus_change' then
self.statusBar:setStatus(event.focused.help) self.statusBar:setStatus(event.focused.help)
self.statusBar:draw()
elseif event.type == 'success_message' then elseif event.type == 'success_message' then
self.notification:success(event.message) self.notification:success(event.message)

View File

@@ -1,14 +1,11 @@
local Ansi = require('opus.ansi') local Ansi = require('opus.ansi')
local UI = require('opus.ui') local UI = require('opus.ui')
local colors = _G.colors
local infoTab = UI.Tab { local infoTab = UI.Tab {
tabTitle = 'Info', tabTitle = 'Info',
index = 4, index = 4,
backgroundColor = colors.cyan,
textArea = UI.TextArea { textArea = UI.TextArea {
x = 2, ex = -2, y = 2, x = 2, ex = -2, y = 2, ey = -2,
}, },
} }
@@ -27,6 +24,9 @@ function infoTab:draw()
value = value .. item.nbtHash .. '\n' value = value .. item.nbtHash .. '\n'
end end
value = value .. string.format('\n%sCount:%s %s',
Ansi.yellow, Ansi.reset, item.count)
value = value .. string.format('\n%sDamage:%s %s', value = value .. string.format('\n%sDamage:%s %s',
Ansi.yellow, Ansi.reset, item.damage) Ansi.yellow, Ansi.reset, item.damage)

View File

@@ -9,7 +9,6 @@ local context = Milo:getContext()
local machinesTab = UI.Tab { local machinesTab = UI.Tab {
tabTitle = 'Machine', tabTitle = 'Machine',
index = 3, index = 3,
backgroundColor = colors.cyan,
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
x = 2, ex = -2, y = 2, ey = -2, x = 2, ex = -2, y = 2, ey = -2,
disableHeader = true, disableHeader = true,

View File

@@ -21,12 +21,12 @@ local manageTab = UI.Tab {
[2] = UI.TextEntry { [2] = UI.TextEntry {
width = 7, width = 7,
formLabel = 'Min', formKey = 'low', help = 'Craft if below min', formLabel = 'Min', formKey = 'low', help = 'Craft if below min',
validate = 'numeric', transform = 'number',
}, },
[3] = UI.TextEntry { [3] = UI.TextEntry {
width = 7, width = 7,
formLabel = 'Max', formKey = 'limit', help = 'Send to trash if above max', formLabel = 'Max', formKey = 'limit', help = 'Send to trash if above max',
validate = 'numeric', transform = 'number',
}, },
[4] = UI.Checkbox { [4] = UI.Checkbox {
formLabel = 'Ignore Dmg', formKey = 'ignoreDamage', formLabel = 'Ignore Dmg', formKey = 'ignoreDamage',

View File

@@ -3,12 +3,9 @@ local itemDB = require('core.itemDB')
local Milo = require('milo') local Milo = require('milo')
local UI = require('opus.ui') local UI = require('opus.ui')
local colors = _G.colors
local recipeTab = UI.Tab { local recipeTab = UI.Tab {
tabTitle = 'Recipe', tabTitle = 'Recipe',
index = 2, index = 2,
backgroundColor = colors.cyan,
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
x = 2, ex = -2, y = 2, ey = -4, x = 2, ex = -2, y = 2, ey = -4,
disableHeader = true, disableHeader = true,

View File

@@ -9,7 +9,7 @@ local context = Milo:getContext()
local resetTab = UI.Tab { local resetTab = UI.Tab {
tabTitle = 'Reset', tabTitle = 'Reset',
index = 5, index = 5,
backgroundColor = colors.cyan, noFill = true,
textArea = UI.TextArea { textArea = UI.TextArea {
y = 2, ey = 6, y = 2, ey = 6,
textColor = colors.yellow, textColor = colors.yellow,

View File

@@ -15,7 +15,6 @@ local os = _G.os
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Crafting Monitor', title = 'Crafting Monitor',
index = 2, index = 2,
backgroundColor = colors.cyan,
[1] = UI.TextArea { [1] = UI.TextArea {
x = 2, ex = -2, y = 2, ey = 3, x = 2, ex = -2, y = 2, ey = 3,
marginRight = 0, marginRight = 0,

View File

@@ -1,43 +0,0 @@
local Ansi = require('opus.ansi')
local UI = require('opus.ui')
local colors = _G.colors
local device = _G.device
--[[ Configuration Screen ]]
local template =
[[%sWarning%s
Must an interface for Refined Storage / Applied Energistics.
Add all speed upgrades possible.
]]
local wizardPage = UI.WizardPage {
title = 'Mass Storage',
index = 2,
backgroundColor = colors.cyan,
[1] = UI.TextArea {
x = 2, ex = -2, y = 2, ey = -2,
value = string.format(template, Ansi.red, Ansi.reset),
},
}
function wizardPage:isValidFor(node)
if node.mtype == 'storage' then
local m = device[node.name]
return m and m.listAvailableItems
end
end
function wizardPage:setNode(node)
self.node = node
end
function wizardPage:validate()
self.node.adapterType = 'massAdapter'
return true
end
-- disable until a way is found to transfer between 2 non-transferrable nodes
-- UI:getPage('nodeWizard').wizard:add({ inputChest = wizardPage })

View File

@@ -10,18 +10,17 @@ local STARTUP_FILE = 'usr/autorun/miloRemote.lua'
local context = ({ ... })[1] local context = ({ ... })[1]
local setup = UI.SlideOut { local setup = UI.SlideOut {
backgroundColor = colors.cyan,
titleBar = UI.TitleBar { titleBar = UI.TitleBar {
title = 'Remote Setup', title = 'Remote Setup',
}, },
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 2, ey = -1, y = 2, ey = -1,
[1] = UI.TextEntry { [1] = UI.TextEntry {
formLabel = 'Server', formKey = 'server', formLabel = 'Server', formKey = 'server',
help = 'ID for the server', help = 'ID for the server',
shadowText = 'Milo server ID', shadowText = 'Milo server ID',
limit = 6, limit = 6,
validate = 'numeric', transform = 'number',
required = true, required = true,
}, },
[2] = UI.TextEntry { [2] = UI.TextEntry {
@@ -29,7 +28,7 @@ local setup = UI.SlideOut {
help = 'Use a slot for sending to storage', help = 'Use a slot for sending to storage',
shadowText = 'Inventory slot #', shadowText = 'Inventory slot #',
limit = 5, limit = 5,
validate = 'numeric', transform = 'number',
required = false, required = false,
}, },
[3] = UI.Checkbox { [3] = UI.Checkbox {
@@ -40,18 +39,18 @@ local setup = UI.SlideOut {
formLabel = 'Run on startup', formKey = 'runOnStartup', formLabel = 'Run on startup', formKey = 'runOnStartup',
help = 'Run this program on startup' help = 'Run this program on startup'
}, },
info = UI.TextArea { },
x = 1, ex = -1, y = 6, ey = -4, info = UI.TextArea {
textColor = colors.yellow, x = 2, ex = -2, y = 8, ey = -4,
marginLeft = 0, textColor = colors.yellow,
marginRight = 0, marginLeft = 0,
value = [[The Milo turtle must connect to a manipulator with a ]] .. marginRight = 0,
[[bound introspection module. The neural interface must ]] .. value = [[The Milo turtle must connect to a manipulator with a ]] ..
[[also have an introspection module.]], [[bound introspection module. The neural interface must ]] ..
}, [[also have an introspection module.]],
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
backgroundColor = colors.cyan, backgroundColor = 'primary',
}, },
} }

View File

@@ -14,7 +14,6 @@ end
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Speaker', title = 'Speaker',
index = 2, index = 2,
backgroundColor = colors.cyan,
[1] = UI.Text { [1] = UI.Text {
x = 2, y = 2, x = 2, y = 2,
textColor = colors.yellow, textColor = colors.yellow,
@@ -39,7 +38,7 @@ local wizardPage = UI.WizardPage {
function wizardPage:setNode(node) function wizardPage:setNode(node)
self.form:setValues(node) self.form:setValues(node)
if not node.volume then if not node.volume then
self.form.volume = 1 self.form.volume.value = 1
end end
end end

View File

@@ -18,7 +18,6 @@ Right-clicking on the activity monitor will reset the totals.]]
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Status Monitor', title = 'Status Monitor',
index = 2, index = 2,
backgroundColor = colors.cyan,
[1] = UI.TextArea { [1] = UI.TextArea {
x = 2, ex = -2, y = 2, ey = 6, x = 2, ex = -2, y = 2, ey = 6,
marginRight = 0, marginRight = 0,
@@ -86,6 +85,7 @@ local function createPage(node)
[1] = UI.Tab { [1] = UI.Tab {
tabTitle = 'Overview', tabTitle = 'Overview',
backgroundColor = colors.black, backgroundColor = colors.black,
noFill = true,
onlineLabel = UI.Text { onlineLabel = UI.Text {
x = 2, y = 2, x = 2, y = 2,
value = 'Storage Status', value = 'Storage Status',
@@ -136,12 +136,14 @@ local function createPage(node)
}, },
[2] = UI.Tab { [2] = UI.Tab {
tabTitle = 'Stats', tabTitle = 'Stats',
noFill = true,
textArea = UI.TextArea { textArea = UI.TextArea {
y = 3, y = 3,
}, },
}, },
[3] = UI.Tab { [3] = UI.Tab {
tabTitle = 'Storage', tabTitle = 'Storage',
noFill = true,
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
y = 2, y = 2,
columns = { columns = {
@@ -156,6 +158,7 @@ local function createPage(node)
}, },
[4] = UI.Tab { [4] = UI.Tab {
tabTitle = 'Offline', tabTitle = 'Offline',
noFill = true,
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
y = 2, y = 2,
columns = { columns = {
@@ -166,12 +169,14 @@ local function createPage(node)
}, },
[5] = UI.Tab { [5] = UI.Tab {
tabTitle = 'Activity', tabTitle = 'Activity',
noFill = true,
term = UI.Embedded { term = UI.Embedded {
--visible = true, --visible = true,
}, },
}, },
[6] = UI.Tab { [6] = UI.Tab {
tabTitle = 'Tasks', tabTitle = 'Tasks',
noFill = true,
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
y = 2, y = 2,
values = context.tasks, values = context.tasks,

View File

@@ -7,7 +7,6 @@ local device = _G.device
local storageView = UI.WizardPage { local storageView = UI.WizardPage {
title = 'Storage Options - General', title = 'Storage Options - General',
index = 2, index = 2,
backgroundColor = colors.cyan,
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 1, ey = -2, x = 2, ex = -2, y = 1, ey = -2,
manualControls = true, manualControls = true,
@@ -15,14 +14,14 @@ local storageView = UI.WizardPage {
formLabel = 'Priority', formKey = 'priority', formLabel = 'Priority', formKey = 'priority',
help = 'Larger values get precedence', help = 'Larger values get precedence',
limit = 4, limit = 4,
validate = 'numeric', transform = 'number',
shadowText = 'Numeric priority', shadowText = 'Numeric priority',
}, },
[2] = UI.TextEntry { [2] = UI.TextEntry {
formLabel = 'Refresh', formKey = 'refreshInterval', formLabel = 'Refresh', formKey = 'refreshInterval',
shadowText = 'seconds between refresh', shadowText = 'seconds between refresh',
limit = 4, limit = 4,
validate = 'numeric', tranform = 'number',
help = 'Refresh periodically', help = 'Refresh periodically',
}, },
[3] = UI.TextArea { [3] = UI.TextArea {
@@ -62,7 +61,6 @@ UI:getPage('nodeWizard').wizard:add({ storageGeneral = storageView })
local lockView = UI.WizardPage { local lockView = UI.WizardPage {
title = 'Storage Options - Locking', title = 'Storage Options - Locking',
index = 3, index = 3,
backgroundColor = colors.cyan,
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 1, ey = 3, x = 2, ex = -2, y = 1, ey = 3,
manualControls = true, manualControls = true,

View File

@@ -12,7 +12,6 @@ local context = Milo:getContext()
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Transfer Inventory', title = 'Transfer Inventory',
index = 2, index = 2,
backgroundColor = colors.cyan,
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
y = 2, ey = -2, y = 2, ey = -2,
values = context.storage.nodes, values = context.storage.nodes,

View File

@@ -9,7 +9,6 @@ local device = _G.device
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Trashcan', title = 'Trashcan',
index = 2, index = 2,
backgroundColor = colors.cyan,
info = UI.TextArea { info = UI.TextArea {
x = 1, ex = -1, y = 2, ey = 4, x = 1, ex = -1, y = 2, ey = 4,
textColor = colors.yellow, textColor = colors.yellow,

View File

@@ -637,8 +637,7 @@ Event.addRoutine(function()
end) end)
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()
UI.term:reset()
turtle.reset() turtle.reset()

View File

@@ -121,7 +121,10 @@ function Process:new(args)
self.terminal = self.window self.terminal = self.window
self.container.canvas.parent = monitor.canvas self.container.canvas.parent = monitor.canvas
table.insert(monitor.canvas.layers, 1, self.container.canvas) if not monitor.canvas.children then
monitor.canvas.children = { }
end
table.insert(monitor.canvas.children, 1, self.container.canvas)
self.container.canvas:setVisible(true) self.container.canvas:setVisible(true)
--self.container.getSize = self.window.getSize --self.container.getSize = self.window.getSize

142
neural/Equipment.lua Normal file
View File

@@ -0,0 +1,142 @@
local Event = require('opus.event')
local itemDB = require('core.itemDB')
local neural = require('neural.interface')
local UI = require('opus.ui')
local Util = require('opus.util')
local device = _G.device
neural.assertModules({
'plethora:sensor',
'plethora:kinetic',
'plethora:introspection',
})
UI:configure('Equipment', ...)
local equipment = device.neuralInterface.getEquipment()
local slots = {
'primary',
'offhand',
'boots',
'leggings',
'chest',
'helmet',
}
local page = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Drop', event = 'drop' },
{ text = 'Suck', event = 'suck' },
},
},
grid = UI.Grid {
y = 2,
columns = {
{ heading = 'Slot', key = 'index', width = 7 },
{ heading = 'Name', key = 'displayName' },
{ heading = 'Count', key = 'count', width = 5, align = 'right' },
},
sortColumn = 'index',
accelerators = {
grid_select = 'show_detail',
},
getDisplayValues = function(_, row)
row = Util.shallowCopy(row)
if row.name then
local item = itemDB:get(
table.concat({ row.name, row.damage, row.nbtHash }, ':'),
function()
return equipment.getItemMeta(row.index)
end)
row.displayName = item.displayName
else
row.displayName = 'empty'
end
row.index = slots[row.index]
return row
end,
},
accelerators = {
[ 'control-q' ] = 'quit',
},
detail = UI.SlideOut {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Back', event = 'slide_hide' },
},
},
grid = UI.ScrollingGrid {
y = 2,
columns = {
{ heading = 'Name', key = 'name' },
{ heading = 'Value', key = 'value' },
},
sortColumn = 'name',
accelerators = {
grid_select = 'inspect',
},
},
show = function(self, slot)
local detail = equipment.getItemMeta(slot.index)
local t = { }
for k,v in pairs(detail) do
table.insert(t, {
name = k,
value = v,
})
end
self.grid:setValues(t)
self.grid:setIndex(1)
UI.SlideOut.show(self)
end,
},
enable = function(self)
self:refresh()
UI.Page.enable(self)
end,
refresh = function(self)
local t = { }
local list = equipment.list()
for i = 1, equipment.size() do
local v = list[i] or { }
v.index = i
table.insert(t, v)
end
self.grid:setValues(t)
self.grid:draw()
end,
eventHandler = function(self, event)
if event.type == 'quit' then
UI:quit()
elseif event.type == 'show_detail' then
if event.selected.name then
self.detail:show(event.selected)
end
elseif event.type == 'drop' then
local selected = self.grid:getSelected()
equipment.drop(selected.index)
self:refresh()
elseif event.type == 'suck' then
local selected = self.grid:getSelected()
equipment.suck(selected.index)
self:refresh()
end
UI.Page.eventHandler(self, event)
end,
}
Event.onInterval(1, function()
page:refresh()
page:sync()
end)
UI:setPage(page)
UI:start()
itemDB:flush()

View File

@@ -182,7 +182,7 @@ end
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'quit' then if event.type == 'quit' then
Event.exitPullEvents() UI:quit()
elseif event.type == 'scan' then elseif event.type == 'scan' then
self:scan() self:scan()
@@ -211,7 +211,7 @@ Event.onTimeout(0, function()
page:sync() page:sync()
end) end)
UI:pullEvents() UI:start()
if canvas then if canvas then
canvas:clear() canvas:clear()

View File

@@ -253,7 +253,7 @@ end
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'quit' then if event.type == 'quit' then
Event.exitPullEvents() UI:quit()
elseif event.type == 'tab_activate' then elseif event.type == 'tab_activate' then
config.activeTab = event.activated.tabTitle config.activeTab = event.activated.tabTitle
@@ -268,7 +268,7 @@ if config.activeTab then
end end
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()
if canvas then if canvas then
canvas:clear() canvas:clear()

View File

@@ -29,4 +29,10 @@
run = "ores.lua", run = "ores.lua",
requires = "neuralInterface", requires = "neuralInterface",
}, },
[ "7f2465ac7cefab2766e6ee0714647089df9364b0ff09858c84b21b8a436a845d" ] = {
title = "Equipment",
category = "Neural",
run = "Equipment",
requires = "neuralInterface",
}
} }

View File

@@ -1,6 +1,15 @@
--[[ --[[
Breed either cows or sheep. Changed to use a 2-high mob (smaller mobs may work ?)
Must be run on a mob with the same height. Updated due to entity.look working correctly now.
The mob looks head-on to the lever. Make sure the
lever is accessible by the mob.
Laser is now optional - if no laser, the mobs will be
punched (or provide a stick). Best mob may be a
skeleton (unlimited ammo).
Feeding hand has been changed to off-hand.
]] ]]
local Array = require('opus.array') local Array = require('opus.array')
@@ -21,80 +30,100 @@ local WALK_SPEED = 1.5
neural.assertModules({ neural.assertModules({
'plethora:sensor', 'plethora:sensor',
'plethora:scanner', 'plethora:scanner',
'plethora:laser', --'plethora:laser',
'plethora:kinetic', 'plethora:kinetic',
'plethora:introspection', 'plethora:introspection',
}) })
local caninimals = config.animals or { [ config.animal ] = true }
local animals = { }
for k in pairs(caninimals) do
animals[k] = { }
end
local fed = { } local fed = { }
local function resupply() local function resupply()
local slot = neural.getEquipment().list()[1] local slot = neural.getEquipment().list()[2]
if slot and slot.count > 32 then if slot and slot.count > 32 then
return return
end end
print('resupplying') print('resupplying')
for _ = 1, 2 do for _ = 1, 2 do
local dispenser = Map.find(neural.scan(), 'name', 'minecraft:dispenser') local dispenser = Map.find(neural.scan(), 'name', 'minecraft:lever')
if not dispenser then if not dispenser then
print('dispenser not found') print('dispenser not found')
break break
end end
if math.abs(dispenser.x) <= 1 and math.abs(dispenser.z) <= 1 then if math.abs(dispenser.x) <= 1.2 and math.abs(dispenser.z) <= 1.2 then
neural.lookAt(dispenser) neural.lookAt({ x = dispenser.x, y = dispenser.y, z = dispenser.z })
for _ = 1, 8 do for _ = 1, 8 do
neural.use(0, 'off') if not neural.use(0, 'off') then
break
end
os.sleep(.2) os.sleep(.2)
neural.getEquipment().suck(1, 64) neural.getEquipment().suck(2, 64)
end end
break break
else else
neural.walkTo({ x = dispenser.x, y = 0, z = dispenser.z }, WALK_SPEED) neural.walkTo({ x = dispenser.x, y = 0, z = dispenser.z }, WALK_SPEED, .5)
end end
end end
end end
local function breed(entity) local function breed(entity)
print('breeding') print('breeding ' .. entity.name)
entity.lastFed = os.clock()
fed[entity.id] = entity
neural.walkTo(entity, WALK_SPEED, 1) neural.walkTo(entity, WALK_SPEED, 1)
entity = neural.getMetaByID(entity.id) entity = neural.getMetaByID(entity.id)
if entity then if entity then
neural.lookAt(entity) neural.lookAt(entity)
neural.use(1) if neural.use(1, 'off') then
entity.lastFed = os.clock()
fed[entity.id] = entity
end
os.sleep(.1) os.sleep(.1)
end end
end end
local function kill(entity) local function kill(entity)
print('killing') print('killing ' .. entity.name)
neural.walkTo(entity, WALK_SPEED, 2.5) neural.walkTo(entity, WALK_SPEED, (neural.fire or neural.shoot) and 2.5 or .5)
entity = neural.getMetaByID(entity.id) entity = neural.getMetaByID(entity.id)
if entity then if entity then
neural.lookAt(entity) neural.lookAt(entity)
neural.fireAt({ x = entity.x, y = 0, z = entity.z }) if neural.fire or neural.shoot then
neural.shootAt(entity)
else
neural.swing()
end
Sound.play('entity.firework.launch') Sound.play('entity.firework.launch')
os.sleep(.2) os.sleep(.2)
end end
end end
local function getEntities() local function shuffle(tbl)
local sheep = Array.filter(neural.sense(), function(entity) for i = #tbl, 2, -1 do
if entity.name == 'Sheep' and entity.y > -.5 then local j = math.random(i)
return true tbl[i], tbl[j] = tbl[j], tbl[i]
end
end)
if #sheep > config.maxAdults then
return sheep
end end
return tbl
end
return Map.filter(neural.sense(), function(entity) local function getEntities()
if entity.name == config.animal and entity.y > -.5 then return shuffle(Array.filter(neural.sense(), function(entity)
return true if animals[entity.name] then
if not animals[entity.name].height then
entity = neural.getMetaByID(entity.id)
if entity and not entity.isChild and entity.motionX == 0 and entity.motionZ == 0 then
animals[entity.name].height = entity.y
return true
end
elseif entity.y == animals[entity.name].height then
return true
end
end end
end) end))
end end
local function getHungry(entities) local function getHungry(entities)
@@ -105,13 +134,25 @@ local function getHungry(entities)
end end
end end
local function randomEntity(entities) local function getCount(entities, name)
local r = math.random(1, Map.size(entities)) local c = 0
local i = 1
for _, v in pairs(entities) do for _, v in pairs(entities) do
i = i + 1 if v.name == name then
if i > r then c = c + 1
return v end
end
print(name .. ' ' .. c)
return c
end
local function getKillable(entities)
print('map: ' .. Map.size(fed))
if Map.size(fed) > 1000 then
fed = { }
end
for name in pairs(animals) do
if getCount(entities, name) > config.maxAdults then
return Array.find(entities, 'name', name)
end end
end end
end end
@@ -120,9 +161,10 @@ while true do
resupply() resupply()
local entities = getEntities() local entities = getEntities()
local killable = getKillable(entities)
if Map.size(entities) > config.maxAdults then if killable then
kill(randomEntity(entities)) kill(killable)
else else
local entity = getHungry(entities) local entity = getHungry(entities)
if entity then if entity then

View File

@@ -5,7 +5,9 @@
-- Updated to use new(ish) canvas3d -- Updated to use new(ish) canvas3d
local gps = _G.gps local Config = require('opus.config')
local GPS = require("opus.gps")
local keys = _G.keys local keys = _G.keys
local os = _G.os local os = _G.os
local parallel = _G.parallel local parallel = _G.parallel
@@ -33,17 +35,10 @@ end
local BLOCK_SIZE = .5 local BLOCK_SIZE = .5
local function getPoint() local function getPoint()
local pt = { gps.locate() } return GPS.locate()
if pt[1] then
return {
x = pt[1],
y = pt[2],
z = pt[3],
}
end
end end
local targets = { local targets = Config.load('ores', {
["minecraft:emerald_ore"] = { "minecraft:emerald_ore", 0 }, ["minecraft:emerald_ore"] = { "minecraft:emerald_ore", 0 },
["minecraft:diamond_ore"] = { "minecraft:diamond_ore", 0 }, ["minecraft:diamond_ore"] = { "minecraft:diamond_ore", 0 },
["minecraft:gold_ore"] = { "minecraft:gold_ore", 0 }, ["minecraft:gold_ore"] = { "minecraft:gold_ore", 0 },
@@ -54,7 +49,8 @@ local targets = {
["minecraft:coal_ore"] = { "minecraft:coal_ore", 0 }, ["minecraft:coal_ore"] = { "minecraft:coal_ore", 0 },
["minecraft:quartz_ore"] = { "minecraft:quartz_ore", 0 }, ["minecraft:quartz_ore"] = { "minecraft:quartz_ore", 0 },
["minecraft:glowstone"] = { "minecraft:glowstone", 0 }, ["minecraft:glowstone"] = { "minecraft:glowstone", 0 },
} })
local projecting = { } local projecting = { }
local offset = getPoint() or showRequirements('GPS') local offset = getPoint() or showRequirements('GPS')
local canvas = modules.canvas3d().create({ local canvas = modules.canvas3d().create({
@@ -85,7 +81,7 @@ local function update()
local blocks = { } local blocks = { }
for _, b in pairs(scanned) do for _, b in pairs(scanned) do
if targets[b.name] then if targets[b.name..(b.metadata ~= 0 and ":"..b.metadata or "")] then
-- track block's world position -- track block's world position
b.id = table.concat({ b.id = table.concat({
math.floor(pos.x + b.x), math.floor(pos.x + b.x),
@@ -98,7 +94,8 @@ local function update()
for _, b in pairs(blocks) do for _, b in pairs(blocks) do
if not projecting[b.id] then if not projecting[b.id] then
projecting[b.id] = b projecting[b.id] = b
local target = targets[b.name]
local target = targets[b.name..(b.metadata ~= 0 and ":"..b.metadata or "")]
local x = b.x - math.floor(offset.x) + math.floor(pos.x) local x = b.x - math.floor(offset.x) + math.floor(pos.x)
local y = b.y - math.floor(offset.y) + math.floor(pos.y) local y = b.y - math.floor(offset.y) + math.floor(pos.y)

View File

@@ -1,8 +1,9 @@
{ {
[ 'builder' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/builder/.package',
[ 'cash' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/cash/.package',
[ 'ccemux' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/ccemux/.package',
[ 'common' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/common/.package', [ 'common' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/common/.package',
[ 'core' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/core/.package', [ 'core' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/core/.package',
[ 'builder' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/builder/.package',
[ 'ccemux' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/ccemux/.package',
[ 'farms' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/farms/.package', [ 'farms' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/farms/.package',
-- [ 'forestry' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/forestry/.package', -- [ 'forestry' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/forestry/.package',
[ 'games' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/games/.package', [ 'games' ] = 'https://raw.githubusercontent.com/kepler155c/opus-apps/develop-1.8/games/.package',

View File

@@ -1,6 +1,6 @@
{ {
title = 'Recipe books for crafting programs', title = 'Recipe books for crafting programs',
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/recipeBook', repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/recipeBook',
description = [[ WIP ]], description = [[Recipe book manager for Milo and programs that utilize crafting]],
license = 'MIT', license = 'MIT',
} }

View File

@@ -60,37 +60,37 @@ local page = UI.Page {
sortColumn = 'name', sortColumn = 'name',
autospace = true, autospace = true,
}, },
add = UI.SlideOut { add = UI.SlideOut {
backgroundColor = colors.cyan, height = 9, y = -9,
titleBar = UI.TitleBar { titleBar = UI.TitleBar {
title = 'Add a new book', title = 'Add a new book',
}, },
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 2, ey = -1, y = 2,
[1] = UI.TextEntry { [1] = UI.TextEntry {
formLabel = 'Name', formKey = 'name', formLabel = 'Name', formKey = 'name',
shadowText = 'Friendly name', shadowText = 'Friendly name',
limit = 64, limit = 64,
required = true, required = true,
}, },
[2] = UI.TextEntry { [2] = UI.TextEntry {
formLabel = 'Version', formKey = 'version', formLabel = 'Version', formKey = 'version',
shadowText = 'Mod version', shadowText = 'Mod version',
limit = 10, limit = 10,
}, },
[3] = UI.TextEntry { [3] = UI.TextEntry {
formLabel = 'URL', formKey = 'url', formLabel = 'URL', formKey = 'url',
shadowText = 'URL for recipes', shadowText = 'URL for recipes',
limit = 128, limit = 128,
required = true, required = true,
}, },
[4] = UI.TextEntry { [4] = UI.TextEntry {
formLabel = 'File name', formKey = 'localName', formLabel = 'File name', formKey = 'localName',
shadowText = 'Short name for saving file', shadowText = 'Short name for saving file',
limit = 20, limit = 20,
required = true, required = true,
}, },
}, },
}, },
notification = UI.Notification { }, notification = UI.Notification { },
} }
@@ -100,11 +100,10 @@ function page.info:draw()
self:clear() self:clear()
if book then if book then
self:setCursorPos(1, 1)
self:print( self:print(
string.format('Name: %s%s%s\n', Ansi.yellow, book.name, Ansi.reset)) string.format('Name: %s%s%s\nVersion: %s%s%s\n',
self:print( Ansi.yellow, book.name, Ansi.reset,
string.format('Version: %s%s%s\n', Ansi.yellow, book.version, Ansi.reset)) Ansi.yellow, book.version, Ansi.reset))
self.button.text = book.enabled and 'Disable' or 'Enable' self.button.text = book.enabled and 'Disable' or 'Enable'
self.button:draw() self.button:draw()
@@ -156,8 +155,8 @@ function page:eventHandler(event)
self.grid:draw() self.grid:draw()
elseif event.type == 'add_book' then elseif event.type == 'add_book' then
self.add.form:setValues({ }) self.add.form:setValues({ })
self.add:show() self.add:show()
elseif event.type == 'form_complete' then elseif event.type == 'form_complete' then
self.add:hide() self.add:hide()
@@ -166,18 +165,18 @@ function page:eventHandler(event)
self.grid:setValues(getRecipeBooks()) self.grid:setValues(getRecipeBooks())
self.grid:draw() self.grid:draw()
elseif event.type == 'form_cancel' then elseif event.type == 'form_cancel' then
self.add:hide() self.add:hide()
elseif event.type == 'grid_focus_row' then elseif event.type == 'grid_focus_row' then
self.info:draw() self.info:draw()
elseif event.type == 'quit' then elseif event.type == 'quit' then
UI:exitPullEvents() UI:quit()
end end
UI.Page.eventHandler(self, event) UI.Page.eventHandler(self, event)
end end
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()

View File

@@ -11,7 +11,7 @@ if not multishell then
end end
local config = Config.load('saver', { local config = Config.load('saver', {
enabled = true, enabled = false,
timeout = 60, timeout = 60,
random = true, random = true,
specific = nil, specific = nil,

View File

@@ -6,23 +6,26 @@ local config = Config.load('saver', {
timeout = 60, timeout = 60,
}) })
local tab = UI.Tab { return UI.Tab {
tabTitle = 'Screen Saver', tabTitle = 'Screen Saver',
description = 'Screen saver', description = 'Screen saver',
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 5,
},
label1 = UI.Text { label1 = UI.Text {
x = 2, y = 3, x = 3, y = 3,
value = 'Enabled', value = 'Enabled',
}, },
checkbox = UI.Checkbox { checkbox = UI.Checkbox {
x = 20, y = 3, x = 21, y = 3,
value = config.enabled value = config.enabled
}, },
label2 = UI.Text { label2 = UI.Text {
x = 2, y = 4, x = 3, y = 4,
value = 'Timeout', value = 'Timeout',
}, },
timeout = UI.TextEntry { timeout = UI.TextEntry {
x = 20, y = 4, width = 6, x = 21, y = 4, width = 6,
limit = 4, limit = 4,
transform = 'number', transform = 'number',
value = config.timeout, value = config.timeout,
@@ -31,24 +34,25 @@ local tab = UI.Tab {
}, },
}, },
button = UI.Button { button = UI.Button {
x = 20, y = 6, x = -8, ex = -2, y = -2,
text = 'Update', text = 'Apply',
event = 'update', event = 'update',
}, },
eventHandler = function(self, event)
if event.type =='checkbox_change' then
config.enabled = not not event.checked
elseif event.type == 'update' then
if self.timeout.value then
config.timeout = self.timeout.value
Config.update('saver', config)
self:emit({ type = 'success_message', message = 'Settings updated' })
os.queueEvent('config_update', 'saver', config)
else
self:emit({ type = 'error_message', message = 'Invalid timeout' })
end
end
return UI.Tab.eventHandler(self, event)
end,
} }
function tab:eventHandler(event)
if event.type =='checkbox_change' then
config.enabled = not not event.checked
elseif event.type == 'update' then
config.timeout = self.timeout.value
Config.update('saver', config)
self:emit({ type = 'success_message', message = 'Settings updated' })
os.queueEvent('config_update', 'saver', config)
end
return UI.Tab.eventHandler(self, event)
end
return tab

View File

@@ -49,7 +49,7 @@ local function buildLockScreen()
#self.pass.value > 0 and #self.pass.value > 0 and
Security.verifyPassword(SHA.compute(self.pass.value)) then Security.verifyPassword(SHA.compute(self.pass.value)) then
UI:exitPullEvents() -- valid UI:quit() -- valid
else else
self.notification:error('Invalid password', math.max(counter, 2)) self.notification:error('Invalid password', math.max(counter, 2))
self:sync() self:sync()
@@ -66,7 +66,7 @@ local function buildLockScreen()
Event.onTerminate(function() return false end) Event.onTerminate(function() return false end)
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()
-- restart lock timer -- restart lock timer
timer = os.startTimer(config.timeout) timer = os.startTimer(config.timeout)

View File

@@ -9,20 +9,23 @@ local config = Config.load('secure', {
local tab = UI.Tab { local tab = UI.Tab {
tabTitle = 'Secure', tabTitle = 'Secure',
description = 'Secure options', description = 'Secure options',
[1] = UI.Window {
x = 2, y = 2, ex = -2, ey = 5,
},
label1 = UI.Text { label1 = UI.Text {
x = 2, y = 3, x = 3, y = 3,
value = 'Screen Locking', value = 'Screen Locking',
}, },
checkbox = UI.Checkbox { checkbox = UI.Checkbox {
x = 20, y = 3, x = 21, y = 3,
value = config.enabled value = config.enabled
}, },
label2 = UI.Text { label2 = UI.Text {
x = 2, y = 4, x = 3, y = 4,
value = 'Lock timeout', value = 'Lock timeout',
}, },
timeout = UI.TextEntry { timeout = UI.TextEntry {
x = 20, y = 4, width = 6, x = 21, y = 4, width = 6,
limit = 4, limit = 4,
transform = 'number', transform = 'number',
value = config.timeout, value = config.timeout,
@@ -31,8 +34,8 @@ local tab = UI.Tab {
}, },
}, },
button = UI.Button { button = UI.Button {
x = 20, y = 6, x = -8, ex = -2, y = -2,
text = 'Update', text = 'Apply',
event = 'update', event = 'update',
}, },
} }
@@ -42,11 +45,15 @@ function tab:eventHandler(event)
config.enabled = not not event.checked config.enabled = not not event.checked
elseif event.type == 'update' then elseif event.type == 'update' then
config.timeout = self.timeout.value if self.timeout.value then
Config.update('secure', config) config.timeout = self.timeout.value
Config.update('secure', config)
self:emit({ type = 'success_message', message = 'Settings updated' }) self:emit({ type = 'success_message', message = 'Settings updated' })
os.queueEvent('config_update', 'secure', config) os.queueEvent('config_update', 'secure', config)
else
self:emit({ type = 'error_message', message = 'Invalid timeout' })
end
end end
return UI.Tab.eventHandler(self, event) return UI.Tab.eventHandler(self, event)
end end

View File

@@ -1,4 +1,7 @@
{ {
required = {
'milo',
},
title = 'Switchcraft basic shop', title = 'Switchcraft basic shop',
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/swshop', repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/swshop',
description = 'Modification of the k store by Lemmmy\nRun installPlugin.lua after install', description = 'Modification of the k store by Lemmmy\nRun installPlugin.lua after install',

View File

@@ -141,7 +141,7 @@ end
function page.grid:getDisplayValues(row) function page.grid:getDisplayValues(row)
row = Util.shallowCopy(row) row = Util.shallowCopy(row)
local x = row.recipient local x = row.recipient
row.from = x and x:match('(%w+)@') or row.from row.from = x and x:match('(.+)@') or row.from
return row return row
end end
@@ -189,4 +189,4 @@ end)
page.grid:loadTransactions() page.grid:loadTransactions()
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:start()

25
swshop/help/swshop Normal file
View File

@@ -0,0 +1,25 @@
An item shop software using Krist as its currency.
Requirements
============
* Advanced Turtle
* Chests (any type)
* Milo system
Installation
============
> pastebin run uzghlbnc
> package install swshop
> reboot
Setup
=====
From the shell, run the 'installPlugin.lua' once to install the shop component into your Milo installation.
From Milo, open the setup page and find the monitor you wish to use in the list.
Choose the monitor's type to be 'Store Front', and configure your domain and your wallet's key.
Usage
=====
Setup prices by right-clicking on the desired item and going on the 'Shops' tab.

View File

@@ -9,7 +9,6 @@ local os = _G.os
local wizardPage = UI.WizardPage { local wizardPage = UI.WizardPage {
title = 'Store Front', title = 'Store Front',
index = 2, index = 2,
backgroundColor = colors.cyan,
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 1, ey = -2, x = 2, ex = -2, y = 1, ey = -2,
manualControls = true, manualControls = true,
@@ -33,8 +32,22 @@ local wizardPage = UI.WizardPage {
limit = 64, limit = 64,
}, },
[4] = UI.Chooser { [4] = UI.Chooser {
formLabel = 'RS Signal', formKey = 'rsSide', formIndex = 5,
width = 10,
nochoice = 'Top',
choices = {
{name = 'Bottom', value = 'bottom'},
{name = 'Top', value = 'top'},
{name = 'Back', value = 'back'},
{name = 'Front', value = 'front'},
{name = 'Right', value = 'right'},
{name = 'Left', value = 'left'},
},
required = true,
},
[5] = UI.Chooser {
width = 9, width = 9,
formIndex = 5, formIndex = 6,
formLabel = 'Font Size', formKey = 'textScale', formLabel = 'Font Size', formKey = 'textScale',
nochoice = 'Small', nochoice = 'Small',
choices = { choices = {
@@ -76,7 +89,6 @@ end
local passwordPage = UI.WizardPage { local passwordPage = UI.WizardPage {
title = 'Krist Settings', title = 'Krist Settings',
index = 3, index = 3,
backgroundColor = colors.cyan,
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 1, ey = -2, x = 2, ex = -2, y = 1, ey = -2,
manualControls = true, manualControls = true,
@@ -98,7 +110,7 @@ local passwordPage = UI.WizardPage {
preview = UI.TextEntry { preview = UI.TextEntry {
formIndex = 4, formIndex = 4,
formLabel = 'Using address', formKey = 'address', formLabel = 'Using address', formKey = 'address',
backgroundColor = colors.cyan, backgroundColor = 'primary',
textColor = colors.yellow, textColor = colors.yellow,
inactive = true, inactive = true,
}, },
@@ -106,7 +118,7 @@ local passwordPage = UI.WizardPage {
} }
local function makeAddress(text, isPrivateKey) local function makeAddress(text, isPrivateKey)
local privKey = text local privKey = text or ''
if not isPrivateKey then if not isPrivateKey then
privKey = Krist.toKristWalletFormat(privKey) privKey = Krist.toKristWalletFormat(privKey)
end end
@@ -116,7 +128,7 @@ end
function passwordPage.form:eventHandler(event) function passwordPage.form:eventHandler(event)
if (event.type == 'text_change' and event.element.pass) or if (event.type == 'text_change' and event.element.pass) or
(event.type == 'checkbox_change' and event.element.ispkey) then (event.type == 'checkbox_change' and event.element.ispkey) then
self.passEntry.shadowText = self.pkeyCheck.value and 'Private key' or 'Password' self.passEntry.shadowText = self.pkeyCheck.value and 'Private key' or 'Password'
self.preview.value = makeAddress(self.passEntry.value, self.pkeyCheck.value) self.preview.value = makeAddress(self.passEntry.value, self.pkeyCheck.value)
self:draw() self:draw()
end end

View File

@@ -10,7 +10,7 @@ local shopTab = UI.Tab {
tabTitle = 'Store', tabTitle = 'Store',
index = 2, index = 2,
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 1, ey = -2, x = 2, ex = -2, y = 2, ey = -2,
manualControls = true, manualControls = true,
[1] = UI.TextEntry { [1] = UI.TextEntry {
formLabel = 'Name', formKey = 'name', formLabel = 'Name', formKey = 'name',

View File

@@ -19,7 +19,7 @@ local textutils = _G.textutils
local chat = device['plethora:chat'] local chat = device['plethora:chat']
local storage = Config.load('storage') local storage = Config.load('storage')
rs.setOutput('top', false) Util.each(rs.getSides(), function(side) rs.setOutput(side, false) end)
r.init(jua) r.init(jua)
w.init(jua) w.init(jua)
@@ -29,9 +29,10 @@ local node = ({ ... })[1] or error('Node name is required')
local config = storage[node] local config = storage[node]
local privatekey = config.isPrivateKey and config.password or Krist.toKristWalletFormat(config.password) local privatekey = config.isPrivateKey and config.password or Krist.toKristWalletFormat(config.password)
local address = Krist.makev2address(privatekey) local address = Krist.makev2address(privatekey)
local rsSide = config.rsSide or 'top'
jua.on("terminate", function() jua.on("terminate", function()
rs.setOutput('top', false) rs.setOutput(rsSide, false)
jua.stop() jua.stop()
_G.printError("Terminated") _G.printError("Terminated")
end) end)
@@ -44,7 +45,7 @@ local function getItemDetails(item)
t = textutils.unserialize(t) t = textutils.unserialize(t)
for key, v in pairs(t) do for key, v in pairs(t) do
if v.name == item then if v.name == item then
return key, v.price return key, tonumber(v.price)
end end
end end
end end
@@ -144,7 +145,7 @@ local function connect()
assert(success, "Failed to get websocket URL") assert(success, "Failed to get websocket URL")
print("Connected to websocket.") print("Connected to websocket.")
rs.setOutput('top', true) rs.setOutput(rsSide, true)
success = await(ws.subscribe, "ownTransactions", function(data) success = await(ws.subscribe, "ownTransactions", function(data)
local transaction = data.transaction local transaction = data.transaction
@@ -160,7 +161,7 @@ local s, m = pcall(function()
end) end)
end) end)
rs.setOutput('top', false) rs.setOutput(rsSide, false)
if not s then if not s then
error(m, 2) error(m, 2)
end end

View File

@@ -391,8 +391,9 @@ end
if type(turtle.getFuelLevel()) ~= 'number' then if type(turtle.getFuelLevel()) ~= 'number' then
-- Support unlimited fuel -- Support unlimited fuel
function turtle.getFuelLevel() function turtle.getFuelLevel()
return 100000 return math.huge
end end
turtle.getFuelLimit = turtle.getFuelLevel
end end
-- override to optionally specify a fuel -- override to optionally specify a fuel