Divergent/mods/Personal Adjustable Waypoint/gamedata/scripts/zzzzz_monkey_paw_ui_mcm.script

260 lines
9.4 KiB
Plaintext
Raw Normal View History

2024-03-17 20:18:03 -04:00
-- ======================================================================
--[[ Monkeypatch to enable dynamic UI elements in MCM
-- ======================================================================
Author: Catspaw
Version: 2.3
Updated: 20231020
Source: https://www.moddb.com/mods/stalker-anomaly/addons/personal-adjustable-waypoint-for-anomaly-151-152-and-gamma
Included with Personal Adjustable Waypoint, but parameterized so that
any addon can make use of it.
The code in this script is based on code from RavenAscendant's MCM,
which is in turn based on the works of Tronex and others.
You may freely include this script in your own addon, unaltered--but
unless your name is RavenAscendant, please do not release it merged
with ui_mcm.script or otherwise as an integrated alteration to your
own (or your modpack's) version of MCM.
2.3 roll back support for the Track element due to reported issues
2.2 adds "borderless" attribute to the slide element and "desc"
to supported elements
2.1 adds support for the Track element.
-- ======================================================================
USAGE
-- ======================================================================
Adds a new functor attribute to the Slide and Image element types:
- [ui_hook_functor]
- Define: ( table {function, parameters} )
- Used by: image, slide, list, desc (only in this monkeypatch)
- Parameters passed: anchor, handlers, attrs, flags
Execute a function on initial registration of a UI element
anchor - empty static image container
handlers- table of UI handlers
attrs - table of MCM attributes for the menu option
flags - table of MCM metadata
The value of the "parameters" option in the table is added to the end of the parameters list.
Adds a new functor attribute that triggers on changes in all input types:
- [on_selection_functor]
- Define: ( table {function, parameters} )
- Used by option elements: ALL (only in this monkeypatch)
- Parameters passed: path, opt, value, attrs
Execute a function on any unsaved change to an option value
path - MCM path to changed option
opt - name of the changed option
value - value of uncommitted change
attrs - table of MCM attributes for the menu option
The value of the "parameters" option in the table is added to the end of the parameters list.
For most purposes, like simple custom text or image display and/or
formatting, it is sufficient to just instantiate an "image"-type
menu element with a ui_hook_functor, and let the called functor do
whatever work is necessary to build your UI.
-- ======================================================================
COMPATIBILITY / TROUBLESHOOTING
-- ======================================================================
This monkeypatch should work with any recent MCM version. If yours
is old and doesn't work, just upgrade already.
This monkeypatch should NOT alter any functionality of MCM for any
element that does not explicitly invoke either of the new functors.
However, if you beleve this script is causing problems, you should be
able to delete or disable it without causing issues. Anyone using
these functors in their own addon should know to have it gracefully
fail if this script is missing.
-- ==================================================================--]]
if ui_mcm and not ui_mcm.ui_functors_enabled then
cache_value = ui_mcm.UIMCM.CacheValue
-- Storing pointer to the unmodified MCM function
function init_wrapper_box(xml, anchor, w, h, posx, posy)
if not (xml and anchor) then return end
wrapbox = xml:InitStatic("elements:image", anchor)
if not wrapbox then return end
w = w or anchor:GetWidth()
h = h or anchor:GetHeight()
posx = posx and (type(posx) == "number") and posx or 0
posy = posy and (type(posy) == "number") and posy or 0
wrapbox:SetWndSize(vector2():set(w,h))
pos = wrapbox:GetWndPos()
wrapbox:SetWndPos(vector2():set(pos.x + posx, pos.y + posy))
return wrapbox
end
function ui_mcm.UIMCM:CacheValue(path, opt, value, v)
cache_value(self,path,opt,value,v)
-- Use pointer to pass the args through to MCM unaltered
-- We need to prepend "self" to the args because we're invoking a class method without the colon
if v and v.on_selection_functor then ui_mcm.exec(unpack(v.on_selection_functor),path,opt,value,v) end
-- If the on_selection_functor attribute contains a functor, pass a copy of the same args to the functor
end
function ui_mcm.UIMCM:Register_Image(xml, handler, v)
local pic = xml:InitStatic("elements:image",handler)
if v.link then
if (v.pos) then
local pos = pic:GetWndPos()
pic:SetWndPos(vector2():set( pos.x + v.pos[1] , pos.y + v.pos[2] ))
end
if (v.size) then
pic:SetWndSize(vector2():set( v.size[1] , v.size[2] ))
end
pic:InitTexture(v.link)
pic:SetStretchTexture(v.stretch and true or false)
end
if v.ui_hook_functor then
local wrapbox = init_wrapper_box(xml,handler,pic:GetWidth(),pic:GetHeight(),-10)
local handlers = {
pic = pic, -- Handler for the image element
}
local flags = {
etype = "image",
}
ui_mcm.exec(unpack(v.ui_hook_functor),wrapbox,handlers,v,flags)
end
return pic:GetHeight()
end
function ui_mcm.UIMCM:Register_Slide(xml, handler, v)
local frame = xml:InitStatic("elements:slide", handler)
local _pos = frame:GetWndPos()
frame:SetWndPos(vector2():set( _pos.x , _pos.y + (v.spacing or 20) ))
local pic = xml:InitStatic("elements:slide:pic", frame)
if v.link then
pic:InitTexture(v.link)
pic:SetStretchTexture(true)
if (v.pos) then
local pos = pic:GetWndPos()
pic:SetWndPos(vector2():set( pos.x + v.pos[1] , pos.y + v.pos[2] ))
end
if (v.size) then
pic:SetWndSize(vector2():set( v.size[1] * (utils_xml.is_widescreen() and 0.8 or 1) , v.size[2] ))
end
pic:InitTexture(v.link)
end
local txt = xml:InitTextWnd("elements:slide:txt", frame)
if v.text then
txt:SetText( game.translate_string(v.text) )
end
if not v.borderless then
xml:InitStatic("elements:slide:line_1", frame)
xml:InitStatic("elements:slide:line_2", frame)
end
if v.ui_hook_functor then
local wrapbox = init_wrapper_box(xml,handler,pic:GetWidth(),pic:GetHeight() + 20,-10)
local handlers = {
pic = pic, -- handler for the image element
txt = txt, -- handler for the text element
}
local flags = {
etype = "slide",
}
ui_mcm.exec(unpack(v.ui_hook_functor),wrapbox,handlers,v,flags)
end
return (pic:GetHeight() + 20)
end
function ui_mcm.UIMCM:Register_Desc(xml, handler, v)
local desc = xml:InitTextWnd("elements:desc", handler)
desc:SetText( game.translate_string(v.text) )
desc:AdjustHeightToText()
desc:SetWndSize(vector2():set(desc:GetWidth(), desc:GetHeight() + 20))
if v.clr and v.clr[4] then
desc:SetTextColor( GetARGB(v.clr[1], v.clr[2], v.clr[3], v.clr[4]) )
end
if v.ui_hook_functor then
local wrapbox = init_wrapper_box(xml,handler,desc:GetWidth(),desc:GetHeight(),-10)
local handlers = {
desc = desc, -- Handler for the text description element
}
local flags = {
etype = "desc",
}
ui_mcm.exec(unpack(v.ui_hook_functor),wrapbox,handlers,v,flags)
end
return desc:GetHeight()
end
function ui_mcm.UIMCM:Register_List(xml, handler, path, opt, v, flags)
local id = ui_mcm.cc(path , opt)
-- Caption
local h = self:Register_Cap(xml, handler, id, v.hint)
-- Apply to all button
if flags.apply_to_all and flags.group then
self:Register_BtnAll(xml, handler, path, opt, v, flags)
end
-- Create control
local ctrl = xml:InitComboBox("elements:list",handler)
if (ctrl:GetHeight() > h) then
--h = ctrl:GetHeight()
end
-- Get values
local idx
local value = self:GetValue(path, opt, v, flags)
local content = self:GetContent(path, opt, v)
-- Setup
for i=1,#content do
local str_2 = content[i][2] or tostring(content[i][1])
local str = v.no_str and str_2 or game.translate_string("ui_mcm_lst_" .. str_2)
ctrl:AddItem( game.translate_string(str), i)
if content[i][1] == value then
idx = i
end
end
idx = idx or 1
local str_2 = content[idx][2] or tostring(content[idx][1])
local str = v.no_str and str_2 or game.translate_string("ui_mcm_lst_" .. str_2)
ctrl:enable_id( idx )
ctrl:SetText( game.translate_string(str) )
-- Register
local id_ctrl = self:Stacker(path, opt, v)
self:Register(ctrl, id_ctrl)
local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method
self:Callback_List(ctrl, path, opt, v)
end
self:AddCallback(id_ctrl, ui_events.LIST_ITEM_SELECT, _wrapper, self)
if v.ui_hook_functor then
local id_cap = string.gsub(id, "/", "_")
local cap = self._Cap[id_cap]
local wrapbox = init_wrapper_box(xml,handler,handler:GetWidth(),ctrl:GetHeight(),-10)
local handlers = {
ctrl = ctrl, -- handler for the list control element
cap = cap, -- handler for text caption element
}
flags.etype = "list"
flags.path = path -- MCM menu path
flags.opt = opt -- MCM option ID
ui_mcm.exec(unpack(v.ui_hook_functor),wrapbox,handlers,v,flags)
end
return h
end
printf("ui_mcm.script monkeypatched by zzzzz_monkey_paw_ui_mcm.script")
elseif ui_mcm then
printf("zzzzz_monkey_paw_ui_mcm.script: installed MCM already supports UI functors, aborting monkeypatch")
else
printf("zzzzz_monkey_paw_ui_mcm.script: MCM not found, aborting monkeypatch")
end