local lib = starlit.mod.lib
function starlit.ui.setupForUser(user)
local function cmode(mode)
if user.actMode == mode then return {hue = 150, sat = 0, lum = .3} end
end
user.entity:set_inventory_formspec(starlit.ui.build {
kind = 'vert', mode = 'sw';
padding = .5, spacing = 0.1;
{kind = 'hztl';
{kind = 'contact', w=1.5,h=1.5, id = 'mode_nano',
img='starlit-ui-icon-nano.png', close=true, color = cmode'nano'};
{kind = 'contact', w=1.5,h=1.5, id = 'mode_weapon',
img='starlit-ui-icon-weapon.png', close=true, color = cmode'weapon'};
{kind = 'contact', w=1.5,h=1.5, id = 'mode_psi',
img='starlit-ui-icon-psi.png', close=true, color = cmode'psi'};
};
{kind = 'hztl';
{kind = 'contact', w=1.5,h=1.5, id = 'open_elements',
img='starlit-ui-icon-element.png'};
{kind = 'contact', w=1.5,h=1.5, id = 'open_suit',
img='starlit-item-suit.png^[hsl:200:-.7:0'};
{kind = 'contact', w=1.5,h=1.5, id = 'open_psi',
img='starlit-ui-icon-psi-cfg.png'};
{kind = 'contact', w=1.5,h=1.5, id = 'open_body',
img='starlit-ui-icon-self.png'};
};
{kind = 'list';
target = 'current_player', inv = 'main';
w = 6, h = 1, spacing = 0.1;
};
})
end
function starlit.ui.userMenuDispatch(user, fields)
local function setSuitMode(mode)
if user.actMode == mode then
user:actModeSet 'off'
else
user:actModeSet(mode)
end
end
local modes = { nano = true, psi = false, weapon = true }
for e,s in pairs(modes) do
if fields['mode_' .. e] then
if s and (user:naked() or user:getSuit():powerState() == 'off') then
user:suitSound 'starlit-error'
else
setSuitMode(e)
end
return true
end
end
if fields.open_elements then
user:openUI('starlit:user-menu', 'compiler')
return true
elseif fields.open_psi then
user:openUI('starlit:user-menu', 'psi')
return true
elseif fields.open_suit then
if not user:naked() then
user:openUI('starlit:user-menu', 'suit')
end
return true
elseif fields.open_body then
user:openUI('starlit:user-menu', 'body')
end
return false
end
local function listWrap(n, max)
local h = math.ceil(n / max)
local w = math.min(max, n)
return w, h
end
local function wrapMenu(w, h, rh, max, l)
local root = {kind = 'vert', w=w, h=h}
local bar
local function flush()
if bar and bar[1] then table.insert(root, bar) end
bar = {kind = 'hztl'}
end
flush()
for _, i in ipairs(l) do
local bw = w/max
if i.cfg then w = w - rh end
table.insert(bar, {
kind = i.img and 'contact' or 'button', close = i.close;
color = i.color;
fg = i.fg;
label = i.label;
img = i.img;
id = i.id;
w = bw, h = rh;
})
if i.cfg then
table.insert(bar, {
kind = 'button';
color = i.color;
fg = i.fg;
label = "CFG";
img = i.img;
id = i.id .. '_cfg';
w = rh, h = rh;
})
end
if bar[max] then flush() end
end
flush()
return root
end
local function abilityMenu(a)
-- select primary/secondary abilities or activate ritual abilities
local p = {kind = 'vert'}
for _, o in ipairs(a.order) do
local m = a.menu[o]
table.insert(p, {kind='hbar', fac=0.5, text=string.format("<b>%s</b>",m.label), w=a.w, h = .5})
table.insert(p, wrapMenu(a.w, a.h, 1.2, 2, m.opts))
end
return p
end
local function pptrMatch(a,b)
if a == nil or b == nil then return false end
return (a.chipID ~= nil and (a.chipID == b.chipID and a.pgmIndex == b.pgmIndex))
or (a.ref ~= nil and a.ref == b.ref)
end
starlit.interface.install(starlit.type.ui {
id = 'starlit:user-menu';
pages = {
compiler = {
setupState = function(state, user)
-- nanotech/suit software menu
local chips = user.entity:get_inventory():get_list 'starlit_suit_chips' -- FIXME need better subinv api
local sw = starlit.mod.electronics.chip.usableSoftware(chips)
state.suitSW = {}
local dedup = {}
for i, r in ipairs(sw) do if
r.sw.kind == 'suitPower'
then
if not dedup[r.sw] then
dedup[r.sw] = true
table.insert(state.suitSW, r)
end
end end
end;
handle = function(state, user, act)
if user:getSuit():powerState() == 'off' then return false end
local pgm, cfg
for k in next, act do
local id, mode = k:match('^suit_pgm_([0-9]+)_(.*)$')
if id then
id = tonumber(id)
if state.suitSW[id] then
pgm = state.suitSW[id]
cfg = mode == '_cfg'
break
end
end
end
if not pgm then return false end -- HAX
-- kind=active programs must be assigned to a command slot
-- kind=direct programs must open their UI
-- kind=passive programs must toggle on and off
local function suitCtx(pgm)
local chips = user.entity:get_inventory():get_list 'starlit_suit_chips'
local pgmctx = starlit.mod.electronics.chip.usableSoftware(chips, {pgm})[1]
return {
context = 'suit';
program = pgmctx;
}
end
if pgm.sw.powerKind == 'active' then
if cfg then
user:openUI(pgm.sw.ui, 'index', {
context = 'suit';
program = pgm;
})
return false
end
local ptr = {chipID = starlit.mod.electronics.chip.read(pgm.chip).uuid, pgmIndex = pgm.fd.inode}
local pnan = user.power.nano
if pnan.primary == nil then
pnan.primary = ptr
elseif pptrMatch(ptr, pnan.primary) then
pnan.primary = nil
elseif pptrMatch(ptr, pnan.secondary) then
pnan.secondary = nil
else
pnan.secondary = ptr
end
user:suitSound 'starlit-configure'
elseif pgm.sw.powerKind == 'direct' then
local ctx = suitCtx(pgm)
if pgm.sw.ui then
user:openUI(pgm.sw.ui, 'index', ctx)
return false
else
pgm.sw.run(user, ctx)
end
elseif pgm.sw.powerKind == 'passive' then
if cfg then
user:openUI(pgm.sw.ui, 'index', suitCtx(pgm))
return false
end
local addDisableRec = true
for i, e in ipairs(pgm.file.body.conf) do
if e.key == 'disable' and e.value == 'yes' then
addDisableRec = false
table.remove(pgm.file.body.conf, i)
break
elseif e.key == 'disable' and e.value == 'no' then
e.value = 'yes'
addDisableRec = false
break
end
end
if addDisableRec then
table.insert(pgm.file.body.conf, {key='disable',value='yes'})
end
-- update the chip *wince*
pgm.fd:write(pgm.file)
user.entity:get_inventory():set_stack('starlit_suit_chips',
pgm.chipSlot, pgm.chip)
user:reconfigureSuit()
user:suitSound 'starlit-configure'
end
return true, true
end;
render = function(state, user)
local suit = user:getSuit()
local swm
if user:getSuit():powerState() ~= 'off' then
swm = {
w = 8, h = 3;
order = {'active','ritual','pasv'};
menu = {
active = {
label = 'Nanoware';
opts = {};
};
ritual = {
label = 'Programs';
opts = {};
};
pasv = {
label = 'Passive';
opts = {};
};
};
}
for id, r in pairs(state.suitSW) do
local color = {hue=300,sat=0,lum=0}
local fg = nil
local close = nil
local tbl, cfg if r.sw.powerKind == 'active' then
tbl = swm.menu.active.opts
if r.sw.ui then cfg = true end
local pnan = user.power.nano
if pnan then
local ptr = {chipID = starlit.mod.electronics.chip.read(r.chip).uuid, pgmIndex = r.fd.inode}
if pptrMatch(ptr, pnan.primary) then
color.lum = 1
elseif pptrMatch(ptr, pnan.secondary) then
color.lum = 0.8
end
end
elseif r.sw.powerKind == 'direct' then
tbl = swm.menu.ritual.opts
if not r.sw.ui then
close = true
end
elseif r.sw.powerKind == 'passive' then
tbl = swm.menu.pasv.opts
if r.sw.ui then cfg = true end
for i, e in ipairs(r.file.body.conf) do
if e.key == 'disable' and e.value == 'yes' then
color.lum = -.2
fg = lib.color {hue=color.hue,sat=0.7,lum=0.7}
break
end
end
end
if tbl then table.insert(tbl, {
color = color, fg = fg;
label = r.sw.label or r.sw.name;
id = string.format('suit_pgm_%s_', id);
cfg = cfg, close = close;
}) end
end
end
local menu = { kind = 'vert', mode = 'sw', padding = 0.5 }
if swm then table.insert(menu, abilityMenu(swm)) end
local inv = user.entity:get_inventory()
--[[
local cans = inv:get_list 'starlit_suit_canisters'
if cans and next(cans) then for i, st in ipairs(cans) do
local id = string.format('starlit_canister_%u_elem', i)
local esz = inv:get_size(id)
if esz > 0 then
local eltW, eltH = listWrap(esz, 5)
table.insert(menu, {kind = 'hztl',
{kind = 'img', desc='Elements', img = 'starlit-ui-icon-element.png', w=1,h=1};
{kind = 'list', target = 'current_player', inv = id,
listContent = 'element', w = eltW, h = eltH, spacing = 0.1};
})
end
end end
]]
if #menu == 0 then
table.insert(menu, {
kind = 'img';
img = 'starlit-ui-alert.png';
w=2, h=2;
})
menu.padding = 1;
end
return starlit.ui.build(menu)
end;
};
psi = {
render = function(state, user)
return starlit.ui.build {
kind = 'vert', mode = 'sw';
padding = 0.5;
}
end;
};
body = {
render = function(state, user)
local barh = .75
local tb = {
kind = 'vert', mode = 'sw';
padding = 0.5,
{kind = 'hztl', padding = 0.25;
{kind = 'label', text = 'Name', w = 2, h = barh};
{kind = 'label', text = user.persona.name, w = 4, h = barh}};
}
local statBars = {'stamina', 'numina', 'nutrition', 'hydration', 'fatigue', 'morale', 'irradiation', 'illness'}
local function wrapElts(n, l)
local all = {kind='vert'}
local ct, row
local function flush()
if row then
table.insert(all, row)
end
row = {kind='hztl', spacing = 0.2}
ct = 0
end
flush()
for i, e in ipairs(l) do
ct = ct + 1
table.insert(row, e)
if ct >= n then flush() end
end
flush()
return all
end
local bars = {}
local function pushBar(s, amt, sv, min, max)
local st = string.format('%s / %s', s.desc(amt, true), s.desc(max))
table.insert(bars, {kind = 'hztl', padding = 0.25;
{kind = 'label', w=2, h=barh, text = lib.str.capitalize(s.name)};
{kind = 'hbar', w=4, h=barh, fac = sv, text = st, color=s.color};
})
end
do local hp, hpf = user:effectiveStat 'health'
local desc = {
name='health';
desc = function(hp) return tostring(hp) end;
color = {hue=10,sat=1,lum=.5};
}
pushBar(desc, hp, hpf, starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, 'health'))
end
do local ep, ex = user:suitCharge(), user:suitPowerCapacity()
local desc = {
name = 'power';
desc = function(j) return lib.math.siUI('J', j) end;
color = {hue=190,sat=1,lum=.5};
}
pushBar(desc, ep, ep/ex, 0, ex)
end
for idx, id in ipairs(statBars) do
local s = starlit.world.stats[id]
local amt, sv = user:effectiveStat(id)
local min, max = starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, id)
pushBar(s, amt, sv, min, max)
end
table.insert(tb, wrapElts(2, bars))
local abilities = {
maneuver = {};
direct = {};
passive = {};
}
state.abilityMap = {}
for i, a in pairs(user:species().abilities) do
local id = 'abl_'..a.id;
state.abilityMap[id] = a;
table.insert(abilities[a.powerKind], {
id = id;
label = a.name;
desc = a.desc;
-- img = a.img;
-- HACK
color = pptrMatch(user.power.maneuver, {ref=a}) and
{hue = 150, sat = 0, lum = .3} or nil;
});
end
for i, n in ipairs {'maneuver', 'direct', 'passive'} do
if next(abilities[n]) then
table.insert(tb, wrapMenu(6.25,4, 1,2, abilities[n]))
end
end
return starlit.ui.build(tb)
end;
handle = function(state, user, q)
for k,a in pairs(state.abilityMap) do
if q[k] then
if a.powerKind == 'maneuver' then
if pptrMatch(user.power.maneuver, {ref=a}) then
user.power.maneuver = nil
else
user.power.maneuver = {ref=a}
end
user:suitSound 'starlit-configure'
return true
elseif a.powerKind == 'direct' then
elseif a.powerKind == 'passive' then
else error('bad ability kind ' .. a.powerKind) end
break
end
end
end;
};
suit = {
render = function(state, user)
local suit = user:getSuit()
local suitDef = suit:def()
local chipW, chipH = listWrap(suitDef.slots.chips, 5)
local batW, batH = listWrap(suitDef.slots.batteries, 5)
local canW, canH = listWrap(suitDef.slots.canisters, 5)
local suitMode = suit:powerState()
local function modeColor(mode)
if mode == suitMode then return {hue = 180, sat = 0, lum = .5} end
end
return starlit.ui.build {
kind = 'vert', mode = 'sw';
padding = 0.5, spacing = 0.1;
{kind = 'hztl',
{kind = 'img', desc='Batteries', img = 'starlit-item-battery.png', w=1,h=1};
{kind = 'list', target = 'current_player', inv = 'starlit_suit_bat',
listContent = 'power', w = batW, h = batH, spacing = 0.1};
};
{kind = 'hztl',
{kind = 'img', desc='Chips', img = 'starlit-item-chip.png', w=1,h=1};
{kind = 'list', target = 'current_player', inv = 'starlit_suit_chips',
listContent = 'chip', w = chipW, h = chipH, spacing = 0.1};
};
{kind = 'hztl',
{kind = 'img', desc='Canisters', img = 'starlit-item-element-canister.png', w=1,h=1};
{kind = 'list', target = 'current_player', inv = 'starlit_suit_canisters',
listContent = nil, w = canW, h = canH, spacing = 0.1};
};
{kind = 'hztl';
{kind = 'img', w=1,h=1, item = suit.item:get_name(),
desc = suit.item:get_definition().short_description};
{kind = 'button', w=1.5,h=1, id = 'powerMode_off', label = 'Off';
color=modeColor'off'};
{kind = 'button', w=2.5,h=1, id = 'powerMode_save', label = 'Power Save';
color=modeColor'powerSave'};
{kind = 'button', w=1.5,h=1, id = 'powerMode_on', label = 'On';
color=modeColor'on'};
};
{kind = 'list', target = 'current_player', inv = 'main', w = 6, h = 1, spacing = 0.1};
}
end;
handle = function(state, user, q)
local suitMode
if q.powerMode_off then suitMode = 'off'
elseif q.powerMode_save then suitMode = 'powerSave'
elseif q.powerMode_on then suitMode = 'on' end
if suitMode then
user:suitPowerStateSet(suitMode)
return true
end
end;
};
};
})
local function compilerCanPrint(user, cpl, scm)
local output = ItemStack(scm.sw.output):get_definition()
local fab = output._starlit.fab
local sw = scm.sw
local ok, consume, unsat, leftover, itemSpec = fab:seek {
user.entity:get_inventory():get_list 'main';
}
local cost = {
consume = consume, unsat = unsat, leftover = leftover, itemSpec = itemSpec;
runtimeEstimate = scm.speed + cpl.speed + (fab.time and fab.time.print or 0);
power = cpl.powerCost + scm.powerCost;
ram = (cpl.cost and cpl.cost.ram or 0)
+ (scm.cost and scm.cost.ram or 0);
cycles = (cpl.cost and cpl.cost.cycles or 0)
+ (scm.cost and scm.cost.cycles or 0);
}
local userComp = starlit.mod.electronics.chip.sumCompute(
user.entity:get_inventory():get_list 'starlit_suit_chips'
)
if ok and cost.power <= user:suitCharge() and cost.ram <= userComp.ram then
return true, cost
else return false, cost end
end
-- TODO destroy suit interfaces when power runs out or suit/chip is otherwise disabled
starlit.interface.install(starlit.type.ui {
id = 'starlit:compile-matter-component';
sub = {
suit = function(state, user, evt)
if evt.kind == 'disrobe' then state:close()
elseif evt.kind == 'power' and evt.mode == 'off' then state:close() end
end;
playerInventory = function(state,user)
-- refresh
end;
};
pages = {
index = {
setupState = function(state, user, ctx)
state.pgm = ctx.program
state.select = {}
local E = starlit.mod.electronics
if ctx.context == 'suit' then
state.fetch = function()
local cst = user.entity:get_inventory():get_list 'starlit_suit_chips'
local cl = {order={}, map={}, slot={}}
for i, c in ipairs(cst) do
if not c:is_empty() then
local d = E.chip.read(c)
local co = {
stack = c;
data = d;
}
table.insert(cl.order, co)
cl.map[d.uuid] = co
cl.slot[i] = co
end
end
-- kill me fam
if ( state.select.chip
and state.select.chip ~= true
and not cl.map[state.select.chip])
or (state.select.scm
and not state.select.scms[state.select.scm])
then
-- chip or pgm no longer available
user:suitSound 'starlit-error'
state.select = {}
end
state.select.chips = cl
state.select.scms = {}
if state.select.chip then
state.select.scms = E.chip.usableSoftware(cst,nil, function(s)
if state.select.chip ~= true then
if cl.slot[s.chipSlot].data.uuid ~= state.select.chip then
return false
end
end
return s.sw.kind == 'schematic'
end)
end
end
end
end;
onClose = function(state, user)
user:suitSound 'starlit-quit'
end;
handle = function(state, user, q)
local sel = state.select
state.fetch()
local chips = state.select.chips
local function chirp()
user:suitSound 'starlit-nav'
end
local function trySelection(id)
if sel[id] == nil then
for k in next, q do
local pat = "^"..id.."_(%d+)$" -- ew
local idx = k:match(pat)
if idx then
local cm = tonumber(idx)
if cm then
chirp()
sel[id] = cm
return true
end
end
end
end
end
if sel.chip == nil then
if q.showAll then
chirp()
sel.chip = true
return true
elseif q.find then
chirp()
-- TODO
return true
end
end
if trySelection('chip') then
return true
elseif trySelection('scm') then
return true
else
if q.back then
chirp()
if sel.input then
sel.input = nil
elseif sel.scm then
sel.scm = nil
elseif sel.chip then
sel.chip = nil
end
return true
elseif q.commit then
if not sel.input then
chirp()
sel.input = true
return true
else
local scm = sel.scms[sel.scm]
local ok, cost = compilerCanPrint(user, state.pgm, scm)
if ok then
user:suitSound 'starlit-configure'
-- consume consumables
-- add print job
state.select = {}
return true
else
user:suitSound 'starlit-error'
end
end
end
end
end;
render = function(state, user)
local sel, pgmSelector = state.select, {}
state.fetch()
local function pushSelector(id, item, label, desc, req)
local rh = .5
local label = {kind = 'text', w = 10-1.5, h=1.5;
text = '<global valign=middle>'..lib.str.htsan(label) }
if req then
label.h = label.h - rh - .2
local imgs = {}
for ci,c in ipairs(req) do
for ei, e in ipairs(c.list) do
table.insert(imgs, {kind = 'img', w=rh, h=rh, img=e.img})
end
end
label = {kind = 'vert', w = 10-1.5, h=1.5;
label;
{kind ='hztl', w=10-1.5, h=rh; unpack(imgs); }
}
end
table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5;
{kind = 'contact', id=id, w=1.5, h=1.5;
item = item;
color = {hue=220, sat=0, lum=0};
desc = desc;
};
label;
})
end
local back = {kind = 'button', id='back', label = '<- Back', w=10,h=1.2}
if sel.chips == nil then
table.insert(pgmSelector, {kind = 'img', img = 'starlit-ui-alert.png', w=2, h=2})
elseif sel.chip == nil then
for i, c in ipairs(sel.chips.order) do
-- TODO filter out chips without schematics?
pushSelector('chip_' .. c.data.uuid, c.stack, c.data.label)
end
if next(sel.chips.order) then
table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5;
{kind = 'button', w=5,h=1.5; id='showAll', label='Show All'};
{kind = 'button', w=5,h=1.5; id='find', label='Find'};
})
end
else
if sel.scm == nil then
for idx, ent in ipairs(sel.scms) do
local fab = ItemStack(ent.sw.output):get_definition()._starlit.fab
if fab.flag.print then
local req = fab:visualize()
pushSelector('scm_' .. idx, ent.sw.output, ent.sw.name, nil, req)
end
end
table.insert(pgmSelector, back)
else
local scm = sel.scms[sel.scm]
local output = ItemStack(scm.sw.output):get_definition()
local fab = output._starlit.fab
local sw = scm.sw
local function unmet(str)
return lib.color(1,.3,.3):fmt(str)
end
table.insert(pgmSelector, {kind = 'hztl', w=10, h=1.2;
{kind = 'img', item = sw.output, w=1.2, h=1.2, desc=output.description};
{kind = 'text', text = string.format('<global valign=middle><b>%s</b>', lib.str.htsan(sw.name)), w=10-1.2,h=1.2};
})
local inputTbl = {kind = 'vert', w=5,h=0;
{kind = 'hbar', w=5, h=.5, text=sel.input and 'Input Plan' or 'Input'}};
local costTbl = {kind = 'vert', w=5,h=0;
{kind = 'hbar', w=5, h=.5, text=sel.input and 'Process Plan' or 'Process'}};
local reqPane = {kind = 'pane', id='reqPane', w=10, h=7;
{kind = 'hztl', w=10,h=0; inputTbl, costTbl}
}
local function pushCost(x, t, val)
table.insert(costTbl, {kind='label', w=4.5,h=.5,x=x;
text=string.format('%s: %s',t,val);
})
end
local function pushComputeCosts(header, p)
if p then
table.insert(costTbl, {kind = 'label', w=5, h=.5, x=0; text=header});
if p.cycles then
pushCost(.5, 'Compute', lib.math.siUI({'cycle','cycles'}, p.cycles, true))
end
if p.power then
local str = lib.math.siUI('J', p.power)
if p.power > user:suitCharge() then str = unmet(str) end
pushCost(.5, 'Power', str)
end
if p.ram then
local str = string.format("%s / %s",
lib.math.siUI('B', p.ram),
lib.math.siUI('B', state.pgm.comp.ram))
if p.ram > state.pgm.comp.ram then str = unmet(str) end
pushCost(.5, 'Memory', str)
end
end
end
local function fabToUI(x, inputTbl, req)
for ci,c in ipairs(req) do
table.insert(inputTbl, {kind = 'label', w=5-x, h=.5, x=x;
text=lib.str.capitalize(c.header)});
for ei,e in ipairs(c.list) do
table.insert(inputTbl, {kind = 'hztl', w=4.5-x, h=.5, x=x+.5;
{kind='img', w=.5,h=.5, img=e.img};
{kind='label', w=3.3,h=.5,x=.2, text=lib.str.capitalize(e.label)};
});
end
end
end
local commitHue=120, commitLabel
if not sel.input then
commitLabel = 'Plan'
fabToUI(0, inputTbl, fab:visualize())
local function pushComputeCostsSw(header, p)
if p.sw.cost then
pushComputeCosts(header, {
cycles = p.sw.cost.cycles;
power = p.powerCost;
ram = p.sw.cost.ram;
})
end
end
pushComputeCostsSw('Schematic', scm)
pushComputeCostsSw('Compiler', state.pgm)
else
commitLabel = 'Commit'
pushComputeCosts('Total', {
cycles = (scm.sw.cost and scm.sw.cost.cycles or 0)
+ (state.pgm.sw.cost and state.pgm.sw.cost.cycles or 0);
power = (scm.powerCost or 0)
+ (state.pgm.powerCost or 0)
+ (fab.cost and fab.cost.power or 0);
ram = (scm.sw.cost and scm.sw.cost.ram or 0)
+ (state.pgm.sw.cost and state.pgm.sw.cost.ram or 0);
})
if fab.time and fab.time.print then
pushCost(0, 'Job Runtime', lib.math.timespec(fab.time.print + scm.speed))
pushCost(.5, 'Print Time', lib.math.timespec(fab.time.print))
pushCost(.5, 'CPU Time', lib.math.timespec(scm.speed + state.pgm.speed))
end
local ok, compileCost = compilerCanPrint(user, state.pgm, scm)
fabToUI(0, inputTbl, compileCost.itemSpec:visualize())
if next(compileCost.unsat) then
local vis = compileCost.unsat:visualize()
for si, s in ipairs(vis) do
s.header = 'Missing ' .. s.header
for ei, e in ipairs(s.list) do
e.label = lib.color(1,.2,.2):fmt(e.label)
end
end
fabToUI(0, inputTbl, vis)
end
if not ok then commitHue = 0 end
end
table.insert(pgmSelector, reqPane)
table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.2;
{kind = 'button', id='back', label = '← Back', w=5,h=1.2};
{kind = 'button', id='commit', label = commitLabel .. ' →', w=5,h=1.2, color={hue=commitHue,sat=0,lum=0}};
})
end
end
return starlit.ui.build {
kind = 'hztl', padding = 0.5; w = 20, h = 10, mode = 'sw';
{kind = 'vert', w = 5, h = 5;
{kind = 'hbar', fac=0, w = 5, h = .5, text = '<b><left>Recent Prints</left></b>'};
};
{kind = 'vert', w = 10, h = 10;
{kind = 'hbar', fac=0, w = 10, h = .5, text = '<b>Program Select</b>'};
{kind = 'pane', w = 10, h = 9.5, id='pgmSelect';
unpack(pgmSelector)
};
};
{kind = 'vert', w = 5, h = 10;
{kind = 'hbar', fac=0, w = 5, h = .5, text = '<b><right>Print Queue</right></b>'};
};
}
end;
};
};
})