Add a gui script for viewing and changing job_item properties.

develop
Alexander Gavrilov 2012-10-20 21:57:36 +04:00
parent fbba4caab2
commit dee0c97584
6 changed files with 271 additions and 33 deletions

@ -12,6 +12,7 @@ DFHack future
- removebadthoughts: add --dry-run option
New GUI scripts:
- gui/guide-path: displays the cached path for minecart Guide orders.
- gui/workshop-job: displays inputs of a workshop job and allows tweaking them.
DFHack v0.34.11-r2

@ -75,6 +75,9 @@ keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons
# minecart Guide path
keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path
# workshop job details
# keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job
############################
# UI and game logic tweaks #
############################

@ -238,8 +238,7 @@ function MaterialDialog:submitMaterial(typ, index)
self:dismiss()
if self.on_select then
local info = dfhack.matinfo.decode(typ, index)
self.on_select(info, typ, index)
self.on_select(typ, index)
end
end
@ -276,25 +275,6 @@ function showMaterialPrompt(title, prompt, on_select, on_cancel, mat_filter)
}:show()
end
local itemdefs = df.global.world.raws.itemdefs
local itemtype_info = {
TRAPPARTS = { name = 'mechanisms' },
WEAPON = { defs = itemdefs.weapons },
TRAPCOMP = { defs = itemdefs.trapcomps },
TOY = { defs = itemdefs.toys },
TOOL = { defs = itemdefs.tools },
INSTRUMENT = { defs = itemdefs.instruments },
ARMOR = { defs = itemdefs.armor },
AMMO = { defs = itemdefs.ammo },
SIEGEAMMO = { defs = itemdefs.siege_ammo },
GLOVES = { defs = itemdefs.gloves },
SHOES = { defs = itemdefs.shoes },
SHIELD = { defs = itemdefs.shields },
HELM = { defs = itemdefs.helms },
PANTS = { defs = itemdefs.pants },
FOOD = { defs = itemdefs.food },
}
function ItemTypeDialog(args)
args.text = args.prompt or 'Type or select an item type'
args.text_pen = COLOR_WHITE
@ -307,26 +287,24 @@ function ItemTypeDialog(args)
local filter = args.item_filter
for itype = 0,df.item_type._last_item do
local key = df.item_type[itype]
local info = itemtype_info[key]
local attrs = df.item_type.attrs[itype]
local defcnt = dfhack.items.getSubtypeCount(itype)
if not filter or filter(itype,-1) then
local name = key
local name = attrs.caption or df.item_type[itype]
local icon
if info and info.defs then
if defcnt >= 0 then
name = 'any '..name
icon = '+'
end
if info and info.name then
name = info.name
end
table.insert(choices, {
icon = icon, text = string.lower(name), item_type = itype, item_subtype = -1
})
end
if info and info.defs then
for subtype,def in ipairs(info.defs) do
if defcnt > 0 then
for subtype = 0,defcnt-1 do
local def = dfhack.items.getSubtypeDef(itype, subtype)
if not filter or filter(itype,subtype,def) then
table.insert(choices, {
icon = '\x1e', text = ' '..def.name, item_type = itype, item_subtype = subtype
@ -338,6 +316,13 @@ function ItemTypeDialog(args)
args.choices = choices
if args.on_select then
local cb = args.on_select
args.on_select = function(idx, obj)
return cb(obj.item_type, obj.item_subtype)
end
end
return dlg.ListBox(args)
end

@ -211,6 +211,11 @@ function parse_label_text(obj)
obj.text_ids = idtab
end
local function is_disabled(token)
return (token.disabled ~= nil and getval(token.disabled)) or
(token.enabled ~= nil and not getval(token.enabled))
end
function render_text(obj,dc,x0,y0,pen,dpen)
local width = 0
for iline,line in ipairs(obj.text_lines) do
@ -241,7 +246,7 @@ function render_text(obj,dc,x0,y0,pen,dpen)
local keypen
if dc then
if getval(token.disabled) then
if is_disabled(token) then
dc:pen(getval(token.dpen) or dpen)
keypen = COLOR_GREEN
else
@ -287,7 +292,7 @@ end
function check_text_keys(self, keys)
if self.text_active then
for _,item in ipairs(self.text_active) do
if item.key and keys[item.key] and not getval(item.disabled) then
if item.key and keys[item.key] and not is_disabled(item) then
item.on_activate()
return true
end
@ -361,6 +366,13 @@ STANDARDSCROLL = {
STANDARDSCROLL_PAGEDOWN = '+page',
}
SECONDSCROLL = {
SECONDSCROLL_UP = -1,
SECONDSCROLL_DOWN = 1,
SECONDSCROLL_PAGEUP = '-page',
SECONDSCROLL_PAGEDOWN = '+page',
}
List.ATTRS{
text_pen = COLOR_CYAN,
cursor_pen = COLOR_LIGHTCYAN,

@ -1 +1 @@
Subproject commit 0ed2d1dc5547737fbb838568fc66671098f2c11a
Subproject commit b9b2e8c6d2141f13966ed965b3f3ffe924e527db

@ -0,0 +1,237 @@
-- Show and modify properties of jobs in a workshop.
local utils = require 'utils'
local gui = require 'gui'
local guidm = require 'gui.dwarfmode'
local guimat = require 'gui.materials'
local widgets = require 'gui.widgets'
local dlg = require 'gui.dialogs'
JobDetails = defclass(JobDetails, guidm.MenuOverlay)
JobDetails.focus_path = 'workshop-job'
JobDetails.ATTRS {
job = DEFAULT_NIL,
frame_inset = 1,
frame_background = COLOR_BLACK,
}
function JobDetails:init(args)
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.unit.getVisibleName(worker)), pen = COLOR_GREEN }
end
self:addviews{
widgets.Label{
frame = { l = 0, t = 0 },
text = {
{ text = df.job_type.attrs[self.job.job_type].caption }, NEWLINE, NEWLINE,
' ', status
}
},
widgets.Label{
frame = { l = 0, t = 4 },
text = {
{ key = 'CUSTOM_I', text = ': Input item, ',
enabled = self:callback('canChangeIType'),
on_activate = self:callback('onChangeIType') },
{ key = 'CUSTOM_M', text = ': Material',
enabled = self:callback('canChangeMat'),
on_activate = self:callback('onChangeMat') }
}
},
widgets.List{
view_id = 'list',
frame = { t = 6, b = 2 },
row_height = 4,
scroll_keys = widgets.SECONDSCROLL,
},
widgets.Label{
frame = { l = 0, b = 0 },
text = {
{ key = 'LEAVESCREEN', text = ': Back',
on_activate = self:callback('dismiss') }
}
},
}
self:initListChoices()
end
function describe_item_type(iobj)
local itemline = 'any item'
if iobj.item_type >= 0 then
itemline = df.item_type.attrs[iobj.item_type].caption or iobj.item_type
local def = dfhack.items.getSubtypeDef(iobj.item_type, iobj.item_subtype)
local count = dfhack.items.getSubtypeCount(iobj.item_type, iobj.item_subtype)
if def then
itemline = def.name
elseif count >= 0 then
itemline = 'any '..itemline
end
end
return itemline
end
function is_caste_mat(iobj)
if iobj.item_type >= 0 then
return df.item_type.attrs[iobj.item_type].is_caste_mat
end
return false
end
function describe_material(iobj)
local matline = 'any material'
if is_caste_mat(iobj) then
matline = 'material not applicable'
elseif iobj.mat_type >= 0 then
local info = dfhack.matinfo.decode(iobj.mat_type, iobj.mat_index)
if info then
matline = info:toString()
else
matline = iobj.mat_type..':'..iobj.mat_index
end
end
return matline
end
function list_flags(list, bitfield)
for name,val in pairs(bitfield) do
if val then
table.insert(list, name)
end
end
end
function JobDetails:initListChoices()
local items = {}
for i,ref in ipairs(self.job.items) do
local idx = ref.job_item_idx
if idx >= 0 then
items[idx] = (items[idx] or 0) + 1
end
end
local choices = {}
for i,iobj in ipairs(self.job.job_items) do
local head = 'Item '..(i+1)..': '..(items[idx] or 0)..' of '..iobj.quantity
if iobj.min_dimension > 0 then
head = head .. '(size '..iobj.min_dimension..')'
end
local line1 = {}
local reaction = df.reaction.find(iobj.reaction_id)
if reaction and #iobj.contains > 0 then
for _,ri in ipairs(iobj.contains) do
table.insert(line1, 'has '..utils.call_with_string(
reaction.reagents[ri],'getDescription',iobj.reaction_id
))
end
end
if iobj.metal_ore >= 0 then
local ore = dfhack.matinfo.decode(0, iobj.metal_ore)
if ore then
table.insert(line1, 'ore of '..ore:toString())
end
end
if iobj.has_material_reaction_product ~= '' then
table.insert(line1, 'product '..iobj.has_material_reaction_product)
end
if iobj.reaction_class ~= '' then
table.insert(line1, 'class '..iobj.reaction_class)
end
if iobj.has_tool_use >= 0 then
table.insert(line1, 'has use '..df.tool_uses[iobj.has_tool_use])
end
list_flags(line1, iobj.flags1)
list_flags(line1, iobj.flags2)
list_flags(line1, iobj.flags3)
if #line1 == 0 then
table.insert(line1, 'no flags')
end
table.insert(choices, {
index = i,
iobj = iobj,
text = {
head, NEWLINE,
' ', { text = curry(describe_item_type, iobj) }, NEWLINE,
' ', { text = curry(describe_material, iobj) }, NEWLINE,
' ', table.concat(line1, ', '), NEWLINE
}
})
end
self.subviews.list:setChoices(choices)
end
function JobDetails:canChangeIType()
local idx, obj = self.subviews.list:getSelected()
return obj ~= nil
end
function JobDetails:onChangeIType()
local idx, obj = self.subviews.list:getSelected()
guimat.ItemTypeDialog{
prompt = 'Please select a new item type for input '..idx,
none_caption = 'any item',
item_filter = curry(dfhack.job.isSuitableItem, obj.iobj),
on_select = function(item_type, item_subtype)
obj.iobj.item_type = item_type
obj.iobj.item_subtype = item_subtype
end
}:show()
end
function JobDetails:canChangeMat()
local idx, obj = self.subviews.list:getSelected()
return obj ~= nil and not is_caste_mat(obj.iobj)
end
function JobDetails:onChangeMat()
local idx, obj = self.subviews.list:getSelected()
if obj.iobj.item_type == -1 and obj.iobj.mat_type == -1 then
dlg.showMessage(
'Bug Alert',
{ 'Please set a specific item type first.\n\n',
'Otherwise the material will be matched\n',
'incorrectly due to a limitation in DF code.' },
COLOR_YELLOW
)
return
end
guimat.MaterialDialog{
prompt = 'Please select a new material for input '..idx,
none_caption = 'any material',
mat_filter = function(mat,parent,mat_type,mat_index)
return dfhack.job.isSuitableMaterial(obj.iobj, mat_type, mat_index)
end,
on_select = function(mat_type, mat_index)
if idx == 1
and self.job.mat_type == obj.iobj.mat_type
and self.job.mat_index == obj.iobj.mat_index
and self.job.job_type ~= df.job_type.PrepareMeal
then
self.job.mat_type = mat_type
self.job.mat_index = mat_index
end
obj.iobj.mat_type = mat_type
obj.iobj.mat_index = mat_index
end
}:show()
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 dlg = JobDetails{ job = dfhack.gui.getSelectedJob() }
dlg:show()