phantomwhale
June 4th, 2013, 13:11
I wanted to share a problem I'm having, and see if any of the Lua wizzes (or novices, like me !) might hazard a guess what's happen here - other then I'm being far too fancy for my own good, possibly.
I have a problem with my widgets - they stop updating ! And I have narrowed down why. I created the following "Widget Factory" as a named Lua script:
function createBennyWidget(control, identity, posx, posy)
local bennywidget = control.addBitmapWidget("benny_stack1")
bennywidget.setPosition("topleft", posx, posy)
bennywidget.setVisible(false)
local bennytextwidget = control.addTextWidget("sheetlabelsmallbold", "")
bennytextwidget.setPosition("topleft", posx-1, posy+1)
bennytextwidget.setVisible(false)
local nodeChar = DB.findNode("charsheet." .. identity)
local updateBennies = function()
local nBennies = DB.getValue(nodeChar, "main.bennies", 0)
if nBennies <= 0 then
bennywidget.setVisible(false)
bennytextwidget.setVisible(false)
else
bennywidget.setBitmap("benny_stack" .. nBennies)
bennywidget.setVisible(true)
bennytextwidget.setVisible(false)
end
end
local bennyNode = nodeChar.createChild("main.bennies", "number")
bennyNode.onUpdate = updateBennies
updateBennies()
end
This method simply takes in a windowcontrol, adds a bitmap and text widget onto the control, and then creates and registers a local update method to ensure the widget updates whenever the database node in question changes.
And this basically works - I create a characterlist_entry windowcontrol - this is the portrait you see at the top of each ruleset, representing one player-controlled character. This is created when a player picks up a character (or identity) in the following method:
function onIdentityActivation(identity, username, activated)
if activated then
if not findControlForIdentity(identity) then
CharacterListEntryFactory.create(self, identity)
layoutControls()
end
...
end
You'll note this calls a CharacterListEntryFactory - this is another named lua script, quite small, and the create method, called above, looks a bit like this:
function create(characterList, identity)
local userctrl = characterList.createControl(controlClass, "ctrl_" .. identity)
userctrl.setIdentity(identity)
userctrl.createNameWidget()
if User.isHost() or User.isOwnedIdentity(identity) then
WidgetFactory.createBennyWidget(control, identity, 8, 49)
end
end
So, in summary, the characterlist creates a new entry, passes it into the factory which adds on some basic widgets, and then passes it (again) onto the WidgetFactory, which adds on the benny widget.
Why is it done this way ? Well, we also include the benny widgets onto the character selection screen (for the GM only), so this also calls the following code:
function overlayBennyStack(win, control)
local bennypanel = win.createControl("bennyoverlaypanel", "bennypanel")
WidgetFactory.createBennyWidget(bennypanel, win.getDatabaseNode().getName(), 10, 10)
return bennypanel
end
Nothing vital to understand here, other than there is ANOTHER bit of code somewhere that calls into the WidgetFactory.
The issue I'm having is... whenever I call the WidgetFactory.createBennyWidget method, the previous benny widget created for that database node STOPS updating.
So if a user logs in and takes a character, it creates the benny widget on that character portrait entry at the top of the screen. The benny widget then works... UNTIL I open up the character selection screen as the GM, which creates another benny widget, for a totally different contorl, but somehow STOPPED the updates happening on the original widget.
This does NOT happen when multiple players all log in and select characters; each creates a portrait control with the benny widget, and they all update correctly, it's only when I open up the other window and create widgets against database nodes that already have widgets listening to them, and then the updates stop.
As far as I am aware, you can set the onUpdate handler multiple times against a databasenode and it will call all listener functions. So I don't think that's why. But somehow, calling the WidgetFactory.createBennyWidget is killing the old one.
I thought everything would work, as this method ONLY creates local variables (no globals) and then references them within a function, which it then passes to the FGII database node onUpdate handler. So I thought all these local variables would be locked up in the closure scope, and the stateless createBennyWidget function would just return, meaning multiple calls to it would just generate multiple closures.
Might be a bit heavy for a forum question, but if anyone has any thoughts, I'd be keen to know ! I could just copy and paste that widget code in two places, but it would be a shame to do that, as I'd quite like to figure out the secret to making advanced widget factories that can make widgets to add to ANY control !
Cheers,
Ben (-PW-)
I have a problem with my widgets - they stop updating ! And I have narrowed down why. I created the following "Widget Factory" as a named Lua script:
function createBennyWidget(control, identity, posx, posy)
local bennywidget = control.addBitmapWidget("benny_stack1")
bennywidget.setPosition("topleft", posx, posy)
bennywidget.setVisible(false)
local bennytextwidget = control.addTextWidget("sheetlabelsmallbold", "")
bennytextwidget.setPosition("topleft", posx-1, posy+1)
bennytextwidget.setVisible(false)
local nodeChar = DB.findNode("charsheet." .. identity)
local updateBennies = function()
local nBennies = DB.getValue(nodeChar, "main.bennies", 0)
if nBennies <= 0 then
bennywidget.setVisible(false)
bennytextwidget.setVisible(false)
else
bennywidget.setBitmap("benny_stack" .. nBennies)
bennywidget.setVisible(true)
bennytextwidget.setVisible(false)
end
end
local bennyNode = nodeChar.createChild("main.bennies", "number")
bennyNode.onUpdate = updateBennies
updateBennies()
end
This method simply takes in a windowcontrol, adds a bitmap and text widget onto the control, and then creates and registers a local update method to ensure the widget updates whenever the database node in question changes.
And this basically works - I create a characterlist_entry windowcontrol - this is the portrait you see at the top of each ruleset, representing one player-controlled character. This is created when a player picks up a character (or identity) in the following method:
function onIdentityActivation(identity, username, activated)
if activated then
if not findControlForIdentity(identity) then
CharacterListEntryFactory.create(self, identity)
layoutControls()
end
...
end
You'll note this calls a CharacterListEntryFactory - this is another named lua script, quite small, and the create method, called above, looks a bit like this:
function create(characterList, identity)
local userctrl = characterList.createControl(controlClass, "ctrl_" .. identity)
userctrl.setIdentity(identity)
userctrl.createNameWidget()
if User.isHost() or User.isOwnedIdentity(identity) then
WidgetFactory.createBennyWidget(control, identity, 8, 49)
end
end
So, in summary, the characterlist creates a new entry, passes it into the factory which adds on some basic widgets, and then passes it (again) onto the WidgetFactory, which adds on the benny widget.
Why is it done this way ? Well, we also include the benny widgets onto the character selection screen (for the GM only), so this also calls the following code:
function overlayBennyStack(win, control)
local bennypanel = win.createControl("bennyoverlaypanel", "bennypanel")
WidgetFactory.createBennyWidget(bennypanel, win.getDatabaseNode().getName(), 10, 10)
return bennypanel
end
Nothing vital to understand here, other than there is ANOTHER bit of code somewhere that calls into the WidgetFactory.
The issue I'm having is... whenever I call the WidgetFactory.createBennyWidget method, the previous benny widget created for that database node STOPS updating.
So if a user logs in and takes a character, it creates the benny widget on that character portrait entry at the top of the screen. The benny widget then works... UNTIL I open up the character selection screen as the GM, which creates another benny widget, for a totally different contorl, but somehow STOPPED the updates happening on the original widget.
This does NOT happen when multiple players all log in and select characters; each creates a portrait control with the benny widget, and they all update correctly, it's only when I open up the other window and create widgets against database nodes that already have widgets listening to them, and then the updates stop.
As far as I am aware, you can set the onUpdate handler multiple times against a databasenode and it will call all listener functions. So I don't think that's why. But somehow, calling the WidgetFactory.createBennyWidget is killing the old one.
I thought everything would work, as this method ONLY creates local variables (no globals) and then references them within a function, which it then passes to the FGII database node onUpdate handler. So I thought all these local variables would be locked up in the closure scope, and the stateless createBennyWidget function would just return, meaning multiple calls to it would just generate multiple closures.
Might be a bit heavy for a forum question, but if anyone has any thoughts, I'd be keen to know ! I could just copy and paste that widget code in two places, but it would be a shame to do that, as I'd quite like to figure out the secret to making advanced widget factories that can make widgets to add to ANY control !
Cheers,
Ben (-PW-)