PDA

View Full Version : Iterating Through All Characters In DB



UrsaTeddy
February 20th, 2022, 20:40
Greetings,

so I can access DB Nodes without much of a problem, and I can access a specific character the same.

However I would like to iterate through all characters to adjust a database node when something important changes.

Is this possible? Or do I have to access one character at a time?

Moon Wizard
February 20th, 2022, 20:51
When modifying all the records of a given type; you'll have to be careful to do it sparingly (infrequently), because you have no idea how many records of a given type that a campaign may contain.

The new CharEncumbranceManager script in the Test/beta version does exactly this for PCs in a campaign, when the currency weight option is toggled or the campaign currency list is updated (both infrequent events). See the updateAllCharacters function.

Regards,
JPG

UrsaTeddy
February 20th, 2022, 23:58
Well the need for it is that I have a field that can be dynamically set by the GM in the settings panel - players are notified of the change via OOB.

The problem is that since I cannot seem to get onEnter, onTab, or any of those events to trigger for a textbox in the settings panel I have had to resort to updating everytime the GM changes something.

This then creates a new field with each new letter being something new so the characters end up with a list of useless data in their character data.

So the idea is to clean out the previous entry as the GM changes the value in the textbox.

D

Moon Wizard
February 21st, 2022, 02:18
Try using delaykeyupdate on the fields that the GM edits to reduce the overhead of number of changes while they are editing. It will not update the database until the control loses focus with that tag.

And/or try having a refresh button that will perform the updates once the GM is finished making changes. You could even track whether there have been changes since last refresh to warn the GM that there are pending changes.

Regards,
JPG

UrsaTeddy
February 21st, 2022, 02:57
Okay I have got the onEnter() and onTab() finally working.

It is strange that if I do not put an entry into the control definition (XML) like


function onValueChanged()
window.onValueChanged();
end
function onEnter()
window.onEnter();
end


and then in the script file attached to the control



function onEnter()
if enable_update and option_key
then
OptionsManager.setOption(option_key, getTextValue())
end
end


the onEnter() will not trigger at all.

I would term it strange since it would be assumed the script file would be used if attached to the control.

Anyway I now do not need to worry about the database as this is working as expected.

Trenloe
February 21st, 2022, 04:39
If window.onEnter runs your script onEnter function in the script file then that function is at the window level not at the control level.

UrsaTeddy
February 21st, 2022, 05:44
Well here's the rub ...

I have a lua script for my textbox control which is included thus ...



<root>
<windowclass name="option_textbox">
<margins control="0,0,0,2" />
<script file="textbox.lua" />

<sheetdata>


.. it looks exactly like a normal on/off control but with a textbox instead of the cycler in the definition.


Then I try onEnter in Fantasy Grounds in the Option and it DOES NOT work.

I then enter the window.onEnter() line into the script part of the control, thus ...



<stringcontrol name="textbox">
<anchored width="100">
<top offset="5" />
<left parent="label" anchor="right" offset="25" />
</anchored>
<center />
<font>optionbody</font>
<script>
function onEnter()
window.onEnter();
end
</script>
</stringcontrol>


And suddenly it works.

textbox.lua looks exactly like the script for on/off options, however deals with textboxes.

What is going on here then???

Mike Serfass
February 27th, 2022, 05:43
Starting with simple stuff, because sometimes we miss the obvious.

Is your path to textbox.lua correct? Is it in the same folder as your control xml or in the scripts folder?

Did you try a Debug on the first line of the OnEnter function to confirm it wasn't being called? What does

Debug.chat("OnEnter", enable_update, option_key)
write to chat?

UrsaTeddy
February 27th, 2022, 08:30
... Okay ...

thank you for the suggestions ... I can 100% assure you I did what you are mentioning at the very beginning when I built the control (almost 2 years ago now). I had it working using onValueChanged() but my needs for it have changed and so I have been expanding, modifying, improving it.

The control XML file is in the same directory as the control LUA file. It is included in the control XML using the path from the root of the extension to the file itself ... (the XML lies at "controls/textbox/textbox.xml").



<script file="controls/textbox/textbox.lua" />


... I then placed dummy code headers into my script file



function onValueChanged()
Debug.chat("onValueChanged")
end
function onLoseFocus()
Debug.chat("onLoseFocus")
end
function onGainFocus()
Debug.chat("onGainFocus")
end
function onNavigateUp()
Debug.chat("onNavigateUp")
end
function onNavigateDown()
Debug.chat("onNavigateDown")
end
function onTab()
Debug.chat("onTab")
end
function onEnter()
Debug.chat("onEnter")
end


... because I originally wanted to see when they each fire, if there were multiple events firing and so forth.

However I never received any of these messages in my chat window. Actually that is not true, onValueChanged worked because I had copied code from the Cycler option control and thus it had the onValueChanged() code from below in it.

After asking around the boards, and searching, I was hitting a wall and so began to experiment.

When I did the following in the <stringcontrol> that I was using ...



<script>
function onValueChanged()
window.onValueChanged();
end
function onLoseFocus()
window.onLoseFocus();
end
function onGainFocus()
window.onGainFocus();
end
function onEnter()
window.onEnter();
end
function onTab()
window.onTab();
end
function onNavigateUp()
window.onNavigateUp();
end
function onNavigateDown()
window.onNavigateDown();
end
</script>


All of the callbacks in the script file began to fire, just like the onValueChanged() callback.

