Forms - dialogs
This commit is contained in:
60
apps/Lua.lua
60
apps/Lua.lua
@@ -30,10 +30,11 @@ local page = UI.Page({
|
||||
backgroundFocusColor = colors.black,
|
||||
limit = 256,
|
||||
accelerators = {
|
||||
enter = 'command_enter',
|
||||
up = 'history_back',
|
||||
down = 'history_forward',
|
||||
mouse_rightclick = 'clear_prompt',
|
||||
enter = 'command_enter',
|
||||
up = 'history_back',
|
||||
down = 'history_forward',
|
||||
mouse_rightclick = 'clear_prompt',
|
||||
[ 'control-space' ] = 'autocomplete',
|
||||
},
|
||||
}),
|
||||
grid = UI.ScrollingGrid({
|
||||
@@ -72,20 +73,65 @@ function page:enable()
|
||||
end
|
||||
end
|
||||
|
||||
function autocomplete(env, oLine, x)
|
||||
|
||||
local sLine = oLine:sub(1, x)
|
||||
local nStartPos = sLine:find("[a-zA-Z0-9_%.]+$")
|
||||
if nStartPos then
|
||||
sLine = sLine:sub(nStartPos)
|
||||
end
|
||||
|
||||
if #sLine > 0 then
|
||||
local results = textutils.complete(sLine, env)
|
||||
|
||||
if #results == 0 then
|
||||
-- setError('No completions available')
|
||||
|
||||
elseif #results == 1 then
|
||||
return Util.insertString(oLine, results[1], x + 1)
|
||||
|
||||
elseif #results > 1 then
|
||||
local prefix = results[1]
|
||||
for n = 1, #results do
|
||||
local result = results[n]
|
||||
while #prefix > 0 do
|
||||
if result:find(prefix, 1, true) == 1 then
|
||||
break
|
||||
end
|
||||
prefix = prefix:sub(1, #prefix - 1)
|
||||
end
|
||||
end
|
||||
if #prefix > 0 then
|
||||
return Util.insertString(oLine, prefix, x + 1)
|
||||
else
|
||||
-- setStatus('Too many results')
|
||||
end
|
||||
end
|
||||
end
|
||||
return oLine
|
||||
end
|
||||
|
||||
function page:eventHandler(event)
|
||||
|
||||
if event.type == 'global' then
|
||||
page:setPrompt('', true)
|
||||
self:setPrompt('', true)
|
||||
self:executeStatement('getfenv(0)')
|
||||
command = nil
|
||||
|
||||
elseif event.type == 'local' then
|
||||
page:setPrompt('', true)
|
||||
self:setPrompt('', true)
|
||||
self:executeStatement('getfenv(1)')
|
||||
command = nil
|
||||
|
||||
elseif event.type == 'autocomplete' then
|
||||
local sz = #self.prompt.value
|
||||
local pos = self.prompt.pos
|
||||
self:setPrompt(autocomplete(sandboxEnv, self.prompt.value, self.prompt.pos))
|
||||
self.prompt:setPosition(pos + #self.prompt.value - sz)
|
||||
self.prompt:updateCursor()
|
||||
|
||||
elseif event.type == 'device' then
|
||||
page:setPrompt('device', true)
|
||||
self:setPrompt('device', true)
|
||||
self:executeStatement('device')
|
||||
|
||||
elseif event.type == 'history_back' then
|
||||
|
||||
@@ -121,14 +121,14 @@ function page.grid:draw()
|
||||
end
|
||||
end
|
||||
|
||||
function updateComputers()
|
||||
Event.addThread(function()
|
||||
while true do
|
||||
page.grid:update()
|
||||
page.grid:draw()
|
||||
page:sync()
|
||||
os.sleep(1)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Event.addHandler('device_attach', function(h, deviceName)
|
||||
if deviceName == 'wireless_modem' then
|
||||
@@ -149,5 +149,5 @@ if not device.wireless_modem then
|
||||
end
|
||||
|
||||
UI:setPage(page)
|
||||
Event.pullEvents(updateComputers)
|
||||
Event.pullEvents()
|
||||
UI.term:reset()
|
||||
|
||||
@@ -332,76 +332,64 @@ end
|
||||
|
||||
local formWidth = math.max(UI.term.width - 14, 26)
|
||||
|
||||
local editor = UI.Page {
|
||||
backgroundColor = colors.white,
|
||||
x = math.ceil((UI.term.width - formWidth) / 2) + 1,
|
||||
y = math.ceil((UI.term.height - 11) / 2) + 1,
|
||||
z = 2,
|
||||
local editor = UI.Dialog {
|
||||
height = 11,
|
||||
width = formWidth,
|
||||
titleBar = UI.TitleBar {
|
||||
title = 'Edit application',
|
||||
},
|
||||
inset = UI.Window {
|
||||
x = 2,
|
||||
y = 3,
|
||||
rex = -2,
|
||||
rey = -3,
|
||||
form = UI.Form {
|
||||
textColor = colors.black,
|
||||
fields = {
|
||||
{ label = 'Title', key = 'title', width = formWidth - 11, limit = 11, display = UI.Form.D.entry,
|
||||
help = 'Application title' },
|
||||
{ label = 'Run', key = 'run', width = formWidth - 11, limit = 100, display = UI.Form.D.entry,
|
||||
help = 'Full path to application' },
|
||||
{ label = 'Category', key = 'category', width = formWidth - 11, limit = 11, display = UI.Form.D.entry,
|
||||
help = 'Category of application' },
|
||||
{ text = 'Icon', event = 'loadIcon', display = UI.Form.D.button,
|
||||
x = 10, y = 5, textColor = colors.white, help = 'Select icon' },
|
||||
{ text = 'Ok', event = 'accept', display = UI.Form.D.button,
|
||||
x = formWidth - 14, y = 7, textColor = colors.white },
|
||||
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
||||
x = formWidth - 9, y = 7, textColor = colors.white },
|
||||
},
|
||||
labelWidth = 8,
|
||||
image = UI.NftImage {
|
||||
y = 5,
|
||||
x = 1,
|
||||
height = 3,
|
||||
width = 8,
|
||||
},
|
||||
title = 'Edit application',
|
||||
form = UI.Form {
|
||||
y = 2,
|
||||
height = 9,
|
||||
title = UI.TextEntry {
|
||||
formLabel = 'Title', formKey = 'title', limit = 11, help = 'Application title',
|
||||
required = true,
|
||||
},
|
||||
run = UI.TextEntry {
|
||||
formLabel = 'Run', formKey = 'run', limit = 100, help = 'Full path to application',
|
||||
required = true,
|
||||
},
|
||||
category = UI.TextEntry {
|
||||
formLabel = 'Category', formKey = 'category', limit = 11, help = 'Category of application',
|
||||
required = true,
|
||||
},
|
||||
loadIcon = UI.Button {
|
||||
x = 11, y = 6,
|
||||
text = 'Icon', event = 'loadIcon', help = 'Select icon'
|
||||
},
|
||||
image = UI.NftImage {
|
||||
y = 6,
|
||||
x = 2,
|
||||
height = 3,
|
||||
width = 8,
|
||||
},
|
||||
},
|
||||
statusBar = UI.StatusBar(),
|
||||
notification = UI.Notification(),
|
||||
iconFile = '',
|
||||
}
|
||||
|
||||
function editor:enable(app)
|
||||
if app then
|
||||
self.original = app
|
||||
self.inset.form:setValues(Util.shallowCopy(app))
|
||||
self.form:setValues(app)
|
||||
|
||||
local icon
|
||||
if app.icon then
|
||||
icon = parseIcon(app.icon)
|
||||
end
|
||||
self.inset.form.image:setImage(icon)
|
||||
self.form.image:setImage(icon)
|
||||
end
|
||||
UI.Page.enable(self)
|
||||
self:focusFirst()
|
||||
end
|
||||
|
||||
function editor.inset.form.image:draw()
|
||||
function editor.form.image:draw()
|
||||
self:clear()
|
||||
UI.NftImage.draw(self)
|
||||
end
|
||||
|
||||
function editor:updateApplications(app, original)
|
||||
if original.run then
|
||||
local _,k = Util.find(applications, 'run', original.run)
|
||||
if k then
|
||||
function editor:updateApplications(app)
|
||||
for k,v in pairs(applications) do
|
||||
if v == app then
|
||||
applications[k] = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert(applications, app)
|
||||
@@ -410,7 +398,7 @@ end
|
||||
|
||||
function editor:eventHandler(event)
|
||||
|
||||
if event.type == 'cancel' then
|
||||
if event.type == 'form_cancel' or event.type == 'cancel' then
|
||||
UI:setPreviousPage()
|
||||
|
||||
elseif event.type == 'focus_change' then
|
||||
@@ -438,29 +426,26 @@ function editor:eventHandler(event)
|
||||
if not icon then
|
||||
error(m)
|
||||
end
|
||||
self.inset.form.values.icon = iconLines
|
||||
self.inset.form.image:setImage(icon)
|
||||
self.inset.form.image:draw()
|
||||
self.form.values.icon = iconLines
|
||||
self.form.image:setImage(icon)
|
||||
self.form.image:draw()
|
||||
end)
|
||||
if not s and m then
|
||||
local msg = m:gsub('.*: (.*)', '%1')
|
||||
self.notification:error(msg)
|
||||
page.notification:error(msg)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
elseif event.type == 'accept' then
|
||||
local values = self.inset.form.values
|
||||
if #values.run > 0 and #values.title > 0 and #values.category > 0 then
|
||||
UI:setPreviousPage()
|
||||
self:updateApplications(values, self.original)
|
||||
page:refresh()
|
||||
page:draw()
|
||||
else
|
||||
self.notification:error('Require fields missing')
|
||||
--self.statusBar:setStatus('Require fields missing')
|
||||
--self.statusBar:draw()
|
||||
end
|
||||
elseif event.type == 'form_invalid' then
|
||||
page.notification:error(event.message)
|
||||
|
||||
elseif event.type == 'form_complete' then
|
||||
local values = self.form.values
|
||||
UI:setPreviousPage()
|
||||
self:updateApplications(values)
|
||||
page:refresh()
|
||||
page:draw()
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
end
|
||||
|
||||
@@ -33,6 +33,12 @@ local clipboard = { size, internal }
|
||||
local searchPattern
|
||||
local undo = { chain = { }, pointer = 0 }
|
||||
|
||||
if _G.__CLIPBOARD then
|
||||
clipboard = _G.__CLIPBOARD
|
||||
else
|
||||
_G.__CLIPBOARD = clipboard
|
||||
end
|
||||
|
||||
local color = {
|
||||
textColor = '0',
|
||||
keywordColor = '4',
|
||||
|
||||
@@ -452,51 +452,54 @@ function watchResources(items)
|
||||
return itemList
|
||||
end
|
||||
|
||||
itemPage = UI.Page({
|
||||
itemPage = UI.Page {
|
||||
backgroundColor = colors.lightGray,
|
||||
titleBar = UI.TitleBar({
|
||||
titleBar = UI.TitleBar {
|
||||
title = 'Limit Resource',
|
||||
previousPage = true,
|
||||
event = 'form_cancel',
|
||||
backgroundColor = colors.green
|
||||
}),
|
||||
idField = UI.Text({
|
||||
x = 5,
|
||||
y = 3,
|
||||
width = UI.term.width - 10
|
||||
}),
|
||||
form = UI.Form({
|
||||
fields = {
|
||||
{ label = 'Min', key = 'low', width = 7, display = UI.Form.D.entry,
|
||||
help = 'Craft if below min' },
|
||||
{ label = 'Max', key = 'limit', width = 7, display = UI.Form.D.entry,
|
||||
validation = UI.Form.V.number, dataType = UI.Form.T.number,
|
||||
help = 'Eject if above max' },
|
||||
{ label = 'Autocraft', key = 'auto', width = 7, display = UI.Form.D.chooser,
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Craft until out of ingredients' },
|
||||
{ label = 'Ignore Dmg', key = 'ignore_dmg', width = 7, display = UI.Form.D.chooser,
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Ignore damage of item' },
|
||||
{ text = 'Accept', event = 'accept', display = UI.Form.D.button,
|
||||
x = 1, y = 6, width = 10 },
|
||||
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
||||
x = 21, y = 6, width = 10 },
|
||||
},
|
||||
idField = UI.Text {
|
||||
x = 5, y = 3, width = UI.term.width - 10,
|
||||
},
|
||||
form = UI.Form {
|
||||
x = 4, y = 4, height = 8, rex = -4,
|
||||
[1] = UI.TextEntry {
|
||||
width = 7,
|
||||
backgroundColor = colors.gray,
|
||||
backgroundFocusColor = colors.gray,
|
||||
formLabel = 'Min', formKey = 'low', help = 'Craft if below min'
|
||||
},
|
||||
labelWidth = 10,
|
||||
x = 5,
|
||||
y = 5,
|
||||
height = 6
|
||||
}),
|
||||
statusBar = UI.StatusBar()
|
||||
})
|
||||
[2] = UI.TextEntry {
|
||||
width = 7,
|
||||
backgroundColor = colors.gray,
|
||||
backgroundFocusColor = colors.gray,
|
||||
formLabel = 'Max', formKey = 'limit', help = 'Eject if above max'
|
||||
},
|
||||
[3] = UI.Chooser {
|
||||
width = 7,
|
||||
formLabel = 'Autocraft', formKey = 'auto',
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Craft until out of ingredients'
|
||||
},
|
||||
[4] = UI.Chooser {
|
||||
width = 7,
|
||||
formLabel = 'Ignore Dmg', formKey = 'ignore_dmg',
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Ignore damage of item'
|
||||
},
|
||||
},
|
||||
statusBar = UI.StatusBar { }
|
||||
}
|
||||
|
||||
function itemPage:enable()
|
||||
UI.Page.enable(self)
|
||||
@@ -504,12 +507,14 @@ function itemPage:enable()
|
||||
end
|
||||
|
||||
function itemPage:eventHandler(event)
|
||||
if event.type == 'cancel' then
|
||||
if event.type == 'form_cancel' then
|
||||
UI:setPreviousPage()
|
||||
|
||||
elseif event.type == 'focus_change' then
|
||||
self.statusBar:setStatus(event.focused.help)
|
||||
self.statusBar:draw()
|
||||
elseif event.type == 'accept' then
|
||||
|
||||
elseif event.type == 'form_complete' then
|
||||
local values = self.form.values
|
||||
local t = Util.readTable('resource.limits') or { }
|
||||
for k,v in pairs(t) do
|
||||
@@ -527,55 +532,52 @@ function itemPage:eventHandler(event)
|
||||
table.insert(t, filtered)
|
||||
Util.writeTable('resource.limits', t)
|
||||
UI:setPreviousPage()
|
||||
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
listingPage = UI.Page({
|
||||
menuBar = UI.MenuBar({
|
||||
listingPage = UI.Page {
|
||||
menuBar = UI.MenuBar {
|
||||
buttons = {
|
||||
{ text = 'Learn', event = 'learn' },
|
||||
{ text = 'Forget', event = 'forget' },
|
||||
},
|
||||
}),
|
||||
grid = UI.Grid({
|
||||
},
|
||||
grid = UI.Grid {
|
||||
y = 2, height = UI.term.height - 2,
|
||||
columns = {
|
||||
{ heading = 'Name', key = 'name' , width = 22 },
|
||||
{ heading = 'Qty', key = 'qty' , width = 5 },
|
||||
{ heading = 'Min', key = 'low' , width = 4 },
|
||||
{ heading = 'Max', key = 'limit', width = 4 },
|
||||
},
|
||||
y = 2,
|
||||
sortColumn = 'name',
|
||||
height = UI.term.height-2,
|
||||
}),
|
||||
statusBar = UI.StatusBar({
|
||||
},
|
||||
statusBar = UI.StatusBar {
|
||||
backgroundColor = colors.gray,
|
||||
width = UI.term.width,
|
||||
filterText = UI.Text({
|
||||
filterText = UI.Text {
|
||||
x = 2, width = 6,
|
||||
value = 'Filter',
|
||||
x = 2,
|
||||
width = 6,
|
||||
}),
|
||||
filter = UI.TextEntry({
|
||||
width = 19,
|
||||
},
|
||||
filter = UI.TextEntry {
|
||||
x = 9, width = 19,
|
||||
limit = 50,
|
||||
x = 9,
|
||||
}),
|
||||
refresh = UI.Button({
|
||||
},
|
||||
refresh = UI.Button {
|
||||
x = 31, width = 8,
|
||||
text = 'Refresh',
|
||||
event = 'refresh',
|
||||
x = 31,
|
||||
width = 8
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
accelerators = {
|
||||
r = 'refresh',
|
||||
q = 'quit',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function listingPage.grid:getRowTextColor(row, selected)
|
||||
if row.is_craftable then
|
||||
@@ -622,24 +624,26 @@ end
|
||||
function listingPage:eventHandler(event)
|
||||
if event.type == 'quit' then
|
||||
Event.exitPullEvents()
|
||||
|
||||
elseif event.type == 'grid_select' then
|
||||
local selected = event.selected
|
||||
itemPage.form:setValues(selected)
|
||||
itemPage.titleBar.title = selected.name
|
||||
itemPage.idField.value = selected.id
|
||||
UI:setPage('item')
|
||||
|
||||
elseif event.type == 'refresh' then
|
||||
self:refresh()
|
||||
self.grid:draw()
|
||||
|
||||
elseif event.type == 'learn' then
|
||||
if not duckAntenna then
|
||||
self.statusBar:timedStatus('Missing peripherals', 3)
|
||||
else
|
||||
UI:getPage('craft').form:setValues( { ignore_dmg = 'no' } )
|
||||
UI:setPage('craft')
|
||||
end
|
||||
elseif event.type == 'forget' then
|
||||
|
||||
elseif event.type == 'forget' then
|
||||
local item = self.grid:getSelected()
|
||||
if item then
|
||||
local recipes = Util.readTable('recipes') or { }
|
||||
@@ -673,6 +677,7 @@ function listingPage:eventHandler(event)
|
||||
self:applyFilter()
|
||||
self.grid:draw()
|
||||
self.statusBar.filter:focus()
|
||||
|
||||
else
|
||||
UI.Page.eventHandler(self, event)
|
||||
end
|
||||
@@ -747,7 +752,7 @@ local function filter(t, filter)
|
||||
end
|
||||
end
|
||||
|
||||
local function learnRecipe(page, ignore_dmg)
|
||||
local function learnRecipe(page)
|
||||
local t = Util.readTable('recipes') or { }
|
||||
local recipe = { }
|
||||
local ingredients = duckAntenna.getAllStacks(false) -- getTurtleInventory()
|
||||
@@ -773,7 +778,7 @@ local function learnRecipe(page, ignore_dmg)
|
||||
end
|
||||
end
|
||||
recipe.ingredients = ingredients
|
||||
recipe.ignore_dmg = 'no' -- ignore_dmg
|
||||
recipe.ignore_dmg = 'no'
|
||||
|
||||
t[key] = recipe
|
||||
|
||||
@@ -794,69 +799,52 @@ local function learnRecipe(page, ignore_dmg)
|
||||
end
|
||||
end
|
||||
|
||||
craftPage = UI.Page({
|
||||
x = 4,
|
||||
y = math.floor((UI.term.height - 8) / 2) + 1,
|
||||
height = 7,
|
||||
width = UI.term.width - 6,
|
||||
craftPage = UI.Dialog {
|
||||
height = 7, width = UI.term.width - 6,
|
||||
backgroundColor = colors.lightGray,
|
||||
titleBar = UI.TitleBar({
|
||||
titleBar = UI.TitleBar {
|
||||
title = 'Learn Recipe',
|
||||
previousPage = true,
|
||||
}),
|
||||
idField = UI.Text({
|
||||
},
|
||||
idField = UI.Text {
|
||||
x = 5,
|
||||
y = 3,
|
||||
width = UI.term.width - 10,
|
||||
value = 'Place recipe in turtle'
|
||||
}),
|
||||
form = UI.Form({
|
||||
fields = {
|
||||
--[[
|
||||
{ label = 'Ignore Damage', key = 'ignore_dmg', width = 7, display = UI.Form.D.chooser,
|
||||
nochoice = 'No',
|
||||
choices = {
|
||||
{ name = 'Yes', value = 'yes' },
|
||||
{ name = 'No', value = 'no' },
|
||||
},
|
||||
help = 'Ignore damage of ingredients' },
|
||||
--]]
|
||||
{ text = 'Accept', event = 'accept', display = UI.Form.D.button,
|
||||
x = 1, y = 1, width = 10 },
|
||||
{ text = 'Cancel', event = 'cancel', display = UI.Form.D.button,
|
||||
x = 16, y = 1, width = 10 },
|
||||
},
|
||||
labelWidth = 13,
|
||||
x = 5,
|
||||
y = 5,
|
||||
height = 2
|
||||
}),
|
||||
statusBar = UI.StatusBar({
|
||||
},
|
||||
accept = UI.Button {
|
||||
rx = -13, ry = -2,
|
||||
text = 'Ok', event = 'accept',
|
||||
},
|
||||
cancel = UI.Button {
|
||||
rx = -8, ry = -2,
|
||||
text = 'Cancel', event = 'cancel'
|
||||
},
|
||||
statusBar = UI.StatusBar {
|
||||
status = 'Crafting paused'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function craftPage:enable()
|
||||
craftingPaused = true
|
||||
self:focusFirst()
|
||||
UI.Page.enable(self)
|
||||
UI.Dialog.enable(self)
|
||||
end
|
||||
|
||||
function craftPage:disable()
|
||||
craftingPaused = false
|
||||
UI.Dialog.disable(self)
|
||||
end
|
||||
|
||||
function craftPage:eventHandler(event)
|
||||
if event.type == 'cancel' then
|
||||
UI:setPreviousPage()
|
||||
elseif event.type == 'accept' then
|
||||
local values = self.form.values
|
||||
|
||||
if learnRecipe(self, values.ignore_dmg) then
|
||||
if learnRecipe(self) then
|
||||
UI:setPreviousPage()
|
||||
end
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
return UI.Dialog.eventHandler(self, event)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user