Support changing the constraint ranges from the workflow gui script.

TODO: implement creating completely new constraints.
develop
Alexander Gavrilov 2012-10-24 19:25:06 +04:00
parent cd852e2240
commit 616c57257d
3 changed files with 156 additions and 20 deletions

@ -216,7 +216,7 @@ local function is_disabled(token)
(token.enabled ~= nil and not getval(token.enabled)) (token.enabled ~= nil and not getval(token.enabled))
end end
function render_text(obj,dc,x0,y0,pen,dpen) function render_text(obj,dc,x0,y0,pen,dpen,disabled)
local width = 0 local width = 0
for iline,line in ipairs(obj.text_lines) do for iline,line in ipairs(obj.text_lines) do
local x = 0 local x = 0
@ -246,7 +246,7 @@ function render_text(obj,dc,x0,y0,pen,dpen)
local keypen local keypen
if dc then if dc then
if is_disabled(token) then if disabled or is_disabled(token) then
dc:pen(getval(token.dpen) or dpen) dc:pen(getval(token.dpen) or dpen)
keypen = COLOR_GREEN keypen = COLOR_GREEN
else else
@ -305,6 +305,8 @@ Label = defclass(Label, Widget)
Label.ATTRS{ Label.ATTRS{
text_pen = COLOR_WHITE, text_pen = COLOR_WHITE,
text_dpen = COLOR_DARKGREY, text_dpen = COLOR_DARKGREY,
disabled = DEFAULT_NIL,
enabled = DEFAULT_NIL,
auto_height = true, auto_height = true,
auto_width = false, auto_width = false,
} }
@ -346,12 +348,14 @@ function Label:getTextWidth()
end end
function Label:onRenderBody(dc) function Label:onRenderBody(dc)
render_text(self,dc,0,0,self.text_pen,self.text_dpen) render_text(self,dc,0,0,self.text_pen,self.text_dpen,is_disabled(self))
end end
function Label:onInput(keys) function Label:onInput(keys)
if not is_disabled(self) then
return check_text_keys(self, keys) return check_text_keys(self, keys)
end end
end
---------- ----------
-- List -- -- List --
@ -376,7 +380,6 @@ SECONDSCROLL = {
List.ATTRS{ List.ATTRS{
text_pen = COLOR_CYAN, text_pen = COLOR_CYAN,
cursor_pen = COLOR_LIGHTCYAN, cursor_pen = COLOR_LIGHTCYAN,
cursor_dpen = DEFAULT_NIL,
inactive_pen = DEFAULT_NIL, inactive_pen = DEFAULT_NIL,
on_select = DEFAULT_NIL, on_select = DEFAULT_NIL,
on_submit = DEFAULT_NIL, on_submit = DEFAULT_NIL,
@ -417,8 +420,10 @@ function List:getChoices()
end end
function List:getSelected() function List:getSelected()
if #self.choices > 0 then
return self.selected, self.choices[self.selected] return self.selected, self.choices[self.selected]
end end
end
function List:getContentWidth() function List:getContentWidth()
local width = 0 local width = 0
@ -485,15 +490,11 @@ function List:onRenderBody(dc)
for i = top,iend do for i = top,iend do
local obj = choices[i] local obj = choices[i]
local current = (i == self.selected) local current = (i == self.selected)
local cur_pen = self.text_pen local cur_pen = self.cursor_pen
local cur_dpen = cur_pen local cur_dpen = self.text_pen
if current and active then if not self.active then
cur_pen = self.cursor_pen
cur_dpen = self.cursor_dpen or self.text_pen
elseif current then
cur_pen = self.inactive_pen or self.cursor_pen cur_pen = self.inactive_pen or self.cursor_pen
cur_dpen = self.inactive_pen or self.text_pen
end end
local y = (i - top)*self.row_height local y = (i - top)*self.row_height
@ -503,11 +504,15 @@ function List:onRenderBody(dc)
if type(obj.icon) == 'table' then if type(obj.icon) == 'table' then
dc:char(nil,obj.icon) dc:char(nil,obj.icon)
else else
if current then
dc:string(obj.icon, obj.icon_pen or cur_pen) dc:string(obj.icon, obj.icon_pen or cur_pen)
else
dc:string(obj.icon, obj.icon_pen or cur_dpen)
end
end end
end end
render_text(obj, dc, iw or 0, y, cur_pen, cur_dpen) render_text(obj, dc, iw or 0, y, cur_pen, cur_dpen, not current)
if obj.key then if obj.key then
local keystr = gui.getKeyDisplay(obj.key) local keystr = gui.getKeyDisplay(obj.key)
@ -620,8 +625,10 @@ end
function FilteredList:getSelected() function FilteredList:getSelected()
local i,v = self.list:getSelected() local i,v = self.list:getSelected()
if i then
return map_opttab(self.choice_index, i), v return map_opttab(self.choice_index, i), v
end end
end
function FilteredList:getContentWidth() function FilteredList:getContentWidth()
return self.list:getContentWidth() return self.list:getContentWidth()

@ -306,8 +306,9 @@ public:
void setGoalCount(int v) { config.ival(0) = v; } void setGoalCount(int v) { config.ival(0) = v; }
int goalGap() { int goalGap() {
int gcnt = std::max(1, goalCount()/2); int cval = (config.ival(1) <= 0) ? 5 : config.ival(1);
return std::min(gcnt, config.ival(1) <= 0 ? 5 : config.ival(1)); int cmax = std::max(goalCount()-5, goalCount()/2);
return std::max(1, std::min(cmax, cval));
} }
void setGoalGap(int v) { config.ival(1) = v; } void setGoalGap(int v) { config.ival(1) = v; }

@ -36,6 +36,8 @@ JobConstraints.ATTRS {
frame_background = COLOR_BLACK, frame_background = COLOR_BLACK,
} }
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)
@ -56,13 +58,54 @@ function JobConstraints:init(args)
}, },
widgets.List{ widgets.List{
view_id = 'list', view_id = 'list',
frame = { t = 2, b = 2 }, frame = { t = 2, b = 6 },
row_height = 4, row_height = 4,
scroll_keys = widgets.SECONDSCROLL, scroll_keys = widgets.SECONDSCROLL,
}, },
widgets.Label{
frame = { l = 0, b = 3 },
enabled = self:callback('isAnySelected'),
text = {
{ key = 'BUILDING_TRIGGER_ENABLE_CREATURE',
text = function()
local cons = self:getCurConstraint() or null_cons
if cons.goal_by_count then
return ': Count stacks '
else
return ': Count items '
end
end,
on_activate = self:callback('onChangeUnit') },
{ key = 'BUILDING_TRIGGER_ENABLE_MAGMA', text = ': Modify',
on_activate = self:callback('onEditRange') },
NEWLINE, ' ',
{ key = 'BUILDING_TRIGGER_MIN_SIZE_DOWN',
on_activate = self:callback('onIncRange', 'goal_gap', 5) },
{ key = 'BUILDING_TRIGGER_MIN_SIZE_UP',
on_activate = self:callback('onIncRange', 'goal_gap', -1) },
{ text = function()
local cons = self:getCurConstraint() or null_cons
return string.format(': Min %-4d ', cons.goal_value - cons.goal_gap)
end },
{ key = 'BUILDING_TRIGGER_MAX_SIZE_DOWN',
on_activate = self:callback('onIncRange', 'goal_value', -1) },
{ key = 'BUILDING_TRIGGER_MAX_SIZE_UP',
on_activate = self:callback('onIncRange', 'goal_value', 5) },
{ text = function()
local cons = self:getCurConstraint() or null_cons
return string.format(': Max %-4d', cons.goal_value)
end },
}
},
widgets.Label{ widgets.Label{
frame = { l = 0, b = 0 }, frame = { l = 0, b = 0 },
text = { text = {
{ key = 'CUSTOM_N', text = ': New limit, ',
on_activate = self:callback('onNewConstraint') },
{ key = 'CUSTOM_X', text = ': Delete',
enabled = self:callback('isAnySelected'),
on_activate = self:callback('onDeleteConstraint') },
NEWLINE, NEWLINE,
{ key = 'LEAVESCREEN', text = ': Back', { key = 'LEAVESCREEN', text = ': Back',
on_activate = self:callback('dismiss') } on_activate = self:callback('dismiss') }
} }
@ -157,7 +200,14 @@ function JobConstraints:initListChoices(clist)
local matflags = {} local matflags = {}
list_flags(matflags, cons.mat_mask) list_flags(matflags, cons.mat_mask)
if #matflags > 0 then if #matflags > 0 then
matflagstr = 'class: '..table.concat(matflags, ', ') 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 end
table.insert(choices, { table.insert(choices, {
@ -172,6 +222,84 @@ function JobConstraints:initListChoices(clist)
self.subviews.list:setChoices(choices) self.subviews.list:setChoices(choices)
end end
function JobConstraints:isAnySelected()
return self.subviews.list:getSelected() ~= nil
end
function JobConstraints:getCurConstraint()
local i,v = self.subviews.list:getSelected()
if v then return v.obj 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)
workflow.setConstraint(cons.token, cons.goal_by_count, cons.goal_value, cons.goal_gap)
self:initListChoices()
end
function JobConstraints:onChangeUnit()
local cons = self:getCurConstraint()
cons.goal_by_count = not cons.goal_by_count
self:saveConstraint(cons)
end
function JobConstraints:onEditRange()
local cons = self:getCurConstraint()
dlg.showInputPrompt(
'Input Range',
'Enter the new constraint range:',
COLOR_WHITE,
(cons.goal_value-cons.goal_gap)..'-'..cons.goal_value,
function(text)
local maxv = string.match(text, '^%s*(%d+)%s*$')
if maxv then
cons.goal_value = maxv
return self:saveConstraint(cons)
end
local minv,maxv = string.match(text, '^%s*(%d+)-(%d+)%s*$')
if minv and maxv and minv ~= maxv then
cons.goal_value = math.max(minv,maxv)
cons.goal_gap = math.abs(maxv-minv)
return self:saveConstraint(cons)
end
dlg.showMessage('Invalid Range', 'This range is invalid: '..text, COLOR_LIGHTRED)
end
)
end
function JobConstraints:onIncRange(field, delta)
local cons = self:getCurConstraint()
if not cons.goal_by_count then
delta = delta * 5
end
cons[field] = math.max(1, cons[field] + delta)
self:saveConstraint(cons)
end
function JobConstraints:onNewConstraint()
end
function JobConstraints: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
function JobConstraints:onInput(keys) function JobConstraints:onInput(keys)
if self:propagateMoveKeys(keys) then if self:propagateMoveKeys(keys) then
if df.global.world.selected_building ~= self.building then if df.global.world.selected_building ~= self.building then