Custom Preferences

The editor Preferences window can be customized by adding custom pages with preferences for your tools. The following snippet shows how:

Custom Preferences
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    -- called by the preference registry before preferences are loaded and before onEditorInitialized, to register your preferences
    local function onEditorRegisterPreferences(prefsRegistry)
            -- the category is the actual preferences page shown on the left side of the Preferences window
            -- the 1st argument is the internal name used for preferences path,
            -- the 2nd argument is the label (display name), if nil or missing, it will be computed from the name, as a Sentence Case string
            -- in this case it will be: "Gizmos"
            prefsRegistry:registerCategory("gizmos")
            -- the subcategories are groups of preferences
            -- 3rd argument is the label, same as the category name, if missing
            -- 4th argument would be the list of preferences for that subcategory, optional, otherwise you can use registerPreferences later on
            prefsRegistry:registerSubCategory("gizmos", "general")
            prefsRegistry:registerCategory("snapping")
            prefsRegistry:registerSubCategory("snapping", "general")
            prefsRegistry:registerSubCategory("snapping", "terrain")

            -- now lets add some preferences to general subcategory
            prefsRegistry:registerPreferences("gizmos", "general",
            {
              -- {name = {type, default value, desc, label (nil for auto Sentence Case), min, max, hidden, advanced, customUiFunc, enumLabels}}
              {useObjectBoxCenter = {"bool", true, "Use the object bounding box center as axis gizmo position, else use the pivot"}},
              {drawObjectIcons = {"bool", true, "Draw the object type icons in the world space"}},
              {drawObjectsText = {"bool", false, "Draw the object type name as text in the world space"}},
              {drawGizmoPlane = {"bool", true, "Draw the gizmo plane"}}
            })

            -- another way to register a subcategory and at the same time its preference items
            prefsRegistry:registerSubCategory("gizmos", "objectIcons", nil, -- label, the system will use automatic "Other Settings" label
            {
              -- {name = {type, default value, desc, label (nil for auto Sentence Case), min, max, hidden, advanced, customUiFunc, enumLabels}}
              {drawIconShadow = {"bool", true, "Draw a shadow under the object icons"}},
              {constantSizeIcons = {"bool", true, "Draw the object type icons with a constant screen size"}},
              {constantSizeIconScale = {"float", 0.8, "The scale of the constant size icons"}},
              {iconWorldScale = {"float", 0.2, "The scale of the icons when rendered in world size"}},
              {fadeIcons = {"bool", true, "Fade the icons based on their distance to the camera"}},
              {useIconColor = {"bool", false, "Draw the object icons with different colors"}},
              {randomIconColorSeed = {"float", 0, "The color random seed used for coloured icon rendering"}},
              {fadeIconsDistance = {"float", 30, "The distance from where icons will start to fade out"}},
              {iconBackgroundType = {"enum", "None", "The icon background shape type", nil, nil, nil, nil, nil, nil, {"None", "Circle", "Square"}}},
              {iconBackgroundScale = {"float", 1.4, "The icon background scale factor"}},
              {monoIconColor = {"ColorI", ColorI(255, 255, 255, 255), "The color of the icons when using a single color for all"}},
              {selectedIconColor = {"ColorI", ColorI(255, 128, 0, 255), "The color of a selected icon"}},
              {iconShadowColor = {"ColorI", ColorI(0, 0, 0, 255), "The object icon's shadow color"}},
              {iconBackgroundColor = {"ColorI", ColorI(0, 255, 255, 255), "The object icon's background color"}},
              {selectedIconBackgroundColor = {"ColorI", ColorI(178, 102, 0, 255), "Selected object icon's background color"}},
              {objectTextBackgroundColor = {"ColorI", ColorI(0, 0, 0, 255), "World space object name text background color"}},
              {objectTextColor = {"ColorI", ColorI(255, 255, 255, 255), "World space object name text color"}},
              {iconShadowOffset = {"Point2F", Point2F(3, 3), "The offset in pixels, for the shadow of the object icons"}},
              {hiddenObjectIconClasses = {"table", {"TSStatic"}, nil, nil, nil, nil, nil, nil, hiddenObjectIconsUI}},
            })
    end

    -- called by the preferences registry when a preference value is set (changed), using editor.setPreference(path, value) function
    local function onEditorPreferenceValueChanged(path, value)
            -- if the changed prereference path matches our needed one, do something with the new value
            -- you dont need this for all preferences, usually used when it needs to be set into the C++ engine
            -- or some recomputation is needed
            if path == "gizmos.objectIcons.drawIconShadow" then setIconShadowInEngine(value) end
    end

    M.onEditorInitialized = onEditorInitialized
    M.onEditorRegisterPreferences = onEditorRegisterPreferences
    M.onEditorPreferenceValueChanged = onEditorPreferenceValueChanged
Accessing Custom Preferences
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
-- here we access the preferences
local function myFunction()
    -- lets read the value of a preference item
    -- Variant #1:
    if editor.preferences.gizmos.objectIcons.fadeIcons then doSomething() end
    -- Variant #2:
    if editor.getPreference("gizmos.objectIcons.fadeIcons") then doSomething() end

    -- lets set the value:
    -- Variant #1 (recommended):
    editor.setPreference("gizmos.objectIcons.fadeIcons", true)
    -- Variant #2 (longer):
    editor.preferencesRegistry:set("gizmos.objectIcons.fadeIcons", true)
    -- Variant #3 (not recommended, do not use):
    -- not recommended because the onEditorPreferenceValueChanged hook will not be called
    -- and also the registry will not be invalidated so to save the modified preferences
    -- in the future the preferences table (and subtables/values) will be readonly
    editor.preferences.gizmos.objectIcons.fadeIcons = true
end

A bit more on the preferences fields:

  • name [string] - the internal name of the preference, it will be used when a preference is accessed in a path
  • type [string] - the type of the preference item (float, int, double, char, bool, Point2F, Point3F, Point4F, ColorI, ColorF, RectF, enum, table)
  • default value [actual item type] - the default value of the preference item
  • desc [string] - the description of the preference item
  • label [string or nil] - the display name label for the preference item (nil for auto “Sentence Case” from name)
  • min [actual item type] - the minimum value, for numeric types
  • max [actual item type] - the maximum value, for numeric types
  • hidden [bool] - true if the preference item is hidden in the Preferences window
  • advanced [bool] - (not used yet) true if the preference item is advanced (not shown initially) in the Preferences window
  • customUiFunc - callback used on rendering the UI for this particular preference item, format: customUiFunc(item, value) the item is the preferences registry item object and value is the item’s current value
  • enumLabels - an array of string values for a simple enum type, with 0-based indexing, the value of this preferences is the actual selected enum string

Special types: * enum - this type will store a string and will show a dropdown to choose from the enumLabels table of string values * table - this type holds a Lua table/array which will be json encoded on preferences save, and json decoded on load, keep in mind that this table should be made of simple JSON types not complex objects

Technicalities:

  • preference items are declared in their own tables to maintain the order of UI rendering the items as in the code
  • when the preferences were changed, the preferences registry will be set as dirty and at the end of each game frame, they will be saved to file, no need to call any savePreferences function

Also check the API for preferences-api

../../../_images/preferences.png