260 lines
9.4 KiB
Plaintext
260 lines
9.4 KiB
Plaintext
|
-- ======================================================================
|
||
|
--[[ 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
|