add basic framework for info search widget

develop
Myk Taylor 2023-10-07 12:11:24 -07:00
parent 37ad0c3e6f
commit ae1d6f98f6
No known key found for this signature in database
2 changed files with 147 additions and 6 deletions

@ -1,5 +1,6 @@
local _ENV = mkmodule('plugins.sort')
local creatures = require('plugins.sort.creatures')
local gui = require('gui')
local overlay = require('plugins.overlay')
local setbelief = reqscript('modtools/set-belief')
@ -275,29 +276,29 @@ local function get_ranged_skill_effectiveness_rating(unit)
return get_rating(ranged_skill_effectiveness(unit), 0, 800000, 72, 52, 31, 11)
end
local function make_sort_by_ranged_skill_effectiveness_desc(list)
local function make_sort_by_ranged_skill_effectiveness_desc()
return function(unit_id_1, unit_id_2)
if unit_id_1 == unit_id_2 then return 0 end
local unit1 = df.unit.find(unit_id_1)
local unit2 = df.unit.find(unit_id_2)
if not unit1 then return -1 end
if not unit2 then return 1 end
local rating1 = ranged_skill_effectiveness(unit1, list)
local rating2 = ranged_skill_effectiveness(unit2, list)
local rating1 = ranged_skill_effectiveness(unit1)
local rating2 = ranged_skill_effectiveness(unit2)
if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end
return utils.compare(rating2, rating1)
end
end
local function make_sort_by_ranged_skill_effectiveness_asc(list)
local function make_sort_by_ranged_skill_effectiveness_asc()
return function(unit_id_1, unit_id_2)
if unit_id_1 == unit_id_2 then return 0 end
local unit1 = df.unit.find(unit_id_1)
local unit2 = df.unit.find(unit_id_2)
if not unit1 then return -1 end
if not unit2 then return 1 end
local rating1 = ranged_skill_effectiveness(unit1, list)
local rating2 = ranged_skill_effectiveness(unit2, list)
local rating1 = ranged_skill_effectiveness(unit1)
local rating2 = ranged_skill_effectiveness(unit2)
if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end
return utils.compare(rating1, rating2)
end
@ -1261,6 +1262,7 @@ end
OVERLAY_WIDGETS = {
squad_assignment=SquadAssignmentOverlay,
squad_annotation=SquadAnnotationOverlay,
creatures=creatures.InfoOverlay,
}
dfhack.onStateChange[GLOBAL_KEY] = function(sc)

@ -0,0 +1,139 @@
local _ENV = mkmodule('plugins.sort.creatures')
local overlay = require('plugins.overlay')
local widgets = require('gui.widgets')
local creatures = df.global.game.main_interface.info.creatures
-- ----------------------
-- InfoOverlay
--
InfoOverlay = defclass(InfoOverlay, overlay.OverlayWidget)
InfoOverlay.ATTRS{
default_pos={x=64, y=9},
default_enabled=true,
viewscreens={
'dwarfmode/Info/CREATURES/CITIZEN',
'dwarfmode/Info/CREATURES/PET',
'dwarfmode/Info/CREATURES/OverallTraining',
'dwarfmode/Info/CREATURES/AddingTrainer',
'dwarfmode/Info/CREATURES/OTHER',
'dwarfmode/Info/CREATURES/DECEASED',
},
hotspot=true,
overlay_onupdate_max_freq_seconds=0,
frame={w=40, h=3},
}
function InfoOverlay:init()
self.state = {}
self:addviews{
widgets.BannerPanel{
view_id='panel',
frame={l=0, t=0, r=0, h=1},
subviews={
widgets.EditField{
view_id='search',
frame={l=1, t=0, r=1},
label_text="Search: ",
key='CUSTOM_ALT_S',
on_change=self:callback('text_input'),
},
},
},
}
end
function InfoOverlay:overlay_onupdate(scr)
if next(self.state) and not dfhack.gui.matchFocusString('dwarfmode/Info', scr) then
-- TODO: add dynamically allocated elements that were not visible at the time of
-- closure back to the list so they can be properly disposed of
self.state = {}
self.subviews.search:setText('')
self.subviews.search:setFocus(false)
self.overlay_onupdate_max_freq_seconds = 60
end
end
local function are_tabs_in_two_rows()
local pen = dfhack.screen.readTile(64, 6, false) -- tile is occupied iff tabs are in one row
return pen.ch == 0
end
local function resize_overlay(self)
local sw = dfhack.screen.getWindowSize()
local overlay_width = math.min(40, sw-(self.frame_rect.x1 + 30))
if overlay_width ~= self.frame.w then
self.frame.w = overlay_width
return true
end
end
function InfoOverlay:updateFrames()
local ret = resize_overlay(self)
local two_rows = are_tabs_in_two_rows()
if (self.two_rows == two_rows) then return ret end
self.two_rows = two_rows
self.subviews.panel.frame.t = two_rows and 2 or 0
return true
end
local function get_key()
if creatures.current_mode == df.unit_list_mode_type.PET then
if creatures.showing_overall_training then
return 'PET_OT'
elseif creatures.adding_trainer then
return 'PET_AT'
end
end
return df.unit_list_mode_type[creatures.current_mode]
end
local function check_context(self)
local key = get_key()
if self.state.prev_key ~= key then
self.state.prev_key = key
local prev_text = ensure_key(self.state, key).prev_text
self.subviews.search:setText(prev_text or '')
end
end
function InfoOverlay:onRenderBody(dc)
if next(self.state) then
check_context(self)
end
if self:updateFrames() then
self:updateLayout()
end
self.overlay_onupdate_max_freq_seconds = 0
InfoOverlay.super.onRenderBody(self, dc)
end
function InfoOverlay:text_input(text)
if not next(self.state) and text == '' then return end
-- the EditField state is guaranteed to be consistent with the current
-- context since when clicking to switch tabs, onRenderBody is always called
-- before this text_input callback, even if a key is pressed before the next
-- graphical frame would otherwise be printed. if this ever becomes untrue,
-- then we can add an on_char handler to the EditField that also calls
-- check_context.
local key = get_key()
local prev_text = ensure_key(self.state, key).prev_text
if text == prev_text then return end
if prev_text and text:startswith(prev_text) then
-- TODO: search
print('performing incremental search; text:', text, 'key:', key)
else
-- TODO: save list if not already saved
-- TODO: else restore list from saved list
-- TODO: if text ~= '' then search
-- TODO: sort according to vanilla sort widget state
print('performing full search; text:', text, 'key:', key)
end
-- TODO: save visible list
self.state[key].prev_text = text
end
return _ENV