add some hover action to the overlay

develop
Myk Taylor 2023-04-22 23:13:50 -07:00
parent 44f8f84bba
commit 7beac6b4c2
No known key found for this signature in database
1 changed files with 202 additions and 122 deletions

@ -6,12 +6,13 @@ local logistics = require('plugins.logistics')
local overlay = require('plugins.overlay') local overlay = require('plugins.overlay')
local widgets = require('gui.widgets') local widgets = require('gui.widgets')
local STOCKPILES_DIR = "dfhack-config/stockpiles"; local STOCKPILES_DIR = 'dfhack-config/stockpiles';
local STOCKPILES_LIBRARY_DIR = "hack/data/stockpiles"; local STOCKPILES_LIBRARY_DIR = 'hack/data/stockpiles';
-------------------- --------------------
-- plugin logic -- plugin logic
-------------------- --------------------
local function get_sp_name(name, num) local function get_sp_name(name, num)
if #name > 0 then return name end if #name > 0 then return name end
return ('Stockpile %d'):format(num) return ('Stockpile %d'):format(num)
@ -38,9 +39,7 @@ local function list_dir(path, prefix, filters)
return return
end end
local normalized_filters = {} local normalized_filters = {}
for _,filter in ipairs(filters or {}) do for _, filter in ipairs(filters or {}) do table.insert(normalized_filters, filter:lower()) end
table.insert(normalized_filters, filter:lower())
end
for _, v in ipairs(paths) do for _, v in ipairs(paths) do
local normalized_path = prefix .. v.path:lower() local normalized_path = prefix .. v.path:lower()
if v.isdir or not normalized_path:endswith('.dfstock') then goto continue end if v.isdir or not normalized_path:endswith('.dfstock') then goto continue end
@ -66,9 +65,7 @@ local function list_settings_files(filters)
end end
local function assert_safe_name(name) local function assert_safe_name(name)
if not name or #name == 0 then if not name or #name == 0 then qerror('name missing or empty') end
qerror('name missing or empty')
end
if name:find('[^%w._]') then if name:find('[^%w._]') then
qerror('name can only contain numbers, letters, periods, and underscores') qerror('name can only contain numbers, letters, periods, and underscores')
end end
@ -81,13 +78,7 @@ local function get_sp_id(opts)
return nil return nil
end end
local included_elements = { local included_elements = {containers=1, general=2, categories=4, types=8, features=16}
containers=1,
general=2,
categories=4,
types=8,
features=16,
}
function export_stockpile(name, opts) function export_stockpile(name, opts)
assert_safe_name(name) assert_safe_name(name)
@ -99,9 +90,7 @@ function export_stockpile(name, opts)
end end
if includedElements == 0 then if includedElements == 0 then
for _,v in pairs(included_elements) do for _, v in pairs(included_elements) do includedElements = includedElements | v end
includedElements = includedElements | v
end
end end
stockpiles_export(name, get_sp_id(opts), includedElements) stockpiles_export(name, get_sp_id(opts), includedElements)
@ -133,9 +122,7 @@ end
local function parse_include(arg) local function parse_include(arg)
local includes = argparse.stringList(arg, 'include') local includes = argparse.stringList(arg, 'include')
for _, v in ipairs(includes) do for _, v in ipairs(includes) do
if not included_elements[v] then if not included_elements[v] then qerror(('invalid included element: "%s"'):format(v)) end
qerror(('invalid included element: "%s"'):format(v))
end
end end
return includes return includes
end end
@ -143,9 +130,7 @@ end
local valid_modes = {set=true, enable=true, disable=true} local valid_modes = {set=true, enable=true, disable=true}
local function parse_mode(arg) local function parse_mode(arg)
if not valid_modes[arg] then if not valid_modes[arg] then qerror(('invalid mode: "%s"'):format(arg)) end
qerror(('invalid mode: "%s"'):format(arg))
end
return arg return arg
end end
@ -160,15 +145,41 @@ local function process_args(opts, args)
opts.filters = {} opts.filters = {}
return argparse.processArgsGetopt(args, { return argparse.processArgsGetopt(args, {
{'f', 'filter', hasArg=true, {
handler=function(arg) opts.filters = argparse.stringList(arg) end}, 'h',
{'h', 'help', handler=function() opts.help = true end}, 'help',
{'i', 'include', hasArg=true, handler=function()
handler=function(arg) opts.includes = parse_include(arg) end}, opts.help = true
{'m', 'mode', hasArg=true, end,
handler=function(arg) opts.mode = parse_mode(arg) end}, }, {
{'s', 'stockpile', hasArg=true, 'm',
handler=function(arg) opts.id = argparse.nonnegativeInt(arg, 'stockpile') end}, 'mode',
hasArg=true,
handler=function(arg)
opts.mode = parse_mode(arg)
end,
}, {
'f',
'filter',
hasArg=true,
handler=function(arg)
opts.filters = argparse.stringList(arg)
end,
}, {
'i',
'include',
hasArg=true,
handler=function(arg)
opts.includes = parse_include(arg)
end,
}, {
's',
'stockpile',
hasArg=true,
handler=function(arg)
opts.id = argparse.nonnegativeInt(arg, 'stockpile')
end,
},
}) })
end end
@ -176,9 +187,7 @@ function parse_commandline(args)
local opts = {} local opts = {}
local positionals = process_args(opts, args) local positionals = process_args(opts, args)
if opts.help or not positionals then if opts.help or not positionals then return false end
return false
end
local command = table.remove(positionals, 1) local command = table.remove(positionals, 1)
if not command or command == 'status' then if not command or command == 'status' then
@ -196,7 +205,44 @@ function parse_commandline(args)
return true return true
end end
--
-- dialogs
-------------------- --------------------
StockpilesExport = defclass(StockpilesExport, widgets.Window)
StockpilesExport.ATTRS{
frame_title='My Window',
frame={w=50, h=45},
resizable=true,
resize_min={w=50, h=20}, -- try to allow users to shrink your windows
}
function StockpilesExport:init()
self:addviews{
-- add subview widgets here
}
end
function StockpilesExport:onInput(keys)
-- if required
end
StockpilesExportScreen = defclass(StockpilesExportScreen, gui.ZScreenModal)
StockpilesExportScreen.ATTRS{focus_path='stockpiles/export'}
function StockpilesExportScreen:init()
self:addviews{StockpilesExport{}}
end
function StockpilesExportScreen:onDismiss()
export_view = nil
end
local function do_export()
export_view = export_view and export_view:raise() or StockpilesExportScreen{}:show()
end
--
-- StockpilesOverlay -- StockpilesOverlay
-------------------- --------------------
@ -205,59 +251,74 @@ StockpilesOverlay.ATTRS{
default_pos={x=53, y=-6}, default_pos={x=53, y=-6},
default_enabled=true, default_enabled=true,
viewscreens='dwarfmode/Some/Stockpile', viewscreens='dwarfmode/Some/Stockpile',
frame = {w = 27, h = 10}, frame={w=27, h=11},
} }
function StockpilesOverlay:init() function StockpilesOverlay:init()
self.minimized = false self.minimized = false
self.hovered = false
local main_panel = widgets.Panel{ local main_panel = widgets.ResizingPanel{
frame = {t = 0, l = 0, r = 0, b = 0}, view_id='main',
frame={t=0, l=0, r=0},
frame_style=gui.MEDIUM_FRAME, frame_style=gui.MEDIUM_FRAME,
frame_background=gui.CLEAR_PEN, frame_background=gui.CLEAR_PEN,
visible = function() return not self.minimized end, autoarrange_subviews=true,
visible=function()
return not self.minimized
end,
subviews={ subviews={
widgets.HotkeyLabel{ widgets.HotkeyLabel{
frame={t=0, l=0}, frame={t=0, l=0},
label='apply settings', label='apply settings',
key='CUSTOM_CTRL_I', key='CUSTOM_CTRL_I',
auto_width = true,
on_activate=do_import, on_activate=do_import,
}, }, widgets.HotkeyLabel{
widgets.HotkeyLabel{
frame={t=1, l=0}, frame={t=1, l=0},
label='export settings', label='export settings',
key='CUSTOM_CTRL_E', key='CUSTOM_CTRL_E',
auto_width = true,
on_activate=do_export, on_activate=do_export,
}, }, widgets.Panel{
frame={t=2, h=4},
subviews={
widgets.Label{ widgets.Label{
frame = {t = 3, l = 0}, frame={t=1, l=0, h=2},
text = { auto_height=false,
'Designate items brought', NEWLINE, text={'Designate items brought', NEWLINE, 'to this stockpile for:'},
'to this stockpile for:'
}, },
}, },
widgets.ToggleHotkeyLabel{ visible=function()
return self.hovered or self.subviews.melt:getOptionValue() or
self.subviews.trade:getOptionValue() or
self.subviews.dump:getOptionValue()
end,
}, widgets.ToggleHotkeyLabel{
view_id='melt', view_id='melt',
frame = {t = 5, l = 2}, frame={t=6, l=2},
label='melting', label='melting',
key='CUSTOM_CTRL_M', key='CUSTOM_CTRL_M',
on_change=self:callback('toggleLogisticsFeature', 'melt'), on_change=self:callback('toggleLogisticsFeature', 'melt'),
}, visible=function()
widgets.ToggleHotkeyLabel{ return self.hovered or self.subviews.melt:getOptionValue()
end,
}, widgets.ToggleHotkeyLabel{
view_id='trade', view_id='trade',
frame = {t = 6, l = 2}, frame={t=7, l=2},
label='trading', label='trading',
key='CUSTOM_CTRL_T', key='CUSTOM_CTRL_T',
on_change=self:callback('toggleLogisticsFeature', 'trade'), on_change=self:callback('toggleLogisticsFeature', 'trade'),
}, visible=function()
widgets.ToggleHotkeyLabel{ return self.hovered or self.subviews.trade:getOptionValue()
end,
}, widgets.ToggleHotkeyLabel{
view_id='dump', view_id='dump',
frame = {t = 7, l = 2}, frame={t=8, l=2},
label='dumping', label='dumping',
key='CUSTOM_CTRL_D', key='CUSTOM_CTRL_D',
on_change=self:callback('toggleLogisticsFeature', 'dump'), on_change=self:callback('toggleLogisticsFeature', 'dump'),
visible=function()
return self.hovered or self.subviews.dump:getOptionValue()
end,
}, },
}, },
} }
@ -269,42 +330,57 @@ function StockpilesOverlay:init()
frame={t=0, l=0, w=1, h=1}, frame={t=0, l=0, w=1, h=1},
text='[', text='[',
text_pen=COLOR_RED, text_pen=COLOR_RED,
visible = function() return self.minimized end, visible=function()
}, return self.minimized
widgets.Label{ end,
}, widgets.Label{
frame={t=0, l=1, w=1, h=1}, frame={t=0, l=1, w=1, h=1},
text = {{text = function() return self.minimized and string.char(31) or string.char(30) end}}, text={
{
text=function()
return self.minimized and string.char(31) or string.char(30)
end,
},
},
text_pen=dfhack.pen.parse{fg=COLOR_BLACK, bg=COLOR_GREY}, text_pen=dfhack.pen.parse{fg=COLOR_BLACK, bg=COLOR_GREY},
text_hpen=dfhack.pen.parse{fg=COLOR_BLACK, bg=COLOR_WHITE}, text_hpen=dfhack.pen.parse{fg=COLOR_BLACK, bg=COLOR_WHITE},
on_click = function() self.minimized = not self.minimized end, on_click=self:callback('toggleMinimized'),
}, }, widgets.Label{
widgets.Label{
frame={t=0, r=0, w=1, h=1}, frame={t=0, r=0, w=1, h=1},
text=']', text=']',
text_pen=COLOR_RED, text_pen=COLOR_RED,
visible = function() return self.minimized end, visible=function()
return self.minimized
end,
}, },
}, },
} }
self:addviews{ self:addviews{main_panel, minimized_panel}
main_panel,
minimized_panel,
}
end end
function StockpilesOverlay:overlay_onupdate() function StockpilesOverlay:overlay_onupdate()
-- periodically pick up changes made from other interfaces
self.cur_stockpile = nil self.cur_stockpile = nil
end end
function StockpilesOverlay:onRenderFrame() function StockpilesOverlay:onRenderFrame()
local sp = dfhack.gui.getSelectedStockpile() local sp = dfhack.gui.getSelectedStockpile()
local sp_updated = false
if self.cur_stockpile ~= sp then if self.cur_stockpile ~= sp then
local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1] local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1]
self.subviews.melt:setOption(config.melt == 1) self.subviews.melt:setOption(config.melt == 1)
self.subviews.trade:setOption(config.trade == 1) self.subviews.trade:setOption(config.trade == 1)
self.subviews.dump:setOption(config.dump == 1) self.subviews.dump:setOption(config.dump == 1)
self.cur_stockpile = sp self.cur_stockpile = sp
sp_updated = true
end
local prev_hovered = self.hovered
self.hovered = not not (self.hovered and self:getMouseFramePos() or
self.subviews.main:getMousePos())
if self.hovered ~= prev_hovered or sp_updated then
self:updateLayout()
df.global.gps.force_full_display_count = 1
end end
end end
@ -313,20 +389,24 @@ function StockpilesOverlay:toggleLogisticsFeature(feature)
local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1] local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1]
-- logical xor -- logical xor
logistics.logistics_setStockpileConfig(config.stockpile_number, logistics.logistics_setStockpileConfig(config.stockpile_number,
(feature == 'melt') ~= (config.melt == 1), (feature == 'melt') ~= (config.melt == 1), (feature == 'trade') ~= (config.trade == 1),
(feature == 'trade') ~= (config.trade == 1),
(feature == 'dump') ~= (config.dump == 1)) (feature == 'dump') ~= (config.dump == 1))
self.cur_stockpile = nil
end
function StockpilesOverlay:toggleMinimized()
self.minimized = not self.minimized
self.cur_stockpile = nil
end end
function StockpilesOverlay:onInput(keys) function StockpilesOverlay:onInput(keys)
if keys.CUSTOM_ALT_M then if keys.CUSTOM_ALT_M then
self.minimized = not self.minimized self:toggleMinimized()
return true return true
end end
return StockpilesOverlay.super.onInput(self, keys) return StockpilesOverlay.super.onInput(self, keys)
end end
OVERLAY_WIDGETS = { OVERLAY_WIDGETS = {overlay=StockpilesOverlay}
overlay = StockpilesOverlay,
}
return _ENV return _ENV