How to use binding in Lua.

Forums: How to use binding in Lua.
Forum for OctaneRender Lua scripting examples, discussion and support.

How to use binding in Lua.

Postby stratified » Tue Jan 28, 2014 3:04 am

stratified Tue Jan 28, 2014 3:04 am
Hi everybody,

We hope you're all having a good time hacking together scripts. If not, you're definitely missing out on something great! Today we'll explain how to use the octane.gui.bind functionality. The examples here work with release candidate 1.29. Binding doesn't bring extra functionality to the API. It's a way to manage complexity in scripts with a user interface.

Binding couples a value in a table with a property of a GUI component. When the GUI component is modified, the value in the table is modified and the script receives an optional callback. When the value in the table is modified, the GUI component is automatically updated to reflect the new value. Not all properties are bindable, and trying to bind a property that isn't bindable results in a lua error. The API browser documents which properties are bindable.

First we need to create a "property" table. This table behaves like a regular lua table but it's mandatory to create it with octane.gui.createPropertyTable. Using the table constructor {} won't work and will throw an error. We need this special creation to add some magic to the table. For those who like nitty-gritty details: we attach a meta table to this table, override the __index and __newindex functions and keep the values in a "shadow" table. The principle is described here. Here's how we create our magic table:

Code: Select all
-- Create the table that has the coupled value. It won't work with a regular
-- table. We need to do a bit of magic in the API.
local props = octane.gui.createPropertyTable()


Next we create a slider and bind it's value and enable properties to the table keys "width" and "red". We set the slider's value with props.red it's a bit less verbose than redSlider:updateProperties{ value = 255 }. We also attach a callback when we bind the value property of the slider. This callback is called when the "red" key in the table is updated:

Code: Select all
local redSlider = octane.gui.create
{
    type     = octane.gui.componentType.SLIDER,
    width    = 200,
    height   = 24,
    minValue = 0,
    maxValue = 255,
}
-- bind the value and enable properties of the slider
redSlider:bind("value" , props, "red", function (key, data) print(key, data) end)
redSlider:bind("enable", props, "enableWidth")
props.red = 255


Let's create a swatch and bind it's colour and enable properties. When the colour of the swatch changes, we'd like to update the slider for the red channel. We can do this via the callback:

Code: Select all
local swatch = octane.gui.create
{
    type     = octane.gui.componentType.COLOUR_SWATCH,
    width    = 100,
    height   = 100,
}
-- bind the colour and enable properties of the swatch
swatch:bind("colour", props, "myColour", function (key, data) props.red = data[1] end)
swatch:bind("enable", props, "allowColourPick")


Just for the heck of it. We create a button to enable or disable the slider and swatch via the props table. We throw it all together in a layout table and place it on a window:

Code: Select all
local button = octane.gui.create
{
    type     = octane.gui.componentType.BUTTON,
    width    = 100,
    height   = 24,
    text     = "Enable/Disable",
    callback =
        -- callback that toggles the enabled state of the ui components
        function()
            props.enableWidth     = not props.enableWidth
            props.allowColourPick = not props.allowColourPick
        end
}

local layoutGrp = octane.gui.create
{
    type     = octane.gui.componentType.GROUP,
    children = { redSlider, swatch, button },
    rows     = 3,
    cols     = 1,
    padding  = { 20 },
    border   = false,
}

local window = octane.gui.create
{
    type     = octane.gui.componentType.WINDOW,
    width    = layoutGrp:getProperties().width,
    height   = layoutGrp:getProperties().height,
    children = { layoutGrp },
    text     = "Bind Example",
}

window:showWindow()


When all went fine, you should have something like this:

Code: Select all
--
-- Bind example script
--

-- Create the table that has the coupled value. It won't work with a regular
-- table. We need to do a bit of magic in the API.
local props = octane.gui.createPropertyTable()

local redSlider = octane.gui.create
{
    type     = octane.gui.componentType.SLIDER,
    width    = 200,
    height   = 24,
    minValue = 0,
    maxValue = 255,
}
-- bind the value and enable properties of the slider
redSlider:bind("value" , props, "red", function (key, data) print(key, data) end)
redSlider:bind("enable", props, "enableWidth")
props.red = 255

local swatch = octane.gui.create
{
    type     = octane.gui.componentType.COLOUR_SWATCH,
    width    = 100,
    height   = 100,
}
-- bind the colour and enable properties of the swatch
swatch:bind("colour", props, "myColour", function (key, data) props.red = data[1] end)
swatch:bind("enable", props, "allowColourPick")

local button = octane.gui.create
{
    type     = octane.gui.componentType.BUTTON,
    width    = 100,
    height   = 24,
    text     = "Enable/Disable",
    callback =
        -- callback that toggles the enabled state of the ui components
        function()
            props.enableWidth     = not props.enableWidth
            props.allowColourPick = not props.allowColourPick
        end
}

local layoutGrp = octane.gui.create
{
    type     = octane.gui.componentType.GROUP,
    children = { redSlider, swatch, button },
    rows     = 3,
    cols     = 1,
    padding  = { 20 },
    border   = false,
}

local window = octane.gui.create
{
    type     = octane.gui.componentType.WINDOW,
    width    = layoutGrp:getProperties().width,
    height   = layoutGrp:getProperties().height,
    children = { layoutGrp },
    text     = "Bind Example",
}

window:showWindow()


There's nothing magic about binding. It's a nice way to decouple program state and the user interface elements that represent that program state. Multiple binding isn't allowed at this time but is something we'd like to add in the future.

Happy hacking,
Thomas
User avatar
stratified
OctaneRender Team
OctaneRender Team
 
Posts: 945
Joined: Wed Aug 15, 2012 6:32 am
Location: Auckland, New Zealand

Return to Lua Scripting


Who is online

Users browsing this forum: No registered users and 1 guest

Fri Sep 20, 2019 1:24 am [ UTC ]