Thus my comment "here's the rub". It does not seem to be working like Trenloe and MoonWizard have suggested it should. Or there has been a miscommunication somewhere.

Trenloe
February 27th, 2022, 17:45
What I eluded to in my post earier - you're running code in two different places - the windowclass level (window.) and the control level. Control events only fire at the control level.

Windows (specified using <windowclass>) are containers that have one or more controls within the windowclass - code and events that run in a control doesn't automatically run in the windowclass - because the windowclass is not the control, it's at one level higher than the control. Hence why window.onValueChanged() works - because that is the event code in the control calling code in the windowclass (window.)

Trenloe
February 27th, 2022, 17:54
Referring to your earlier code, put together:


<windowclass name="option_textbox">
<margins control="0,0,0,2" />
<script file="textbox.lua" /> This is code at the window level

<sheetdata>
<stringcontrol name="textbox">
<anchored width="100">
<top offset="5" />
<left parent="label" anchor="right" offset="25" />
</anchored>
<center />
<font>optionbody</font>
<script> This is code at the control level
function onEnter()
window.onEnter();
end
</script>
</stringcontrol>
</sheetdata>
</windowclass>

There are two levels of code here - the control level - specified within <stringcontrol><script>, and the window level - specified within <windowclass><script>.

the onEnter function is only executed when the Enter key is pressed within a text based control (stringcontrol is a text based control) - details on the onEnter function here: https://fantasygroundsunity.atlassian.net/wiki/spaces/FGCP/pages/996644760/textbasecontrol#onEnter

onEnter is not exectued at the window level - see the available API functiona available to the window control here: https://fantasygroundsunity.atlassian.net/wiki/spaces/FGCP/pages/996644833/windowcontrol

In the above code example, the onEnter function within the textbox string control is exectued when enter is pressed in that control. Because you have window.onEnter(); within the code of that function, it runs the onEnter function at the window level - normally this wouldn't do anything as the window control doesn't have that function within its API - but you have function onEnter in the textbox.lua file - thus creating a custom onEnter function at the window level - so the code gets calls in the window via the code in the onEnter trigger in the control. It wouldn't get called without window.onEnter as the onEnter code is only triggered by the FGI API in the control.

If you want to code in textbox.lua to run directly against the control then use the following:


<windowclass name="option_textbox">
<margins control="0,0,0,2" />

<sheetdata>
<stringcontrol name="textbox">
<anchored width="100">
<top offset="5" />
<left parent="label" anchor="right" offset="25" />
</anchored>
<center />
<font>optionbody</font>
<script file="textbox.lua" /> This is code at the control level
</stringcontrol>
</sheetdata>
</windowclass>

UrsaTeddy
February 27th, 2022, 20:29
I understand what you have said and are saying.

However in my experience as noted in my last post, it does not seem to be happening the way you are describing.

All I did was take the Cycler option definition (so icon/label/left arrow/cycler/right arrow), remove the arrows, and change the cycler to a stringcontrol.

I then renamed the code file (option_entry_cycler.lua) to textbox.lua

In textbox.lua I modified the code to deal with text changes rather than cycler changes (very little work but some). No functions were changed in any major way.

That process worked and was great for a while.

However I needed a more "this is complete" method for text entry hence the attempts at all the "on" callbacks like Enter, Tab, Navigate etc.

I first just put that code into the textbox.lua file and nothing worked. I then copied the method from option_entry_cycler and put the code in the definition file (XML) and VOILA! it worked.

I have only the following extensions loaded into my DEV campaign: WindowSaverX2, Theme: FG Simple Gray, and my Extension. I sometimes load the Dev: Properties Inspector to get window titles and types but currently not loading it.

From my understanding of your replies, I should not need to put the code that I have into the class definition (although onValueChanged should be there) - if this is correct then why did I have to do it for the other callbacks to make it trigger?

Trenloe
February 27th, 2022, 20:55
I first just put that code into the textbox.lua file and nothing worked. I then copied the method from option_entry_cycler and put the code in the definition file (XML) and VOILA! it worked.
If your textbox.lua <script> definition is in the first code example shown in post #11 above (i.e. within the <windowclass> defintiion and not within the <stringcontrol> definition), then no control based code will run in that script because it is not tied to a control - it is tied to the holding window. Code will only run in that file if it is called using window.<function name>.


From my understanding of your replies, I should not need to put the code that I have into the class definition (although onValueChanged should be there) - if this is correct then why did I have to do it for the other callbacks to make it trigger?
onValueChanged is relevant to your stringcontrol not to the windowclass - because onValueChanged only gets executed when a value changes in the string control - there is no value changing in the windowclass so no onValueChanged code runs there (see the previously linked API reference - onValueChanged is not an API function for the window control).

I still think you're getting confused with the scope of scripts running within windowclasses or within a control, and also confused with the GUI window/control hierarchy. So please post all your code so we can see exactly where you're code is and identify where the issue/s are.

UrsaTeddy
February 27th, 2022, 23:47
Okay that last post clarified it.

Since I am using code that was essentially a base copy of the Cycler code, it uses a script in the windowclass that must be triggered from the stringcontrol itself using the window.onXXX method.

All clear now ... thank you.

Trenloe
February 27th, 2022, 23:55
Okay that last post clarified it.

Since I am using code that was essentially a base copy of the Cycler code, it uses a script in the windowclass that must be triggered from the stringcontrol itself using the window.onXXX method.

All clear now ... thank you.
Great! :)