Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[caravan] make search field per-goods list #808

Merged
merged 5 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion internal/caravan/common.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--@ module = true

local dialogs = require('gui.dialogs')
local predicates = reqscript('internal/caravan/predicates')
local widgets = require('gui.widgets')

CH_UP = string.char(30)
Expand Down Expand Up @@ -457,7 +458,50 @@ local function get_ethics_token(animal_ethics, wood_ethics)
}
end

function get_info_widgets(self, export_agreements)
function get_advanced_filter_widgets(self, context)
predicates.init_context_predicates(context)
local predicate_str = predicates.make_predicate_str(context)

return {
--[[
widgets.Label{
frame={t=0, l=0},
text='Advanced filter:',
},
widgets.HotkeyLabel{
frame={t=0, l=18, w=9},
key='CUSTOM_SHIFT_J',
label='[edit]',
on_activate=function()
predicates.customize_predicates(context,
function()
predicate_str = predicates.make_predicate_str(context)
self:refresh_list()
end)
end,
},
widgets.HotkeyLabel{
frame={t=0, l=29, w=10},
key='CUSTOM_SHIFT_K',
label='[clear]',
text_pen=COLOR_LIGHTRED,
on_activate=function()
context.predicates = {}
predicate_str = predicates.make_predicate_str(context)
self:refresh_list()
end,
enabled=function() return next(context) end,
},
widgets.Label{
frame={t=1, l=2},
text={{text=function() return predicate_str end}},
text_pen=COLOR_GREEN,
},
--]]
}
end

function get_info_widgets(self, export_agreements, context)
return {
widgets.Panel{
frame={t=0, l=0, r=0, h=2},
Expand Down Expand Up @@ -546,6 +590,10 @@ function get_info_widgets(self, export_agreements)
},
},
},
widgets.Panel{
frame={t=13, l=0, r=0, h=2},
subviews=get_advanced_filter_widgets(self, context),
},
}
end

Expand Down
8 changes: 7 additions & 1 deletion internal/caravan/movegoods.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
local common = reqscript('internal/caravan/common')
local gui = require('gui')
local overlay = require('plugins.overlay')
local predicates = reqscript('internal/caravan/predicates')
local utils = require('utils')
local widgets = require('gui.widgets')

Expand Down Expand Up @@ -132,6 +133,8 @@ function MoveGoods:init()
self.risky_items = common.get_risky_items(self.banned_items)
self.choices_cache = {}

self.predicate_context = {name='movegoods'}

