Skip to content

Commit

Permalink
Merge pull request #808 from myk002/myk_trade
Browse files Browse the repository at this point in the history
[caravan] make search field per-goods list
  • Loading branch information
myk002 authored Aug 31, 2023
2 parents 7b6ed83 + 56538fb commit 3ed41e4
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 23 deletions.
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

0 comments on commit 3ed41e4

Please sign in to comment.