PDA

View Full Version : Referencing other controls on the same sheet from a windowlist item?



cscase
December 15th, 2013, 05:36
I might have just been staring at this too long, but I think this is probably a simple question and I'm hoping someone can set me straight.

I want to reference a control on a sheet from a windowlist item on that same sheet. In the past, you guys have taught me how to access database nodes that those other controls are tied to, but in this case, I need to reference the controls themselves, so it seems like I need a different way of going about it. Here's my non-working code where I was trying to get at it from the dbnode reference approach. I see now that it's wrong but might make it clearer what I'm trying to do:


function onValueChanged()
local charsheet = window.getDatabaseNode().getParent().getParent();
local dbnodehitthreshold = charsheet.getChild("hitthreshold");
local htname = dbnodehitthreshold.getName();
local nodename = getDatabaseNode().getParent().getName();

if nodename == "Athletics" then
Debug.chat(dbnodehitthreshold);
Debug.chat(dbnodehitthreshold.getValue());
charsheet.hitthreshold.calcHitThreshold();
end
end

So, on this same character sheet as the windowlist there is a control called hitthreshold. That control has a function attached to it that causes it to recalculate and update itself, and I'm trying to trigger that update whenever a skill's value is changed.

window.hitthreshold doesn't work, because hitthreshold is not another window on the same windowlist.

I also tried window.window.hitthreshold - which may be totally silly, but can you see what I'm trying to get to? Is there a "getParent" type thing for windows, the way there is for DB nodes? Or am I just going at this from the wrong angle?

Thanks for any insight you might be able to add.

Trenloe
December 15th, 2013, 06:09
charsheet.hitthreshold.calcHitThreshold();
You're using a database node to try to reference a control on a window? Yes, that definitely isn't going to work - you can't use a database object to reference a GUI control.

Try using debug to see what window class is being reported by this function, i.e. window.getClass() to return the classname. This will give you an idea of which window class is being returned and will give you an idea of what controls are available within that window class - so you'll know if window.hitthreshold would work or not. Further reference to the windowclass object here: https://www.fantasygrounds.com/refdocbeta/windowinstance.xcp

If this doesn't help you please post the XML for you window instance where the hitthreshhold control is defined - the code you list above doesn't really help in debugging as we have no idea the control hierarchy in your GUI XML.

cscase
December 15th, 2013, 06:56
Well, the control this function is attached to just sits on the main tab of my character sheet - so that's charsheet_main. It's like this:


<root>
<windowclass name="charsheet_main">
<sheetdata>

...

<numberfield name="hitthreshold" source=".hitthreshold">
<anchored>
<to>hpframe</to>
<position>insidebottom</position>
<offset>0,9</offset>
</anchored>
<font>sheetlabel</font>
<default>3</default>
<min>1</min>
<max>6</max>
<nodrop />
<noreset />
<readonly />
<script>
function onInit()
calcHitThreshold()
end


function calcHitThreshold()
Debug.chat(window.getClass());
local charsheet = window.getDatabaseNode();
local dbnodeathleticsrating = charsheet.getChild("genskills.Athletics.rating");
if dbnodeathleticsrating.getValue() &gt; 7 then
setValue(4);
else
setValue(3);
end
end

</script>
</numberfield>

Then elsewhere within that same sheetdata block, there is a windowlist, and I am trying to call the function from inside a script block on the windowlist item definition class.

Or, to give a high-level description: There's a field on the character sheet, at the top level, just a read only field dropped on there. It has a function attached which calculates what it should be based on the value of a skill. And that function works correctly, updates the value. I just need to trigger that update to happen whenever the skill's value changes, so that the calculated field gets updated if the contributing variable changes.

I found this page, which has a section titled "Script Block Scope" that seems very relevant: https://www.fantasygrounds.com/modguide/scripting.xcp
It describes the "window" and "windowlist" and "subwindow" built-in variables. I've found I can use window.windowlist to get the name of the windowlist control that I'm trying to make the function call from, but that's not really getting me where I need to go. And I can't simply say "window.window.windowlist," but if I could, I think that would be exactly the reference I need.

Maybe this is not as straightforward as I thought. I'll keep fiddling and reading! Thanks once again, Trenloe.

Trenloe
December 15th, 2013, 07:08
Yep, looking at scope is definitely what you want to do. But, you need to be aware that the window object is just that - and object pointing at the windowinstance of the window the script is running in. Using window.window doesn't work as you are using the same variable twice.