self:addviews{
widgets.CycleHotkeyLabel{
view_id='sort',
Expand Down Expand Up @@ -175,7 +178,7 @@ function MoveGoods:init()
},
widgets.Panel{
frame={t=4, l=40, r=0, h=12},
subviews=common.get_info_widgets(self, get_export_agreements()),
subviews=common.get_info_widgets(self, get_export_agreements(), self.predicate_context),
},
widgets.Panel{
frame={t=17, l=0, r=0, b=6},
Expand Down Expand Up @@ -572,6 +575,9 @@ function MoveGoods:get_choices()
goto continue
end
end
if not predicates.pass_predicates(self.predicate_context, data.item) then
goto continue
end
table.insert(choices, choice)
::continue::
end
Expand Down
125 changes: 125 additions & 0 deletions internal/caravan/predicates.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
--@ module = true

local gui = require('gui')
local scriptmanager = require('script-manager')
local widgets = require('gui.widgets')

local function to_item_type_str(item_type)
return string.lower(df.item_type[item_type]):gsub('_', ' ')
end

local PREDICATE_LIBRARY = {
{name='weapons-grade metal', match=function(item)
if item:getMaterial() ~= 0 then return false end
local flags = df.global.world.raws.inorganics[item:getMaterialIndex()].material.flags
return flags.IS_METAL and
(flags.ITEMS_METAL or flags.ITEMS_WEAPON or flags.ITEMS_WEAPON_RANGED or flags.ITEMS_AMMO or flags.ITEMS_ARMOR)
end},
}
for _,item_type in ipairs(df.item_type) do
table.insert(PREDICATE_LIBRARY, {
name=to_item_type_str(item_type),
group='item type',
match=function(item) return item_type == item:getType() end,
})
end

local PREDICATES_VAR = 'ITEM_PREDICATES'

local function get_user_predicates()
local user_predicates = {}
local load_user_predicates = function(env_name, env)
local predicates = env[PREDICATES_VAR]
if not predicates then return end
if type(predicates) ~= 'table' then
dfhack.printerr(
('error loading predicates from "%s": %s map is malformed')
:format(env_name, PREDICATES_VAR))
return
end
for i,predicate in ipairs(predicates) do
if type(predicate) ~= 'table' then
dfhack.printerr(('error loading predicate %s:%d (must be a table)'):format(env_name, i))
goto continue
end
if type(predicate.name) ~= 'string' or #predicate.name == 0 then
dfhack.printerr(('error loading predicate %s:%d (must have a string "name" field)'):format(env_name, i))
goto continue
end
if type(predicate.match) ~= 'function' then
dfhack.printerr(('error loading predicate %s:%d (must have a function "match" field)'):format(env_name, i))
goto continue
end
table.insert(user_predicates, {id=('%s:%s'):format(env_name, predicate.name), name=predicate.name, match=predicate.match})
::continue::
end
end
scriptmanager.foreach_module_script(load_user_predicates)
return user_predicates
end

function make_predicate_str(context)
local preset, names = nil, {}
for name, predicate in pairs(context.predicates) do
if not preset then
preset = predicate.preset or ''
end
if #preset > 0 and preset ~= predicate.preset then
preset = ''
end
table.insert(names, name)
end
if preset and #preset > 0 then
return preset
end
if #names > 0 then
return table.concat(names, ', ')
end
return 'All'
end

function init_context_predicates(context)
-- TODO: init according to saved preferences associated with context.name
context.predicates = {}
end

function pass_predicates(context, item)
for _,predicate in pairs(context.predicates) do
local ok, matches = safecall(predicate.match, item)
if not ok then goto continue end
if matches ~= predicate.invert then return false end
::continue::
end
return true
end

AdvancedFilter = defclass(AdvancedFilter, widgets.Window)
AdvancedFilter.ATTRS {
frame_title='Advanced item filters',
frame={w=50, h=45},
resizable=true,
resize_min={w=50, h=20},
context=DEFAULT_NIL,
on_change=DEFAULT_NIL,
}

function AdvancedFilter:init()
self:addviews{
}
end

AdvancedFilterScreen = defclass(AdvancedFilterScreen, gui.ZScreenModal)
AdvancedFilterScreen.ATTRS {
focus_path='advanced_item_filter',
context=DEFAULT_NIL,
on_change=DEFAULT_NIL,
}

function AdvancedFilterScreen:init()
self:addviews{AdvancedFilter{context=self.context, on_change=self.on_change}}
end

function customize_predicates(context, on_change)
context.user_predicates = context.user_predicates or get_user_predicates()
AdvancedFilterScreen{context=context, on_change=on_change}:show()
end
56 changes: 35 additions & 21 deletions internal/caravan/trade.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
local common = reqscript('internal/caravan/common')
local gui = require('gui')
local overlay = require('plugins.overlay')
local predicates = reqscript('internal/caravan/predicates')
local widgets = require('gui.widgets')

trader_selected_state = trader_selected_state or {}
Expand Down Expand Up @@ -142,6 +143,8 @@ local FILTER_HEIGHT = 15

function Trade:init()
self.cur_page = 1
self.filters = {'', ''}
self.predicate_contexts = {{name='trade_caravan'}, {name='trade_fort'}}

self.animal_ethics = common.is_animal_lover_caravan(trade.mer)
self.wood_ethics = common.is_tree_lover_caravan(trade.mer)
Expand All @@ -151,7 +154,7 @@ function Trade:init()
self:addviews{
widgets.CycleHotkeyLabel{
view_id='sort',
frame={l=0, t=0, w=21},
frame={t=0, l=0, w=21},
label='Sort by:',
key='CUSTOM_SHIFT_S',
options={
Expand All @@ -165,15 +168,9 @@ function Trade:init()
initial_option=sort_by_status_desc,
on_change=self:callback('refresh_list', 'sort'),
},
widgets.EditField{
view_id='search',
frame={l=26, t=0},
label_text='Search: ',
on_char=function(ch) return ch:match('[%l -]') end,
},
widgets.ToggleHotkeyLabel{
view_id='trade_bins',
frame={t=2, l=0, w=36},
frame={t=0, l=26, w=36},
label='Bins:',
key='CUSTOM_SHIFT_B',
options={
Expand All @@ -183,9 +180,24 @@ function Trade:init()
initial_option=false,
on_change=function() self:refresh_list() end,
},
widgets.TabBar{
frame={t=2, l=0},
labels={
'Caravan goods',
'Fort goods',
},
on_select=function(idx)
local list = self.subviews.list
self.filters[self.cur_page] = list:getFilter()
list:setFilter(self.filters[idx])
self.cur_page = idx
self:refresh_list()
end,
get_cur_page=function() return self.cur_page end,
},
widgets.ToggleHotkeyLabel{
view_id='filters',
frame={t=2, l=40, w=36},
frame={t=5, l=0, w=36},
label='Show filters:',
key='CUSTOM_SHIFT_F',
options={
Expand All @@ -195,17 +207,11 @@ function Trade:init()
initial_option=false,
on_change=function() self:updateLayout() end,
},
widgets.TabBar{
frame={t=4, l=0},
labels={
'Caravan goods',
'Fort goods',
},
on_select=function(idx)
self.cur_page = idx
self:refresh_list()
end,
get_cur_page=function() return self.cur_page end,
widgets.EditField{
view_id='search',
frame={t=5, l=40},
label_text='Search: ',
on_char=function(ch) return ch:match('[%l -]') end,
},
widgets.Panel{
frame={t=7, l=0, r=0, h=FILTER_HEIGHT},
Expand All @@ -229,10 +235,15 @@ function Trade:init()
visible=function() return self.cur_page == 2 end,
subviews=common.get_slider_widgets(self, '2'),
},
widgets.Panel{
frame={b=0, l=40, r=0, h=2},
visible=function() return self.cur_page == 1 end,
subviews=common.get_advanced_filter_widgets(self, self.predicate_contexts[1]),
},
widgets.Panel{
frame={t=2, l=40, r=0, h=FILTER_HEIGHT-2},
visible=function() return self.cur_page == 2 end,
subviews=common.get_info_widgets(self, {trade.mer.buy_prices}),
subviews=common.get_info_widgets(self, {trade.mer.buy_prices}, self.predicate_contexts[2]),
},
},
},
Expand Down Expand Up @@ -438,6 +449,9 @@ function Trade:get_choices()
goto continue
end
end
if not predicates.pass_predicates(self.predicate_contexts[self.cur_page], data.item) then
goto continue
end
table.insert(choices, choice)
::continue::
end
Expand Down