diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index e6a9a4d72..0ec92030b 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -216,7 +216,7 @@ local function is_disabled(token) (token.enabled ~= nil and not getval(token.enabled)) end -function render_text(obj,dc,x0,y0,pen,dpen) +function render_text(obj,dc,x0,y0,pen,dpen,disabled) local width = 0 for iline,line in ipairs(obj.text_lines) do local x = 0 @@ -246,7 +246,7 @@ function render_text(obj,dc,x0,y0,pen,dpen) local keypen if dc then - if is_disabled(token) then + if disabled or is_disabled(token) then dc:pen(getval(token.dpen) or dpen) keypen = COLOR_GREEN else @@ -305,6 +305,8 @@ Label = defclass(Label, Widget) Label.ATTRS{ text_pen = COLOR_WHITE, text_dpen = COLOR_DARKGREY, + disabled = DEFAULT_NIL, + enabled = DEFAULT_NIL, auto_height = true, auto_width = false, } @@ -346,11 +348,13 @@ function Label:getTextWidth() end 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 function Label:onInput(keys) - return check_text_keys(self, keys) + if not is_disabled(self) then + return check_text_keys(self, keys) + end end ---------- @@ -376,7 +380,6 @@ SECONDSCROLL = { List.ATTRS{ text_pen = COLOR_CYAN, cursor_pen = COLOR_LIGHTCYAN, - cursor_dpen = DEFAULT_NIL, inactive_pen = DEFAULT_NIL, on_select = DEFAULT_NIL, on_submit = DEFAULT_NIL, @@ -417,7 +420,9 @@ function List:getChoices() end function List:getSelected() - return self.selected, self.choices[self.selected] + if #self.choices > 0 then + return self.selected, self.choices[self.selected] + end end function List:getContentWidth() @@ -485,15 +490,11 @@ function List:onRenderBody(dc) for i = top,iend do local obj = choices[i] local current = (i == self.selected) - local cur_pen = self.text_pen - local cur_dpen = cur_pen + local cur_pen = self.cursor_pen + local cur_dpen = self.text_pen - if current and active then - cur_pen = self.cursor_pen - cur_dpen = self.cursor_dpen or self.text_pen - elseif current then + if not self.active then cur_pen = self.inactive_pen or self.cursor_pen - cur_dpen = self.inactive_pen or self.text_pen end local y = (i - top)*self.row_height @@ -503,11 +504,15 @@ function List:onRenderBody(dc) if type(obj.icon) == 'table' then dc:char(nil,obj.icon) else - dc:string(obj.icon, obj.icon_pen or cur_pen) + if current then + dc:string(obj.icon, obj.icon_pen or cur_pen) + else + dc:string(obj.icon, obj.icon_pen or cur_dpen) + 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 local keystr = gui.getKeyDisplay(obj.key) @@ -620,7 +625,9 @@ end function FilteredList:getSelected() local i,v = self.list:getSelected() - return map_opttab(self.choice_index, i), v + if i then + return map_opttab(self.choice_index, i), v + end end function FilteredList:getContentWidth() diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index b58a0763c..29538b6c9 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -306,8 +306,9 @@ public: void setGoalCount(int v) { config.ival(0) = v; } int goalGap() { - int gcnt = std::max(1, goalCount()/2); - return std::min(gcnt, config.ival(1) <= 0 ? 5 : config.ival(1)); + int cval = (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; } diff --git a/scripts/gui/workflow.lua b/scripts/gui/workflow.lua index 17413d46e..c5d28cb98 100644 --- a/scripts/gui/workflow.lua +++ b/scripts/gui/workflow.lua @@ -36,6 +36,8 @@ JobConstraints.ATTRS { frame_background = COLOR_BLACK, } +local null_cons = { goal_value = 0, goal_gap = 0, goal_by_count = false } + function JobConstraints:init(args) self.building = dfhack.job.getHolder(self.job) @@ -56,13 +58,54 @@ function JobConstraints:init(args) }, widgets.List{ view_id = 'list', - frame = { t = 2, b = 2 }, + frame = { t = 2, b = 6 }, row_height = 4, 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{ frame = { l = 0, b = 0 }, 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', on_activate = self:callback('dismiss') } } @@ -157,7 +200,14 @@ function JobConstraints:initListChoices(clist) local matflags = {} list_flags(matflags, cons.mat_mask) 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 table.insert(choices, { @@ -172,6 +222,84 @@ function JobConstraints:initListChoices(clist) self.subviews.list:setChoices(choices) 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) if self:propagateMoveKeys(keys) then if df.global.world.selected_building ~= self.building then