Did you try debug code to print out window.getClass() as I suggested above? This will give you the class name of the window instance that is available to you. If this returns "charsheet_main" then window.hitthreshold.calcHitThreshold() should work. I can't comment on other window classes that may be returned as you didn't include the XML for the <windowlist> control.

cscase
December 15th, 2013, 07:19
Yes - I put in the getClass call as you suggested and got "charsheet_main." That was when I called it from the function I'm looking to call, which was what I thought you meant.

Just now, I've also called it from the script block where I want to reference that function from, (which is in a windowlist element). From there, it returns "char_skill." Here's the windowlist itself. Just to give it some context, this appears at the top level in sheetdata for the charsheet_main window:

<windowlist name="genskills"> <!--GENERAL SKILLS WINDOWLIST-->
<anchored to="genskillframe">
<top offset="25" />
<left offset="10" />
<right offset="-7" />
<bottom offset="-15" />
</anchored>
<allowcreate/>
<datasource>.genskills</datasource>
<class>char_skill</class>
<sortby><control>label</control></sortby>
<columns width="175" filldown="true" />
<script file="campaign/scripts/char_skilllist.lua" />
</windowlist>

So, the call is being made from an instance of the windowclass char_skill. That defines one skill on a list of skills, so it has things like the name of the skill, the max pool value and the current pool value. It's on that max pool value field that I'm trying to make this function call.

To illustrate visually:

charsheet_main....................(Main character sheet windowclass)
--->genskills........................(windowlist which contains skill entries)
--->--->char_skill.................(the individual skill)
--->--->--->Athletics.rating...(numberfield from which I am trying to make the function call)

--->hitthreshold.......(the control where the function is that I want to call)

I wonder if, if this is an unusual and difficult thing to do, maybe I could set up sort of a relay, where I call a function that is within scope, which calls the function I'm actually wanting to call. My gut says that that is kludgey and probably a bad idea.

Trenloe
December 15th, 2013, 07:37
OK, cool. You're getting the "char_skill" window class when window.getClass() is called as this is the window instance within the window list - so the window variable points to this.

As you've discovered, there is no easy way to go back through GUI controls like there is database nodes.

One way to do it is to have a function at the <windowlist> level that you can call from within your "char_skill" window instance using windowlist.<function name> The "windowlist" variable is described in "script block scope" here: https://www.fantasygrounds.com/modguide/scripting.xcp

This windowlist is essentially the parent GUI control of any of the window instances in the window list - *and* it has access to the window instance where the windowlist resides via the window variable, in this case "charsheet_main".

So, put a function in campaign/scripts/char_skilllist.lua that looks something like this:

function handleCalcHitThreshold()
window.hitthreshold.calcHitThreshold();
end
As this script file is at the windowlist level it has access to it's containing window instance "charsheet_main" via the window variable, and functions within char_skilllist.lua can be called by "char_skill" windows within the window list using the windowlist variable. So, within your "char_skill" window instance use window.windowlist.handleCalcHitThreshold() to call the new function listed above and this will in turn call the calcHitThreshold() function in the hitthreshold control.

Hope this makes sense? (And I hope it works)... :)

Trenloe
December 15th, 2013, 07:49
Actually - all of the above may be overkill.

Try:

window.windowlist.window.hitthreshold.calcHitThres hold();
Which is what you were asking for originally... Sorry! :)

I eventually found examples of this in the calendar.xml file in the 3.5e ruleset.

This is doing essentially what I was doing with the "handle" function in my post above. window.windowlist returns the <windowlist> object "genskills" that the "char_skill" window instance is contained in. Adding .window to this will return the "charsheet_main" window instance - so this is like going up in the control heirarchy to the parent. Then, once at "charsheet_main" (window.windowlist.window) you can get to the hitthreshold control. Sorry for the confusion - it took me a while to understand your XML layout and names.

cscase
December 15th, 2013, 07:58
AHA! Yes, that made sense. Set up basically a repeater for the function, or a relay if you prefer.

And not only did that make sense, it worked perfectly.

I added this to the script for my windowlist:


function refreshThresh()
window.hitthreshold.calcHitThreshold();
end

Then, I called this new intermediary function from the block on the skill where I've been trying to make the call from:


window.windowlist.refreshThresh();

It's a little strange but it works without a hitch!

Thanks for your repeated and patient help, Trenloe.

cscase
December 15th, 2013, 08:03
Aha again! I just read your second reply, and yes, that also works, and more directly, too. Many thanks!!

Trenloe
December 15th, 2013, 08:06
Aha again! I just read your second reply, and yes, that also works, and more directly, too. Many thanks!!
No worries at all. I learnt something new too! :)