Tweak the workflow gui script to make the UI operate smoother.

develop
Alexander Gavrilov 2012-10-25 12:15:18 +04:00
parent a1dd31aab3
commit 8eebfa007c
5 changed files with 144 additions and 108 deletions

@ -283,7 +283,11 @@ function clone_with_default(obj,default,force)
return rv return rv
end end
-- Parse an integer value into a bitfield table
function parse_bitfield_int(value, type_ref) function parse_bitfield_int(value, type_ref)
if value == 0 then
return nil
end
local res = {} local res = {}
for i,v in ipairs(type_ref) do for i,v in ipairs(type_ref) do
if bit32.extract(value, i) ~= 0 then if bit32.extract(value, i) ~= 0 then
@ -293,6 +297,19 @@ function parse_bitfield_int(value, type_ref)
return res return res
end end
-- List the enabled flag names in the bitfield table
function list_bitfield_flags(bitfield, list)
list = list or {}
if bitfield then
for name,val in pairs(bitfield) do
if val then
table.insert(list, name)
end
end
end
return list
end
-- Sort a vector or lua table -- Sort a vector or lua table
function sort_vector(vector,field,cmp) function sort_vector(vector,field,cmp)
local fcmp = compare_field(field,cmp) local fcmp = compare_field(field,cmp)

@ -9,7 +9,7 @@ local utils = require 'utils'
* isEnabled() * isEnabled()
* setEnabled(enable) * setEnabled(enable)
* listConstraints([job]) -> {...} * listConstraints([job]) -> {...}
* setConstraint(token, by_count, goal[, gap]) -> {...} * setConstraint(token[, by_count, goal, gap]) -> {...}
* deleteConstraint(token) -> true/false * deleteConstraint(token) -> true/false
--]] --]]
@ -40,6 +40,10 @@ local job_outputs = {}
function job_outputs.CustomReaction(callback, job) function job_outputs.CustomReaction(callback, job)
local rid, r = get_reaction(job.reaction_name) local rid, r = get_reaction(job.reaction_name)
if not r then
return
end
for i,prod in ipairs(r.products) do for i,prod in ipairs(r.products) do
if df.reaction_product_itemst:is_instance(prod) then if df.reaction_product_itemst:is_instance(prod) then
local mat_type, mat_index = prod.mat_type, prod.mat_index local mat_type, mat_index = prod.mat_type, prod.mat_index
@ -239,11 +243,7 @@ function constraintToToken(cspec)
end end
local mask_part local mask_part
if cspec.mat_mask then if cspec.mat_mask then
local lst = {} mask_part = table.concat(utils.list_bitfield_flags(cspec.mat_mask), ',')
for n,v in pairs(cspec.mat_mask) do
if v then table.insert(lst,n) end
end
mask_part = table.concat(lst, ',')
end end
local mat_part local mat_part
if cspec.mat_type and cspec.mat_type >= 0 then if cspec.mat_type and cspec.mat_type >= 0 then
@ -272,4 +272,43 @@ function constraintToToken(cspec)
return token return token
end end
function listWeakenedConstraints(outputs)
local variants = {}
local known = {}
local function register(cons)
cons.token = constraintToToken(cons)
if not known[cons.token] then
known[cons.token] = true
table.insert(variants, cons)
end
end
local generic = {}
local anymat = {}
for i,cons in ipairs(outputs) do
local mask = cons.mat_mask
if (cons.mat_type or -1) >= 0 then
cons.mat_mask = nil
end
register(cons)
if mask then
table.insert(generic, {
item_type = cons.item_type,
item_subtype = cons.item_subtype,
is_craft = cons.is_craft,
mat_mask = mask
})
end
table.insert(anymat, {
item_type = cons.item_type,
item_subtype = cons.item_subtype,
is_craft = cons.is_craft
})
end
for i,cons in ipairs(generic) do register(cons) end
for i,cons in ipairs(anymat) do register(cons) end
return variants
end
return _ENV return _ENV

