allow material filter to be read and set

develop
Myk Taylor 2023-03-05 18:17:10 -08:00
parent 0562dc5234
commit 2a2141931f
No known key found for this signature in database
2 changed files with 103 additions and 80 deletions

@ -144,12 +144,12 @@ static const vector<const df::job_item *> & get_job_items(color_ostream &out, Bu
return jitems; return jitems;
} }
static void cache_matched(int16_t type, int32_t index) {
static const df::dfhack_material_category stone_cat(df::dfhack_material_category::mask_stone); static const df::dfhack_material_category stone_cat(df::dfhack_material_category::mask_stone);
static const df::dfhack_material_category wood_cat(df::dfhack_material_category::mask_wood); static const df::dfhack_material_category wood_cat(df::dfhack_material_category::mask_wood);
static const df::dfhack_material_category metal_cat(df::dfhack_material_category::mask_metal); static const df::dfhack_material_category metal_cat(df::dfhack_material_category::mask_metal);
static const df::dfhack_material_category other_cat(df::dfhack_material_category::mask_glass | df::dfhack_material_category::mask_soap); static const df::dfhack_material_category glass_cat(df::dfhack_material_category::mask_glass);
static void cache_matched(int16_t type, int32_t index) {
MaterialInfo mi; MaterialInfo mi;
mi.decode(type, index); mi.decode(type, index);
if (mi.matches(stone_cat)) { if (mi.matches(stone_cat)) {
@ -161,9 +161,9 @@ static void cache_matched(int16_t type, int32_t index) {
} else if (mi.matches(metal_cat)) { } else if (mi.matches(metal_cat)) {
DEBUG(status).print("cached metal material: %s\n", mi.toString().c_str()); DEBUG(status).print("cached metal material: %s\n", mi.toString().c_str());
mat_cache.emplace(mi.toString(), std::make_pair(mi, "metal")); mat_cache.emplace(mi.toString(), std::make_pair(mi, "metal"));
} else if (mi.matches(other_cat)) { } else if (mi.matches(glass_cat)) {
DEBUG(status).print("cached other material: %s\n", mi.toString().c_str()); DEBUG(status).print("cached glass material: %s\n", mi.toString().c_str());
mat_cache.emplace(mi.toString(), std::make_pair(mi, "other")); mat_cache.emplace(mi.toString(), std::make_pair(mi, "glass"));
} }
else else
TRACE(status).print("not matched: %s\n", mi.toString().c_str()); TRACE(status).print("not matched: %s\n", mi.toString().c_str());
@ -729,19 +729,30 @@ static int setMaterialMaskFilter(lua_State *L) {
Lua::GetVector(L, cats, 5); Lua::GetVector(L, cats, 5);
for (auto &cat : cats) { for (auto &cat : cats) {
if (cat == "stone") if (cat == "stone")
mask |= df::dfhack_material_category::mask_stone; mask |= stone_cat.whole;
else if (cat == "wood") else if (cat == "wood")
mask |= df::dfhack_material_category::mask_wood; mask |= wood_cat.whole;
else if (cat == "metal") else if (cat == "metal")
mask |= df::dfhack_material_category::mask_metal; mask |= metal_cat.whole;
else if (cat == "other") else if (cat == "glass")
mask |= df::dfhack_material_category::mask_glass | df::dfhack_material_category::mask_soap; mask |= glass_cat.whole;
} }
DEBUG(status,*out).print( DEBUG(status,*out).print(
"setting material mask filter for building_type=%d subtype=%d custom=%d index=%d to %x\n", "setting material mask filter for building_type=%d subtype=%d custom=%d index=%d to %x\n",
type, subtype, custom, index, mask); type, subtype, custom, index, mask);
ItemFilter filter = filters[index]; ItemFilter filter = filters[index];
filter.setMaterialMask(mask); filter.setMaterialMask(mask);
if (mask) {
// remove materials from the list that don't match the mask
const auto &mats = filter.getMaterials();
set<MaterialInfo> new_mats;
const df::dfhack_material_category mat_mask(mask);
for (auto & mat : mats) {
if (mat.matches(mat_mask))
new_mats.emplace(mat);
}
filter.setMaterials(new_mats);
}
get_item_filters(*out, key).setItemFilter(*out, filter, index); get_item_filters(*out, key).setItemFilter(*out, filter, index);
call_buildingplan_lua(out, "signal_reset"); call_buildingplan_lua(out, "signal_reset");
return 0; return 0;
@ -762,17 +773,14 @@ static int getMaterialMaskFilter(lua_State *L) {
auto &filters = get_item_filters(*out, key); auto &filters = get_item_filters(*out, key);
if (index < 0 || filters.getItemFilters().size() <= (size_t)index) if (index < 0 || filters.getItemFilters().size() <= (size_t)index)
return 0; return 0;
vector<string> cat_names; map<string, bool> ret;
uint32_t bits = filters.getItemFilters()[index].getMaterialMask().whole; uint32_t bits = filters.getItemFilters()[index].getMaterialMask().whole;
if (!bits || bits & df::dfhack_material_category::mask_stone) ret.emplace("unset", !bits);
cat_names.emplace_back("stone"); ret.emplace("stone", !bits || bits & stone_cat.whole);
if (!bits || bits & df::dfhack_material_category::mask_wood) ret.emplace("wood", !bits || bits & wood_cat.whole);
cat_names.emplace_back("wood"); ret.emplace("metal", !bits || bits & metal_cat.whole);
if (!bits || bits & df::dfhack_material_category::mask_metal) ret.emplace("glass", !bits || bits & glass_cat.whole);
cat_names.emplace_back("metal"); Lua::Push(L, ret);
if (!bits || bits & (df::dfhack_material_category::mask_glass | df::dfhack_material_category::mask_soap))
cat_names.emplace_back("other");
Lua::PushVector(L, cat_names);
return 1; return 1;
} }
@ -793,7 +801,7 @@ static int setMaterialFilter(lua_State *L) {
return 0; return 0;
set<MaterialInfo> mats; set<MaterialInfo> mats;
vector<string> matstrs; vector<string> matstrs;
Lua::GetVector(L, matstrs); Lua::GetVector(L, matstrs, 5);
for (auto &mat : matstrs) { for (auto &mat : matstrs) {
if (mat_cache.count(mat)) if (mat_cache.count(mat))
mats.emplace(mat_cache.at(mat).first); mats.emplace(mat_cache.at(mat).first);
@ -803,6 +811,19 @@ static int setMaterialFilter(lua_State *L) {
type, subtype, custom, index, mats.size()); type, subtype, custom, index, mats.size());
ItemFilter filter = filters[index]; ItemFilter filter = filters[index];
filter.setMaterials(mats); filter.setMaterials(mats);
// ensure relevant masks are explicitly enabled
df::dfhack_material_category mask = filter.getMaterialMask();
for (auto & mat : mats) {
if (mat.matches(stone_cat))
mask.whole |= stone_cat.whole;
else if (mat.matches(wood_cat))
mask.whole |= wood_cat.whole;
else if (mat.matches(metal_cat))
mask.whole |= metal_cat.whole;
else if (mat.matches(glass_cat))
mask.whole |= glass_cat.whole;
}
filter.setMaterialMask(mask.whole);
get_item_filters(*out, key).setItemFilter(*out, filter, index); get_item_filters(*out, key).setItemFilter(*out, filter, index);
call_buildingplan_lua(out, "signal_reset"); call_buildingplan_lua(out, "signal_reset");
return 0; return 0;

@ -622,7 +622,7 @@ QualityAndMaterialsPage.ATTRS{
} }
local TYPE_COL_WIDTH = 20 local TYPE_COL_WIDTH = 20
local HEADER_HEIGHT = 8 local HEADER_HEIGHT = 6
local QUALITY_HEIGHT = 9 local QUALITY_HEIGHT = 9
local FOOTER_HEIGHT = 4 local FOOTER_HEIGHT = 4
@ -649,7 +649,6 @@ local function mat_sort_by_quantity(a, b)
end end
function QualityAndMaterialsPage:init() function QualityAndMaterialsPage:init()
self.lowest_other_item_heat_safety = 2
self.dirty = true self.dirty = true
local enable_item_quality = can_be_improved(self.index) local enable_item_quality = can_be_improved(self.index)
@ -667,38 +666,9 @@ function QualityAndMaterialsPage:init()
{gap=1, pen=COLOR_LIGHTCYAN, text=self:callback('get_summary')} {gap=1, pen=COLOR_LIGHTCYAN, text=self:callback('get_summary')}
}, },
}, },
widgets.CycleHotkeyLabel{
view_id='safety',
frame={t=2, l=0, w=35},
key='CUSTOM_SHIFT_G',
label='Building heat safety:',
options={
{label='Fire Magma', value=0, pen=COLOR_GREY},
{label='Fire Magma', value=2, pen=COLOR_RED},
{label='Fire', value=1, pen=COLOR_LIGHTRED},
},
on_change=self:callback('set_heat_safety'),
},
widgets.Label{
frame={t=2, l=30},
text='Magma',
auto_width=true,
text_pen=COLOR_GREY,
visible=function() return self.subviews.safety:getOptionValue() == 1 end,
},
widgets.Label{
frame={t=3, l=3},
text='Other items for this building may not be able to use all of their selected materials.',
visible=function() return self.subviews.safety:getOptionValue() > self.lowest_other_item_heat_safety end,
},
widgets.EditField{
frame={l=0, t=4, w=23},
label_text='Search: ',
on_char=function(ch) return ch:match('%l') end,
},
widgets.CycleHotkeyLabel{ widgets.CycleHotkeyLabel{
view_id='mat_sort', view_id='mat_sort',
frame={l=24, t=4, w=21}, frame={l=0, t=2, w=21},
label='Sort by:', label='Sort by:',
key='CUSTOM_SHIFT_R', key='CUSTOM_SHIFT_R',
options={ options={
@ -709,12 +679,17 @@ function QualityAndMaterialsPage:init()
}, },
widgets.ToggleHotkeyLabel{ widgets.ToggleHotkeyLabel{
view_id='hide_zero', view_id='hide_zero',
frame={l=24, t=5, w=24}, frame={l=0, t=3, w=24},
label='Hide unavailable:', label='Hide unavailable:',
key='CUSTOM_SHIFT_H', key='CUSTOM_SHIFT_H',
initial_option=false, initial_option=false,
on_change=function() self.dirty = true end, on_change=function() self.dirty = true end,
}, },
widgets.EditField{
frame={l=26, t=2},
label_text='Search: ',
on_char=function(ch) return ch:match('[%l -]') end,
},
widgets.Label{ widgets.Label{
frame={l=1, b=0}, frame={l=1, b=0},
text='Type', text='Type',
@ -727,8 +702,7 @@ function QualityAndMaterialsPage:init()
}, },
}, },
}, },
widgets.Panel{ widgets.Panel{view_id='materials_lists',
view_id='materials_lists',
frame={l=0, t=HEADER_HEIGHT, r=0, b=FOOTER_HEIGHT+QUALITY_HEIGHT}, frame={l=0, t=HEADER_HEIGHT, r=0, b=FOOTER_HEIGHT+QUALITY_HEIGHT},
frame_style=gui.INTERIOR_FRAME, frame_style=gui.INTERIOR_FRAME,
subviews={ subviews={
@ -739,11 +713,13 @@ function QualityAndMaterialsPage:init()
icon_width=2, icon_width=2,
cursor_pen=COLOR_CYAN, cursor_pen=COLOR_CYAN,
on_double_click=self:callback('toggle_category'), on_double_click=self:callback('toggle_category'),
on_submit=self:callback('toggle_category'),
}, },
widgets.List{ widgets.List{
view_id='materials_mats', view_id='materials_mats',
frame={l=TYPE_COL_WIDTH, t=0, r=0, b=0}, frame={l=TYPE_COL_WIDTH, t=0, r=0, b=0},
icon_width=2, icon_width=2,
on_submit=self:callback('toggle_material'),
}, },
}, },
}, },
@ -866,25 +842,35 @@ end
local MAT_ENABLED_PEN = to_pen{ch=string.char(251), fg=COLOR_LIGHTGREEN} local MAT_ENABLED_PEN = to_pen{ch=string.char(251), fg=COLOR_LIGHTGREEN}
local MAT_DISABLED_PEN = to_pen{ch='x', fg=COLOR_RED} local MAT_DISABLED_PEN = to_pen{ch='x', fg=COLOR_RED}
local function make_cat_choice(label, cat, key, enabled_cats) local function make_cat_choice(label, cat, key, cats)
local enabled = enabled_cats[cat] local enabled = cats[cat]
local icon = nil
if not cats.unset then
icon = enabled and MAT_ENABLED_PEN or MAT_DISABLED_PEN
end
return { return {
text=label, text=label,
key=key, key=key,
enabled=enabled, enabled=enabled,
cat=cat, cat=cat,
icon=enabled and MAT_ENABLED_PEN or MAT_DISABLED_PEN icon=icon,
} }
end end
local function make_mat_choice(name, props) local function make_mat_choice(name, props, cats)
local quantity = tonumber(props.count) local quantity = tonumber(props.count)
local text = ('%5d - %s'):format(quantity, name) local text = ('%5d - %s'):format(quantity, name)
local enabled = props.enabled == 'true' local enabled = props.enabled == 'true' and cats[props.category]
local icon = nil
if not cats.unset then
icon = enabled and MAT_ENABLED_PEN or MAT_DISABLED_PEN
end
return { return {
text=text, text=text,
icon=enabled and MAT_ENABLED_PEN or MAT_DISABLED_PEN, enabled=enabled,
icon=icon,
name=name, name=name,
cat=props.category,
quantity=quantity, quantity=quantity,
} }
end end
@ -894,7 +880,6 @@ function QualityAndMaterialsPage:refresh()
local subviews = self.subviews local subviews = self.subviews
local heat = getHeatSafetyFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type) local heat = getHeatSafetyFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type)
subviews.safety:setOption(heat)
if heat >= 2 then summary = summary .. 'Magma safe ' if heat >= 2 then summary = summary .. 'Magma safe '
elseif heat == 1 then summary = summary .. 'Fire safe ' elseif heat == 1 then summary = summary .. 'Fire safe '
end end
@ -904,12 +889,12 @@ function QualityAndMaterialsPage:refresh()
subviews.min_quality:setOption(quality.min_quality) subviews.min_quality:setOption(quality.min_quality)
subviews.max_quality:setOption(quality.max_quality) subviews.max_quality:setOption(quality.max_quality)
local categories = utils.invert(getMaterialMaskFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, self.index-1)) local cats = getMaterialMaskFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, self.index-1)
local category_choices={ local category_choices={
make_cat_choice('Stone', 'stone', 'CUSTOM_SHIFT_S', categories), make_cat_choice('Stone', 'stone', 'CUSTOM_SHIFT_S', cats),
make_cat_choice('Wood', 'wood', 'CUSTOM_SHIFT_O', categories), make_cat_choice('Wood', 'wood', 'CUSTOM_SHIFT_O', cats),
make_cat_choice('Metal', 'metal', 'CUSTOM_SHIFT_M', categories), make_cat_choice('Metal', 'metal', 'CUSTOM_SHIFT_M', cats),
make_cat_choice('Other', 'other', 'CUSTOM_SHIFT_T', categories), make_cat_choice('Glass', 'glass', 'CUSTOM_SHIFT_G', cats),
} }
self.subviews.materials_categories:setChoices(category_choices) self.subviews.materials_categories:setChoices(category_choices)
@ -918,7 +903,7 @@ function QualityAndMaterialsPage:refresh()
local hide_zero = self.subviews.hide_zero:getOptionValue() local hide_zero = self.subviews.hide_zero:getOptionValue()
for name,props in pairs(mat_filter) do for name,props in pairs(mat_filter) do
if not hide_zero or tonumber(props.count) > 0 then if not hide_zero or tonumber(props.count) > 0 then
table.insert(mat_choices, make_mat_choice(name, props)) table.insert(mat_choices, make_mat_choice(name, props, cats))
end end
end end
table.sort(mat_choices, self.subviews.mat_sort:getOptionValue()) table.sort(mat_choices, self.subviews.mat_sort:getOptionValue())
@ -933,20 +918,37 @@ function QualityAndMaterialsPage:get_summary()
return self.summary return self.summary
end end
function QualityAndMaterialsPage:toggle_category(idx, choice) function QualityAndMaterialsPage:toggle_category(_, choice)
choice.enabled = not choice.enabled
local cats = {} local cats = {}
if not choice.icon then
-- toggling from unset to something is set
table.insert(cats, choice.cat)
else
choice.enabled = not choice.enabled
for _,c in ipairs(self.subviews.materials_categories:getChoices()) do for _,c in ipairs(self.subviews.materials_categories:getChoices()) do
if c.enabled then if c.enabled then
table.insert(cats, c.cat) table.insert(cats, c.cat)
end end
end end
end
setMaterialMaskFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, self.index-1, cats) setMaterialMaskFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, self.index-1, cats)
self.dirty = true self.dirty = true
end end
function QualityAndMaterialsPage:set_heat_safety(heat) function QualityAndMaterialsPage:toggle_material(_, choice)
setHeatSafetyFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, heat) local mats = {}
if not choice.icon then
-- toggling from unset to something is set
table.insert(mats, choice.name)
else
choice.enabled = not choice.enabled
for _,c in ipairs(self.subviews.materials_mats:getChoices()) do
if c.enabled then
table.insert(mats, c.name)
end
end
end
setMaterialFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, self.index-1, mats)
self.dirty = true self.dirty = true
end end