You have probably read the post on the lua rewrite (Going for a Lua(jit) rewrite). Since everything is going to change, I took the opportunity to see if there was a framework out there that would be easier to use with Mimas.
What I need is an open source portable GUI framework that has scripting support so that remote devices can “publish” there interfaces with the scripting language.
I want the flexibility of html+css+js with a C++ backend (hard to meet needs) but I found the perfect framework.
The framework is Qt because:
<edit> After some work on the new lua based Rubyk, I realize that I do not want to use too many languages to define interfaces and such, so I’ll probably use Lua for this too. It has the added advantage to make the interface code easily portable to other frameworks or devices (iPad with Wax for example). </edit>
I started learning the framework and I am very impressed by the overall quality. The documentation is good, the examples are easy to understand, the template/macro usage is well worked out (I know it’s hard to keep this simple).
Things just work like you expect, with some nice surprises related to layout (scaling with windows and such).
Now that the tools are in place, I need to redesign how all of this gets connected together. The “things” involved in this game are:
A prototype file contains Lua code to define a “class”. The file contains method definitions, class variables and default values.
Example:
node:outlet('output') node:inlet('input').call = function(self, val) if val then print(string.format("[%s] %s <--- '%s'", self.name, 'input', val)) -- receiving value self.val = val -- can we notify without explicitly adding this line ? self:notify('input', val) -- prepend name and send to outlet self:send('output', self.name .. ': ' .. val) end return self.val end -- other way to declare the same (without the send) node:inlet('input2')
Note that all data needs to be stored in “self” since the file definition is shared among all instances of this “class”. Any global variable is shared with all instances.
A patch contains code to instanciate prototypes, setup links and change parameters.
Example:
rk.set('a', {class='proto.lua', name='A'}) rk.set('b', {class='proto.lua', name='B'}) -- links rk.connect('a', 'output', 'b', 'input')
Note that the “set” operation updates a node if it exists or creates a new node if the given name does not exist. With some tricks in the _G
environment table, a setup file can be used without changes as a new prototype (this enables sub-patch abstraction).
When running a patch or prototype file, we need to “update” existing objects instead of recreating them so that links and state are preserved. Adding new objects or updating existing ones is easy, but how do we delete links/objects/methods ?
A solution could be to mark these elements as dirty before the script reload and remove them if they are still dirty (not touched) after script execution. In order to do this, we could use a new environment table on each reload and simply move objects from the old table to the new one on “create/update”. What is left in the old table should be deleted.
But how do we delete a node in Lua ? Since Lua uses garbage collection, we need to remove all references to the node. This means removing:
And how do we update sub-patch links (sub-patch definitions do not have this problem since they are “live” through the metatable) ? For now, we consider that these elements are not updatable.
In a script, the ‘node’ is a prototype created by Node.new. The prototype stores methods
and outlet/inlet definitions. The script is run in its own private environment. This means
that it is possible to create private methods but all state information should live inside
‘self’ or it will be shared across objects.
An instance is made of an empty table with the prototype as metamethod. The instance also
contains an empty ‘outlets’ list with a special index method to create outlets as needed. In
order to create an outlet, the list searches the prototype’s outlet definitions.
Funding from the Swiss Federal Office of Culture to write the graphical frontend to rubyk !
Moving from a global mutex to a global select/poll loop.
comments