|
|
|
@ -66,20 +66,64 @@ function is_caste_mat(iobj)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function describe_material(iobj)
|
|
|
|
|
local matline = 'any material'
|
|
|
|
|
local matflags = utils.list_bitfield_flags(iobj.mat_mask)
|
|
|
|
|
if #matflags > 0 then
|
|
|
|
|
matflags = 'any '..table.concat(matflags, '/')
|
|
|
|
|
else
|
|
|
|
|
matflags = nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if is_caste_mat(iobj) then
|
|
|
|
|
matline = 'no material'
|
|
|
|
|
return 'no material'
|
|
|
|
|
elseif (iobj.mat_type or -1) >= 0 then
|
|
|
|
|
local info = dfhack.matinfo.decode(iobj.mat_type, iobj.mat_index)
|
|
|
|
|
local matline
|
|
|
|
|
if info then
|
|
|
|
|
matline = info:toString()
|
|
|
|
|
else
|
|
|
|
|
matline = iobj.mat_type..':'..iobj.mat_index
|
|
|
|
|
end
|
|
|
|
|
return matline, matflags
|
|
|
|
|
else
|
|
|
|
|
return matflags or 'any material'
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function current_stock(iobj)
|
|
|
|
|
if iobj.goal_by_count then
|
|
|
|
|
return iobj.cur_count
|
|
|
|
|
else
|
|
|
|
|
return iobj.cur_amount
|
|
|
|
|
end
|
|
|
|
|
return matline
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function if_by_count(iobj,bc,ba)
|
|
|
|
|
if iobj.goal_by_count then
|
|
|
|
|
return bc
|
|
|
|
|
else
|
|
|
|
|
return ba
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function compute_trend(history,field)
|
|
|
|
|
local count = #history
|
|
|
|
|
if count == 0 then
|
|
|
|
|
return 0
|
|
|
|
|
end
|
|
|
|
|
local sumX,sumY,sumXY,sumXX = 0,0,0,0
|
|
|
|
|
for i,v in ipairs(history) do
|
|
|
|
|
sumX = sumX + i
|
|
|
|
|
sumY = sumY + v[field]
|
|
|
|
|
sumXY = sumXY + i*v[field]
|
|
|
|
|
sumXX = sumXX + i*i
|
|
|
|
|
end
|
|
|
|
|
return (count * sumXY - sumX * sumY) / (count * sumXX - sumX * sumX)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
------------------------
|
|
|
|
|
-- RANGE EDITOR GROUP --
|
|
|
|
|
------------------------
|
|
|
|
|
|
|
|
|
|
local null_cons = { goal_value = 0, goal_gap = 0, goal_by_count = false }
|
|
|
|
|
|
|
|
|
|
RangeEditor = defclass(RangeEditor, widgets.Label)
|
|
|
|
@ -162,6 +206,10 @@ function RangeEditor:onIncRange(field, delta)
|
|
|
|
|
self.save_cb(cons)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
---------------------------
|
|
|
|
|
-- NEW CONSTRAINT DIALOG --
|
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
|
|
NewConstraint = defclass(NewConstraint, gui.FramedScreen)
|
|
|
|
|
|
|
|
|
|
NewConstraint.focus_path = 'workflow/new'
|
|
|
|
@ -177,7 +225,7 @@ NewConstraint.ATTRS {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function NewConstraint:init(args)
|
|
|
|
|
self.constraint = args.constraint or {}
|
|
|
|
|
self.constraint = args.constraint or { item_type = -1 }
|
|
|
|
|
rawset_default(self.constraint, { goal_value = 10, goal_gap = 5, goal_by_count = false })
|
|
|
|
|
|
|
|
|
|
local matlist = {}
|
|
|
|
@ -202,8 +250,16 @@ function NewConstraint:init(args)
|
|
|
|
|
frame = { l = 1, t = 2, w = 26 },
|
|
|
|
|
text = {
|
|
|
|
|
'Type: ',
|
|
|
|
|
{ pen = COLOR_LIGHTCYAN,
|
|
|
|
|
text = function() return describe_item_type(self.constraint) end },
|
|
|
|
|
{ pen = function()
|
|
|
|
|
if self:isValid() then return COLOR_LIGHTCYAN else return COLOR_LIGHTRED end
|
|
|
|
|
end,
|
|
|
|
|
text = function()
|
|
|
|
|
if self:isValid() then
|
|
|
|
|
return describe_item_type(self.constraint)
|
|
|
|
|
else
|
|
|
|
|
return 'item not set'
|
|
|
|
|
end
|
|
|
|
|
end },
|
|
|
|
|
NEWLINE, ' ',
|
|
|
|
|
{ key = 'CUSTOM_T', text = ': Select, ',
|
|
|
|
|
on_activate = self:callback('chooseType') },
|
|
|
|
@ -277,6 +333,7 @@ function NewConstraint:init(args)
|
|
|
|
|
{ key = 'LEAVESCREEN', text = ': Cancel, ',
|
|
|
|
|
on_activate = self:callback('dismiss') },
|
|
|
|
|
{ key = 'MENU_CONFIRM', key_sep = ': ',
|
|
|
|
|
enabled = self:callback('isValid'),
|
|
|
|
|
text = function()
|
|
|
|
|
if self.is_existing then return 'Update' else return 'Create new' end
|
|
|
|
|
end,
|
|
|
|
@ -295,9 +352,17 @@ function NewConstraint:postinit()
|
|
|
|
|
self:onChange()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function NewConstraint:isValid()
|
|
|
|
|
return self.constraint.item_type >= 0
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function NewConstraint:onChange()
|
|
|
|
|
local token = workflow.constraintToToken(self.constraint)
|
|
|
|
|
local out = workflow.findConstraint(token)
|
|
|
|
|
local out
|
|
|
|
|
|
|
|
|
|
if self:isValid() then
|
|
|
|
|
out = workflow.findConstraint(token)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if out then
|
|
|
|
|
self.constraint = out
|
|
|
|
@ -390,6 +455,288 @@ function NewConstraint:onRangeChange()
|
|
|
|
|
cons.goal_gap = math.max(1, math.min(cons.goal_gap, cons.goal_value-1))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
------------------------------
|
|
|
|
|
-- GLOBAL CONSTRAINT SCREEN --
|
|
|
|
|
------------------------------
|
|
|
|
|
|
|
|
|
|
ConstraintList = defclass(ConstraintList, gui.FramedScreen)
|
|
|
|
|
|
|
|
|
|
ConstraintList.focus_path = 'workflow/list'
|
|
|
|
|
|
|
|
|
|
ConstraintList.ATTRS {
|
|
|
|
|
frame_title = 'Workflow Status',
|
|
|
|
|
frame_inset = 0,
|
|
|
|
|
frame_background = COLOR_BLACK,
|
|
|
|
|
frame_style = gui.BOUNDARY_FRAME,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ConstraintList:init(args)
|
|
|
|
|
local fwidth_cb = self:cb_getfield('fwidth')
|
|
|
|
|
|
|
|
|
|
self.fwidth = 20
|
|
|
|
|
self.sort_by_severity = false
|
|
|
|
|
|
|
|
|
|
self:addviews{
|
|
|
|
|
widgets.Panel{
|
|
|
|
|
frame = { w = 31, r = 0, h = 6, t = 0 },
|
|
|
|
|
frame_inset = 1,
|
|
|
|
|
subviews = {
|
|
|
|
|
widgets.Label{
|
|
|
|
|
frame = { l = 0, t = 0 },
|
|
|
|
|
enabled = self:callback('isAnySelected'),
|
|
|
|
|
text = {
|
|
|
|
|
{ text = function()
|
|
|
|
|
local cur = self:getCurConstraint()
|
|
|
|
|
if cur then
|
|
|
|
|
return string.format(
|
|
|
|
|
'Currently %d (%d in use)',
|
|
|
|
|
current_stock(cur),
|
|
|
|
|
if_by_count(cur, cur.cur_in_use_count, cur.cur_in_use_amount)
|
|
|
|
|
)
|
|
|
|
|
else
|
|
|
|
|
return 'No constraint selected'
|
|
|
|
|
end
|
|
|
|
|
end }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
RangeEditor{
|
|
|
|
|
frame = { l = 0, t = 2 },
|
|
|
|
|
enabled = self:callback('isAnySelected'),
|
|
|
|
|
get_cb = self:callback('getCurConstraint'),
|
|
|
|
|
save_cb = self:callback('saveConstraint'),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
widgets.Widget{
|
|
|
|
|
active = false,
|
|
|
|
|
frame = { w = 1, r = 31 },
|
|
|
|
|
frame_background = gui.BOUNDARY_FRAME.frame_pen,
|
|
|
|
|
},
|
|
|
|
|
widgets.Widget{
|
|
|
|
|
active = false,
|
|
|
|
|
frame = { w = 31, r = 0, h = 1, t = 6 },
|
|
|
|
|
frame_background = gui.BOUNDARY_FRAME.frame_pen,
|
|
|
|
|
},
|
|
|
|
|
widgets.Panel{
|
|
|
|
|
frame = { l = 0, r = 32 },
|
|
|
|
|
frame_inset = 1,
|
|
|
|
|
on_layout = function(body)
|
|
|
|
|
self.fwidth = body.width - (12+1+1+7+1+1+1+7)
|
|
|
|
|
end,
|
|
|
|
|
subviews = {
|
|
|
|
|
widgets.Label{
|
|
|
|
|
frame = { l = 0, t = 0 },
|
|
|
|
|
text_pen = COLOR_CYAN,
|
|
|
|
|
text = {
|
|
|
|
|
{ text = 'Item', width = 12 }, ' ',
|
|
|
|
|
{ text = 'Material etc', width = fwidth_cb }, ' ',
|
|
|
|
|
{ text = 'Stock / Limit' },
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
widgets.FilteredList{
|
|
|
|
|
view_id = 'list',
|
|
|
|
|
frame = { t = 2, b = 2 },
|
|
|
|
|
edit_below = true,
|
|
|
|
|
not_found_label = 'No matching constraints',
|
|
|
|
|
edit_pen = COLOR_LIGHTCYAN,
|
|
|
|
|
text_pen = { fg = COLOR_GREY, bg = COLOR_BLACK },
|
|
|
|
|
cursor_pen = { fg = COLOR_WHITE, bg = COLOR_GREEN },
|
|
|
|
|
},
|
|
|
|
|
widgets.Label{
|
|
|
|
|
frame = { b = 0, h = 1 },
|
|
|
|
|
text = {
|
|
|
|
|
{ key = 'CUSTOM_SHIFT_A', text = ': Add',
|
|
|
|
|
on_activate = self:callback('onNewConstraint') }, ', ',
|
|
|
|
|
{ key = 'CUSTOM_SHIFT_X', text = ': Delete',
|
|
|
|
|
on_activate = self:callback('onDeleteConstraint') }, ', ',
|
|
|
|
|
{ key = 'CUSTOM_SHIFT_O', text = ': Severity Order',
|
|
|
|
|
on_activate = self:callback('onSwitchSort'),
|
|
|
|
|
pen = function()
|
|
|
|
|
if self.sort_by_severity then
|
|
|
|
|
return COLOR_LIGHTCYAN
|
|
|
|
|
else
|
|
|
|
|
return COLOR_WHITE
|
|
|
|
|
end
|
|
|
|
|
end }, ', ',
|
|
|
|
|
{ key = 'CUSTOM_SHIFT_S', text = ': Search',
|
|
|
|
|
on_activate = function()
|
|
|
|
|
self.subviews.list.edit.active = not self.subviews.list.edit.active
|
|
|
|
|
end,
|
|
|
|
|
pen = function()
|
|
|
|
|
if self.subviews.list.edit.active then
|
|
|
|
|
return COLOR_LIGHTCYAN
|
|
|
|
|
else
|
|
|
|
|
return COLOR_WHITE
|
|
|
|
|
end
|
|
|
|
|
end }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.subviews.list.edit.active = false
|
|
|
|
|
|
|
|
|
|
self:initListChoices()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function stock_trend_color(cons)
|
|
|
|
|
local stock = current_stock(cons)
|
|
|
|
|
if stock >= cons.goal_value - cons.goal_gap then
|
|
|
|
|
return COLOR_LIGHTGREEN, 0
|
|
|
|
|
elseif stock <= cons.goal_gap then
|
|
|
|
|
return COLOR_LIGHTRED, 4
|
|
|
|
|
elseif stock >= cons.goal_value - 2*cons.goal_gap then
|
|
|
|
|
return COLOR_GREEN, 1
|
|
|
|
|
elseif stock <= 2*cons.goal_gap then
|
|
|
|
|
return COLOR_RED, 3
|
|
|
|
|
else
|
|
|
|
|
local trend = if_by_count(cons, cons.trend_count, cons.trend_amount)
|
|
|
|
|
if trend > 0.3 then
|
|
|
|
|
return COLOR_GREEN, 1
|
|
|
|
|
elseif trend < -0.3 then
|
|
|
|
|
return COLOR_RED, 3
|
|
|
|
|
else
|
|
|
|
|
return COLOR_GREY, 2
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:initListChoices(clist, sel_token)
|
|
|
|
|
clist = clist or workflow.listConstraints(nil, true)
|
|
|
|
|
|
|
|
|
|
local fwidth_cb = self:cb_getfield('fwidth')
|
|
|
|
|
local choices = {}
|
|
|
|
|
|
|
|
|
|
for i,cons in ipairs(clist) do
|
|
|
|
|
cons.trend_count = compute_trend(cons.history, 'cur_count')
|
|
|
|
|
cons.trend_amount = compute_trend(cons.history, 'cur_amount')
|
|
|
|
|
|
|
|
|
|
local itemstr = describe_item_type(cons)
|
|
|
|
|
local matstr,matflagstr = describe_material(cons)
|
|
|
|
|
if matflagstr then
|
|
|
|
|
matstr = matflagstr .. ' ' .. matstr
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if cons.min_quality > 0 or cons.is_local then
|
|
|
|
|
local lst = {}
|
|
|
|
|
if cons.is_local then
|
|
|
|
|
table.insert(lst, 'local')
|
|
|
|
|
end
|
|
|
|
|
if cons.min_quality > 0 then
|
|
|
|
|
table.insert(lst, string.lower(df.item_quality[cons.min_quality]))
|
|
|
|
|
end
|
|
|
|
|
matstr = matstr .. ' ('..table.concat(lst,',')..')'
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local goal_color = COLOR_GREY
|
|
|
|
|
if #cons.jobs == 0 then
|
|
|
|
|
goal_color = COLOR_RED
|
|
|
|
|
elseif cons.is_delayed then
|
|
|
|
|
goal_color = COLOR_YELLOW
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
table.insert(choices, {
|
|
|
|
|
text = {
|
|
|
|
|
{ text = itemstr, width = 12, pad_char = ' ' }, ' ',
|
|
|
|
|
{ text = matstr, width = fwidth_cb, pad_char = ' ' }, ' ',
|
|
|
|
|
{ text = curry(current_stock,cons), width = 7, rjustify = true,
|
|
|
|
|
pen = function() return { fg = stock_trend_color(cons) } end },
|
|
|
|
|
{ text = curry(if_by_count,cons,'S','I'), gap = 1,
|
|
|
|
|
pen = { fg = COLOR_GREY } },
|
|
|
|
|
{ text = function() return cons.goal_value end, gap = 1,
|
|
|
|
|
pen = { fg = goal_color } }
|
|
|
|
|
},
|
|
|
|
|
severity = select(2, stock_trend_color(cons)),
|
|
|
|
|
search_key = itemstr .. ' | ' .. matstr,
|
|
|
|
|
token = cons.token,
|
|
|
|
|
obj = cons
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
self:setChoices(choices, sel_token)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:isAnySelected()
|
|
|
|
|
return self.subviews.list:getSelected() ~= nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:getCurConstraint()
|
|
|
|
|
local selidx,selobj = self.subviews.list:getSelected()
|
|
|
|
|
if selobj then return selobj.obj end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:onSwitchSort()
|
|
|
|
|
self.sort_by_severity = not self.sort_by_severity
|
|
|
|
|
self:setChoices(self.subviews.list:getChoices())
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:setChoices(choices, sel_token)
|
|
|
|
|
if self.sort_by_severity then
|
|
|
|
|
table.sort(choices, function(a,b)
|
|
|
|
|
return a.severity > b.severity
|
|
|
|
|
or (a.severity == b.severity and
|
|
|
|
|
current_stock(a.obj)/a.obj.goal_value < current_stock(b.obj)/b.obj.goal_value)
|
|
|
|
|
end)
|
|
|
|
|
else
|
|
|
|
|
table.sort(choices, function(a,b) return a.search_key < b.search_key end)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local selidx = nil
|
|
|
|
|
if sel_token then
|
|
|
|
|
selidx = utils.linear_index(choices, sel_token, 'token')
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local list = self.subviews.list
|
|
|
|
|
local filter = list:getFilter()
|
|
|
|
|
|
|
|
|
|
list:setChoices(choices, selidx)
|
|
|
|
|
|
|
|
|
|
if filter ~= '' then
|
|
|
|
|
list:setFilter(filter, selidx)
|
|
|
|
|
|
|
|
|
|
if selidx and list:getSelected() ~= selidx then
|
|
|
|
|
list:setFilter('', selidx)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:onInput(keys)
|
|
|
|
|
if keys.LEAVESCREEN then
|
|
|
|
|
self:dismiss()
|
|
|
|
|
else
|
|
|
|
|
ConstraintList.super.onInput(self, keys)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:onNewConstraint()
|
|
|
|
|
NewConstraint{
|
|
|
|
|
on_submit = self:callback('saveConstraint')
|
|
|
|
|
}:show()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:saveConstraint(cons)
|
|
|
|
|
local out = workflow.setConstraint(cons.token, cons.goal_by_count, cons.goal_value, cons.goal_gap)
|
|
|
|
|
self:initListChoices(nil, out.token)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ConstraintList:onDeleteConstraint()
|
|
|
|
|
local cons = self:getCurConstraint()
|
|
|
|
|
dlg.showYesNoPrompt(
|
|
|
|
|
'Delete Constraint',
|
|
|
|
|
'Really delete the current constraint?',
|
|
|
|
|
COLOR_YELLOW,
|
|
|
|
|
function()
|
|
|
|
|
workflow.deleteConstraint(cons.token)
|
|
|
|
|
self:initListChoices()
|
|
|
|
|
end
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-------------------------------
|
|
|
|
|
-- WORKSHOP JOB INFO OVERLAY --
|
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
|
|
JobConstraints = defclass(JobConstraints, guidm.MenuOverlay)
|
|
|
|
|
|
|
|
|
|
JobConstraints.focus_path = 'workflow/job'
|
|
|
|
@ -480,24 +827,12 @@ function JobConstraints:initListChoices(clist, sel_token)
|
|
|
|
|
end
|
|
|
|
|
itemstr = itemstr .. ' ('..table.concat(lst,',')..')'
|
|
|
|
|
end
|
|
|
|
|
local matstr = describe_material(cons)
|
|
|
|
|
local matflagstr = ''
|
|
|
|
|
local matflags = utils.list_bitfield_flags(cons.mat_mask)
|
|
|
|
|
if #matflags > 0 then
|
|
|
|
|
matflags[1] = 'any '..matflags[1]
|
|
|
|
|
if matstr == 'any material' then
|
|
|
|
|
matstr = table.concat(matflags, ', ')
|
|
|
|
|
matflags = {}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if #matflags > 0 then
|
|
|
|
|
matflagstr = table.concat(matflags, ', ')
|
|
|
|
|
end
|
|
|
|
|
local matstr,matflagstr = describe_material(cons)
|
|
|
|
|
|
|
|
|
|
table.insert(choices, {
|
|
|
|
|
text = {
|
|
|
|
|
goal, ' ', { text = '(now '..curval..')', pen = order_pen }, NEWLINE,
|
|
|
|
|
' ', itemstr, NEWLINE, ' ', matstr, NEWLINE, ' ', matflagstr
|
|
|
|
|
' ', itemstr, NEWLINE, ' ', matstr, NEWLINE, ' ', (matflagstr or '')
|
|
|
|
|
},
|
|
|
|
|
token = cons.token,
|
|
|
|
|
obj = cons
|
|
|
|
@ -593,20 +928,25 @@ function JobConstraints:onInput(keys)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/QueryBuilding/Some/Workshop/Job') then
|
|
|
|
|
qerror("This script requires a workshop job selected in the 'q' mode")
|
|
|
|
|
end
|
|
|
|
|
local args = {...}
|
|
|
|
|
|
|
|
|
|
local job = dfhack.gui.getSelectedJob()
|
|
|
|
|
if args[1] == 'list' then
|
|
|
|
|
check_enabled(function() ConstraintList{}:show() end)
|
|
|
|
|
else
|
|
|
|
|
if not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/QueryBuilding/Some/Workshop/Job') then
|
|
|
|
|
qerror("This script requires a workshop job selected in the 'q' mode")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
check_enabled(function()
|
|
|
|
|
check_repeat(job, function()
|
|
|
|
|
local clist = workflow.listConstraints(job)
|
|
|
|
|
if not clist then
|
|
|
|
|
dlg.showMessage('Not Supported', 'This type of job is not supported by workflow.', COLOR_LIGHTRED)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
JobConstraints{ job = job, clist = clist }:show()
|
|
|
|
|
end)
|
|
|
|
|
end)
|
|
|
|
|
local job = dfhack.gui.getSelectedJob()
|
|
|
|
|
|
|
|
|
|
check_enabled(function()
|
|
|
|
|
check_repeat(job, function()
|
|
|
|
|
local clist = workflow.listConstraints(job)
|
|
|
|
|
if not clist then
|
|
|
|
|
dlg.showMessage('Not Supported', 'This type of job is not supported by workflow.', COLOR_LIGHTRED)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
JobConstraints{ job = job, clist = clist }:show()
|
|
|
|
|
end)
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|