@ -1452,19 +1452,23 @@ static void push_constraint(lua_State *L, ItemConstraint *cv)
static int listConstraints(lua_State *L) static int listConstraints(lua_State *L)
{ {
auto job = Lua::CheckDFObject<df::job>(L, 1); auto job = Lua::CheckDFObject<df::job>(L, 1);
ProtectedJob *pj = NULL;
if (job)
pj = get_known(job->id);
if (!enabled || (job && !pj))
{
lua_pushnil(L); lua_pushnil(L);
if (!enabled || (job && !isSupportedJob(job)))
return 1; return 1;
}
color_ostream &out = *Lua::GetOutput(L); color_ostream &out = *Lua::GetOutput(L);
update_data_structures(out); update_data_structures(out);
ProtectedJob *pj = NULL;
if (job)
{
pj = get_known(job->id);
if (!pj)
return 1;
}
lua_newtable(L); lua_newtable(L);
auto &vec = (pj ? pj->constraints : constraints); auto &vec = (pj ? pj->constraints : constraints);
@ -1491,6 +1495,7 @@ static int setConstraint(lua_State *L)
if (!icv) if (!icv)
luaL_error(L, "invalid constraint: %s", token); luaL_error(L, "invalid constraint: %s", token);
if (!lua_isnil(L, 2))
icv->setGoalByCount(by_count); icv->setGoalByCount(by_count);
if (!lua_isnil(L, 3)) if (!lua_isnil(L, 3))
icv->setGoalCount(count); icv->setGoalCount(count);

@ -26,6 +26,23 @@ function check_enabled(cb,...)
end end
end end
function check_repeat(job, cb)
if job.flags['repeat'] then
return cb(job)
else
dlg.showYesNoPrompt(
'Not Repeat Job',
{ 'Workflow only tracks repeating jobs.', NEWLINE, NEWLINE,
'Press ', { key = 'MENU_CONFIRM' }, ' to make this one repeat.' },
COLOR_YELLOW,
function()
job.flags['repeat'] = true
return cb(job)
end
)
end
end
JobConstraints = defclass(JobConstraints, guidm.MenuOverlay) JobConstraints = defclass(JobConstraints, guidm.MenuOverlay)
JobConstraints.focus_path = 'workflow-job' JobConstraints.focus_path = 'workflow-job'
@ -41,14 +58,6 @@ local null_cons = { goal_value = 0, goal_gap = 0, goal_by_count = false }
function JobConstraints:init(args) function JobConstraints:init(args)
self.building = dfhack.job.getHolder(self.job) self.building = dfhack.job.getHolder(self.job)
local status = { text = 'No worker', pen = COLOR_DARKGREY }
local worker = dfhack.job.getWorker(self.job)
if self.job.flags.suspend then
status = { text = 'Suspended', pen = COLOR_RED }
elseif worker then
status = { text = dfhack.TranslateName(dfhack.units.getVisibleName(worker)), pen = COLOR_GREEN }
end
self:addviews{ self:addviews{
widgets.Label{ widgets.Label{
frame = { l = 0, t = 0 }, frame = { l = 0, t = 0 },
@ -160,19 +169,7 @@ function describe_material(iobj)
return matline return matline
end end
function list_flags(bitfield) function JobConstraints:initListChoices(clist, sel_token)
local list = {}
if bitfield then
for name,val in pairs(bitfield) do
if val then
table.insert(list, name)
end
end
end
return list
end
function JobConstraints:initListChoices(clist)
clist = clist or workflow.listConstraints(self.job) clist = clist or workflow.listConstraints(self.job)
local choices = {} local choices = {}
@ -199,7 +196,7 @@ function JobConstraints:initListChoices(clist)
end end
local matstr = describe_material(cons) local matstr = describe_material(cons)
local matflagstr = '' local matflagstr = ''
local matflags = list_flags(cons.mat_mask) local matflags = utils.list_bitfield_flags(cons.mat_mask)
if #matflags > 0 then if #matflags > 0 then
matflags[1] = 'any '..matflags[1] matflags[1] = 'any '..matflags[1]
if matstr == 'any material' then if matstr == 'any material' then
@ -216,11 +213,17 @@ function JobConstraints:initListChoices(clist)
goal, ' ', { text = '(now '..curval..')', pen = order_pen }, NEWLINE, goal, ' ', { text = '(now '..curval..')', pen = order_pen }, NEWLINE,
' ', itemstr, NEWLINE, ' ', matstr, NEWLINE, ' ', matflagstr ' ', itemstr, NEWLINE, ' ', matstr, NEWLINE, ' ', matflagstr
}, },
token = cons.token,
obj = cons obj = cons
}) })
end end
self.subviews.list:setChoices(choices) local selidx = nil
if sel_token then
selidx = utils.linear_index(choices, sel_token, 'token')
end
self.subviews.list:setChoices(choices, selidx)
end end
function JobConstraints:isAnySelected() function JobConstraints:isAnySelected()
@ -232,18 +235,9 @@ function JobConstraints:getCurConstraint()
if v then return v.obj end if v then return v.obj end
end end
function JobConstraints:getCurUnit()
local cons = self:getCurConstraint()
if cons and cons.goal_by_count then
return 'stacks'
else
return 'items'
end
end
function JobConstraints:saveConstraint(cons) function JobConstraints:saveConstraint(cons)
workflow.setConstraint(cons.token, cons.goal_by_count, cons.goal_value, cons.goal_gap) local out = workflow.setConstraint(cons.token, cons.goal_by_count, cons.goal_value, cons.goal_gap)
self:initListChoices() self:initListChoices(nil, out.token)
end end
function JobConstraints:onChangeUnit() function JobConstraints:onChangeUnit()
@ -285,45 +279,6 @@ function JobConstraints:onIncRange(field, delta)
self:saveConstraint(cons) self:saveConstraint(cons)
end end
function make_constraint_variants(outputs)
local variants = {}
local known = {}
local function register(cons)
cons.token = workflow.constraintToToken(cons)
if not known[cons.token] then
known[cons.token] = true
table.insert(variants, cons)
end
end
local generic = {}
local anymat = {}
for i,cons in ipairs(outputs) do
local mask = cons.mat_mask
if (cons.mat_type or -1) >= 0 then
cons.mat_mask = nil
end
register(cons)
if mask then
table.insert(generic, {
item_type = cons.item_type,
item_subtype = cons.item_subtype,
is_craft = cons.is_craft,
mat_mask = mask
})
end
table.insert(anymat, {
item_type = cons.item_type,
item_subtype = cons.item_subtype,
is_craft = cons.is_craft
})
end
for i,cons in ipairs(generic) do register(cons) end
for i,cons in ipairs(anymat) do register(cons) end
return variants
end
function JobConstraints:onNewConstraint() function JobConstraints:onNewConstraint()
local outputs = workflow.listJobOutputs(self.job) local outputs = workflow.listJobOutputs(self.job)
if #outputs == 0 then if #outputs == 0 then
@ -331,13 +286,13 @@ function JobConstraints:onNewConstraint()
return return
end end
local variants = make_constraint_variants(outputs) local variants = workflow.listWeakenedConstraints(outputs)
local choices = {} local choices = {}
for i,cons in ipairs(variants) do for i,cons in ipairs(variants) do
local itemstr = describe_item_type(cons) local itemstr = describe_item_type(cons)
local matstr = describe_material(cons) local matstr = describe_material(cons)
local matflags = list_flags(cons.mat_mask or {}) local matflags = utils.list_bitfield_flags(cons.mat_mask)
if #matflags > 0 then if #matflags > 0 then
local fstr = table.concat(matflags, '/') local fstr = table.concat(matflags, '/')
if matstr == 'any material' then if matstr == 'any material' then
@ -352,7 +307,7 @@ function JobConstraints:onNewConstraint()
dlg.showListPrompt( dlg.showListPrompt(
'Job Outputs', 'Job Outputs',
'Select one of the job outputs:', 'Select one of the possible outputs:',
COLOR_WHITE, COLOR_WHITE,
choices, choices,
function(idx,item) function(idx,item)
@ -390,15 +345,13 @@ end
check_enabled(function() check_enabled(function()
local job = dfhack.gui.getSelectedJob() local job = dfhack.gui.getSelectedJob()
if not job.flags['repeat'] then check_repeat(job, function(job)
dlg.showMessage('Not Supported', 'Workflow only tracks repeat jobs.', COLOR_LIGHTRED)
return
end
local clist = workflow.listConstraints(job) local clist = workflow.listConstraints(job)
if not clist then if not clist then
dlg.showMessage('Not Supported', 'This type of job is not supported by workflow.', COLOR_LIGHTRED) dlg.showMessage('Not Supported', 'This type of job is not supported by workflow.', COLOR_LIGHTRED)
return return
end end
JobConstraints{ job = job, clist = clist }:show() JobConstraints{ job = job, clist = clist }:show()
end)
end) end)

@ -220,10 +220,31 @@ function JobDetails:setMaterial(obj, mat_type, mat_index)
obj.iobj.mat_index = mat_index obj.iobj.mat_index = mat_index
end end
function JobDetails:findUnambiguousItem(iobj)
local count = 0
local itype
for i = 0,df.item_type._last_item do
if dfhack.job.isSuitableItem(iobj, i, -1) then
count = count + 1
if count > 1 then return nil end
itype = i
end
end
return itype
end
function JobDetails:onChangeMat() function JobDetails:onChangeMat()
local idx, obj = self.subviews.list:getSelected() local idx, obj = self.subviews.list:getSelected()
if obj.iobj.item_type == -1 and obj.iobj.mat_type == -1 then if obj.iobj.item_type == -1 and obj.iobj.mat_type == -1 then
-- If the job allows only one specific item type, use it
local vitype = self:findUnambiguousItem(obj.iobj)
if vitype then
obj.iobj.item_type = vitype
else
dlg.showMessage( dlg.showMessage(
'Bug Alert', 'Bug Alert',
{ 'Please set a specific item type first.\n\n', { 'Please set a specific item type first.\n\n',
@ -233,6 +254,7 @@ function JobDetails:onChangeMat()
) )
return return
end end
end
guimat.MaterialDialog{ guimat.MaterialDialog{
prompt = 'Please select a new material for input '..idx, prompt = 'Please select a new material for input '..idx,