MenuBuilder - segabl/pd2-hoplib GitHub Wiki

The MenuBuilder automatically builds a mod options menu from a provided settings table and sets up all the needed menu elements and callback functions.

A minimal example usage of the MenuBuilder looks like this:

TestMod = {}
TestMod.settings = {
  toggle = true,
  value = 0
}

local builder = MenuBuilder:new("test_mod", TestMod.settings)
Hooks:Add("MenuManagerBuildCustomMenus", "MenuManagerBuildCustomMenusTestMod", function(menu_manager, nodes)
  builder:create_menu(nodes)
end)

In the above example a new menu will be created in the BLT Mod Options, the setting toggle will turn into a checkbox and the setting value will turn into a slider with a minimum value of 0 and a maximum value of 1.

Customizing settings

You can provide additional settings for creating the menu elements via the optional params argument. This parameter should be a table with keys of same name as the keys in your main settings table and the values for them should be tables containing some information about that specific setting.

Setting slider values

You can specify min, max and step for a slider, which will control the minimum and maximum allowed values of that menu element, as well as the step size when the arrow keys are pressed on it. The defaults are min = 0, max = 1 and step = 0.1.

Turning a setting into multi-select menu element

If the table contains an items entry, this is used to make a multi-select menu element instead of the default slider for a number value setting.

Menu element ordering

You can specify the priority for the created menu element of a setting, which determines the sorting of elements. By default, menu elements will be sorted in the order they are added (which depends on Lua's table keys), you can overwrite that by specifying a priority value.

Dividers

If you want to add some padding around specific menu entries, you can specify a divider value which will put some space before or after the element, depending on the value. A negative number will put a divider of that size before the menu entry, positive number will put it after the entry.

Callbacks

You can add a callback function that is executed whenever that setting is changed by adding the callback key and setting it to a function.

Preventing menu element creation

If you want to prevent a specific setting from showing up in the menu altogether you can add a hidden key and setting it to true.

Adjusted example

Changing the code from the first example:

TestMod = {}
TestMod.settings = {
  toggle = true,
  value = 0
}
TestMod.values = {
  value = {
    items = { "dialog_yes", "dialog_no" },
    priority = 99,
    divider = 16,
    callback = function () log("menu item has been changed") end
  }
}

local builder = MenuBuilder:new("test_mod", TestMod.settings, TestMod.values)
Hooks:Add("MenuManagerBuildCustomMenus", "MenuManagerBuildCustomMenusTestMod", function(menu_manager, nodes)
  builder:create_menu(nodes)
end)

This would result in the value setting turning into a multi-select instead and being displayed as the first element of the menu. The menu entry will have a spacing of 16 pixels to the next entry and the callback function will be called everytime the selection of the multi-select changes.

Sub-Menus

You can create sub-menus by adding table values to your settings table, and specifying some details for the sub-menu via the optional values argument will pass down those values to any child elements in that table and be used as default for them if no other values are specified.

Simple example of a sub-menu with its children elements inheriting values from it:

TestMod.settings = {
  toggle = true,
  submenu = {
    value1 = 0,
    value2 = 0
  }
}
TestMod.values = {
  submenu = {
    items = { "dialog_yes", "dialog_no" }
  }
}

local builder = MenuBuilder:new("test_mod", TestMod.settings, TestMod.values)
Hooks:Add("MenuManagerBuildCustomMenus", "MenuManagerBuildCustomMenusTestMod", function(menu_manager, nodes)
  builder:create_menu(nodes)
end)

This will result in a sub-menu with both the value1 and value2 setting turning into a multi-select element.

Buttons

A setting which has a function as its value will result in a button menu element that executes that function when clicked.

Example of a button that prints text to the log file when it's clicked:

TestMod.settings = {
  button = function ()
    log("Hello World!")
  end
}

local builder = MenuBuilder:new("test_mod", TestMod.settings)
Hooks:Add("MenuManagerBuildCustomMenus", "MenuManagerBuildCustomMenusTestMod", function(menu_manager, nodes)
  builder:create_menu(nodes)
end)

Localization

When creating the MenuBuilder, it looks for existing localization in the form of menu_ID_SETTING and menu_ID_SETTING_desc where ID is the id you specified when creating the MenuBuilder and SETTING is the name of the setting in the settings table. The main menu node is using menu_ID and menu_ID_desc. If these localization strings can't be found, the MenuBuilder automatically creates localization strings based on the settings names. Localization strings for menu items of multi-select elements always have to be created manually.

In the examples above, we set the identifier of the MenuBuilder to test_mod, so the localization keys it will look for to display the main menu node would be menu_test_mod and menu_test_mod_desc.

Saving and loading

Note that you don't have to call the save_settings or load_settings functions manually in most cases. Settings are loaded when the MenuBuilder is created and saved whenever you leave the mod options menu. The functions are there in case you need to save/load data manually for some special usecase.