It’s a bit difficult finding documentation on luabind class syntax. I have two small questions:
Is there some way to make these support metamethods? (__index, __newindex)
I’m trying to make an alternative to the “viewbuilder” class, adding some behaviors and stuff that doesn’t exist natively. For simplicity, I want this class to revert to using the standard renoise.ViewBuilder() whenever I haven’t defined my own method that “overrides” it. Will I have to revert to oldschool Lua OO to access __index and make this possible?
Also tried this, but it doesn’t work:
Click to view contents
-- GUI builder class, "inheriting" all standard viewbuilder()
-- classes unless we override them.
class 'JouleBuilder'
function JouleBuilder:__init()
self.vb = renoise.ViewBuilder()
self.jb = { }
-- revert to standard viewbuilder for all undefined methods
self._mt = { __index = self.vb }
setmetatable(self.jb, self._mt)
end
local jb = JouleBuilder()
local real_jb = jb.jb
local content = real_jb:row { } -- returns error, probably due to not passing the correct "self" to method?
A small question in the comment below:
class 'MyClass'
function MyClass:__init(value)
self.value = value
return self -- this line is pretty useless, right? when would it be useful?
end
This concept with traditional OO kind of works, but it won’t provide the friendliest syntax…
local jb = { }
jb.mt = { __call = function() return jb:new() end } -- jb() instead of jb:new()
setmetatable(jb, jb.mt)
function jb:new()
local o = { }
self.vb = renoise.ViewBuilder()
setmetatable(o, self)
self.__index = self
return o
end
-- wrap all standard vb classes like this :(
function jb:row(args)
return self.vb:row(args)
end
-- for the sake of sanity, these kind of methods could very well be externalized to their separate classes
-- bugger we'll then have to change all values with set() calls :(
function jb:my_element(args)
local vb = self.vb
local my_element = vb:row {
vb:text {
text = args.label },
vb:minislider { min = args.min,
max = args.max,
value = args.value,
}
}
return my_element
end
local a = jb()
local test_content = a:row {
a:my_element { min = 0, max = 100, value = 40, label = "slider label" }
}
local dialog = renoise.app():show_custom_dialog("test", test_content)
It seems only the __call method is available in classes.
Anyhow, I think I managed to make a transparent ViewBuilder wrapper like this. It’s pretty nifty having the possibility of adding your own “viewbuilder classes” (combinations of stuff, or additional behaviors to the native classes), while maintaining a transparent syntax to the standard viewbuilder.
class 'NewBuilder'
NewBuilder.subclasses = { "bitmap", "button", "checkbox", "chooser", "column",
"horizontal_aligner", "minislider", "multiline_text", "multiline_textfield",
"popup", "rotary", "row", "slider", "space", "switch", "text", "textfield",
"value", "valuebox", "valuefield", "vertical_aligner", "xypad", -- "slider_labeled"
}
function NewBuilder:__init()
self.vb = renoise.ViewBuilder()
for _, sub_class in ipairs(self.subclasses) do
NewBuilder[sub_class] = function(self, properties)
-- override or return your own "viewbuilder class" here
-- if sub_class == "slider_labeled" then
-- print("creating a slider with attached label")
-- return your object
-- end
return self.vb[sub_class](self.vb, properties)
end
end
end
NewBuilder.views = property(
function(obj) return obj.vb.views end,
function(obj, val) obj.vb.views = val end
)
--[[ quick test
local nb = NewBuilder()
local my_row = nb:row { id = "test" }
oprint(nb)
rprint(nb.views)
]]
It seems only the __call method is available in classes.
I was hesitant to give you a reply, as we are in largely uncharted territory here.
But __index - yes, I think luabind is using that for it’s own getter/setter interface.
In my experience, comparison and toString methods are working though – especially the comparison could be interesting here?
In your code, the missing _index shouldn’t be much of a problem, should it? You’re the “gatekeeper” of your own code, so you know what methods to expect, etc.
Otherwise cLib.reflection.lua has a few (pretty hacky) ways of scanning object properties
Well. What I’m really trying to do is create a class that is (close to) 100% compatible with how viewbuilder is used. An intermediate bridge, where custom classes can be added, so to speak. I want to use it as a general replacement for the ViewBuilder class, being “backwards” compatible syntax wise.
I concluded it’s probably not possible. Simply put, I can’t get it to support all of the below three syntaxes. But it’s good enough so I’ll leave it there.
-- Example 1: works just fine
local content = nb:row {
nb:my_own_slider { label = "Volume", min = 0, max = 100 }
}
-- Example 2: doesn't work, since "element" must be a native vb object to support the syntax in example 1.
local element = vb:my_own_slider { label = "Volume", min = 0, max = 100 }
element.label = "Panning" -- not possible, of course.
-- Example 3: works thanks to building a custom "views" table. (could perhaps add a working add_child and remove_child even)
local element = nb:row {
my_own_slider { id = "my_slider", label = "Volume" }
}
nb.views.my_slider.label = "Panning"