PDA

View Full Version : Multiple levels of onValueChanged()? [iconcycler]



MeepoSose
November 16th, 2008, 06:52
I managed to get a iconcycler control to update a series of checkboxes whenever the value changed. After I got that working, I modified the template_iconcycler to allow me to link the iconcycler between the combat tracker and charsheet. The problem is that while that piece is now working, it no longer calls the onValueChanged() at the character sheet level. The icon changes, but all the dependent dropdowns don't.

A few things I tried gave me some nice infinite loops.

here is the script section on the control in the charsheet:


<!-- DAD 11/15/2008 added iconcycler for consistency with NPC sheets -->
<iconcycler name="condition" source="condition">
<anchored>
<to>conditionframe</to>
<position>insidetopleft</position>
<offset>20,20</offset>
<size>
<width>55</width>
<height>22</height>
</size>
</anchored>
<frame>
<name>modifier</name>
<offset>6,5,5,5</offset>
</frame>
<sourcefields>
<icons>condition_normal|condition_one|condition_two|condi tion_five|condition_ten|condition_helpless</icons>
<values>0|-1|-2|-5|-10|-99</values>
<srcnode>condition</srcnode>
<defaulticon>condition_normal</defaulticon>
</sourcefields>
<script>
function onInit()
super.onInit();
end

function onValueChanged()
print("local onValueChanged()");
local iCondition = getSourceValue();

if iCondition == "0" then
window.normalbox.setState(1);
print("normal");
else
window.normalbox.setState(0);
end

if iCondition == "-1" then
window.onebox.setState(1);
print("one");
else
window.onebox.setState(0);
end

if iCondition == "-2" then
window.twobox.setState(1);
print("two");
else
window.twobox.setState(0);
end

if iCondition == "-5" then
print("five");
window.fivebox.setState(1);
else
window.fivebox.setState(0);
end

if iCondition == "-10" then
print("10");
window.tenbox.setState(1);
else
window.tenbox.setState(0);
end

if iCondition == "-99" then
print("helpless");
window.helplessbox.setState(1);
else
window.helplessbox.setState(0);
end

end

</script>
</iconcycler>



and here is the full script for the modified template_iconcycler:


--
-- Please see the readme.txt file included with this distribution for
-- attribution and copyright information.
--

linknode = nil;
semaphorenode = nil;
cycleindex = 0;
icons = {};
values = {};
srcnode = nil;
defaulticon = nil;
readonly = false;

function onInit()
-- Get any custom fields
local icontext = "";
local valuetext = "";
local srcnodename = "";
if sourcefields then
if sourcefields[1].icons then
icontext = sourcefields[1].icons[1];
end
if sourcefields[1].values then
valuetext = sourcefields[1].values[1];
end
if sourcefields[1].srcnode then
srcnodename = sourcefields[1].srcnode[1];
end
if sourcefields[1].defaulticon then
defaulticon = sourcefields[1].defaulticon[1];
end
end

-- Parse the icons
for v in string.gmatch(icontext, "[^|]+") do
icons[#icons+1] = v;
end

-- Parse the underlying possible values
for v in string.gmatch(valuetext, "[^|]+") do
values[#values+1] = v;
end

-- Get the data node set up and synched
if srcnodename ~= "" then
srcnode = window.getDatabaseNode().createChild(srcnodename, "string");
srcnode.onUpdate = onValueChanged;
synch_index();
end

-- Set the right icon
updateDisplay();
end

function synch_index()
local srcval = srcnode.getValue();
local match = 0;
for k,v in pairs(values) do
if v == srcval then
match = k;
end
end

if match > 0 then
cycleindex = match;
else
cycleindex = 0;
end
end

function updateDisplay()
if cycleindex > 0 and cycleindex <= #icons then
setIcon(icons[cycleindex]);
else
setIcon(defaulticon);
end
end

function setSourceValue(srcval)
srcnode.setValue(srcval);
end

function getSourceValue()
if cycleindex > 0 and cycleindex <= #values then
return values[cycleindex];
end

return "";
end

function cycleIcon()
if cycleindex < #icons then
cycleindex = cycleindex + 1;
else
cycleindex = 0;
end

if srcnode then
srcnode.setValue(getSourceValue());
else
updateDisplay();
end
end

function onClickDown(button, x, y)
if not readonly then
cycleIcon();
end
end

function setReadOnly(val)
if val == true then
readonly = true;
else
readonly = false;
end
end

function isSemaphoreClear()
print('isSemaphoreClear 1');

if not semaphorenode then
return false;
end
return (semaphorenode.getValue() == 1);
end

function initSemaphore()
print('initSemaphore 1');
semaphorenode = window.getDatabaseNode().createChild(getName() .. "_lock", "number");
clearSemaphore();
end

function setSemaphore()
print('setSemaphore 1');
if semaphorenode then
semaphorenode.setValue(0);
end
end

function clearSemaphore()
print('clearSemaphore 1');
if semaphorenode then
semaphorenode.setValue(1);
end
end

function onLinkUpdated(source)
print('onLinkUpdated 1');
if source then
if isSemaphoreClear() then
if super.getSourceValue()~=source.getValue() then
super.setSourceValue(source.getValue());
end

setSemaphore();
setSourceValue(source.getValue());
clearSemaphore();
end
end

if self.update then
self.update();
end
end

function onValueChanged()
print('onValueChanged 1');
if self.update then
self.update();
end

print("update");
synch_index();
updateDisplay();

if linknode and not readonly then
if isSemaphoreClear() then
setSemaphore();
linknode.setValue(getSourceValue());
clearSemaphore();
end
end
end

function setLink(dbnode, readonly)
print('setLink 1');
if dbnode then
initSemaphore();

linknode = dbnode;
linknode.onUpdate = onLinkUpdated;

if readonly then
addBitmapWidget("indicator_linked").setPosition("bottomright", 0, -3);
else
addBitmapWidget("indicator_linked").setPosition("bottomright", -5, -5);
end

if readonly == true then
setReadOnly(true);
end

onLinkUpdated(linknode);
end
end

Foen
November 16th, 2008, 06:56
I think iconcycler is a jpg_d20 or jpg_4e template and I'm not familiar with how it works :confused:

One problem may be that you are using onValueChanged (which only fires when a window control is being displayed) instead of onUpdate (which fires when the underlying database node value changes, regardless of whether the control is displayed or not).

Just a thought.

Foen

MeepoSose
November 16th, 2008, 08:46
Thanks Foen. I saw you posted something about calling to "super" object, but I get an error message when I try to call in to it. Do you typically need to instruct the scripts within the lua files to bubble the event up?



if super.getSourceValue()~=source.getValue() then


If I leave it out, it seems my debug statements don't even fire -- so the scripts in charsheet_main.xml never trigger at all. I've tried both onUpdate and onValueChanged.

Moon Wizard
November 17th, 2008, 19:47
The combat tracker entry and character sheet are two completely separate records. You have to go through some fairly convoluted coding to get them to sync up with each other.

You might try looking at the template_ctnumberfield.lua in the 4E_JPG ruleset. This is the template used for the HP fields in the combat tracker to link them to the character sheets.

Cheers,
JPG

MeepoSose
November 18th, 2008, 03:06
Thanks everyone. I finally got it working via a not so elegant workaround. I merged both events into the onValueChanged() event in the global template_iconcycler itself instead of having a separate set of code for the condition instance of the icon_cycler. This means that a change to any icon_cycler in the ruleset has to do a couple extra checks to see if its updating the one instance of the icon_cycler that needs the extra code; otherwise, that code is ignored.

Looking at the HP fields was an incredible help in getting these linked up originally. They were just enough different, however, that I had a hard time trying to get the link code to work with the charsheet specific code I had written previously. I thought I would never need to think about semaphores again after my networking and DB class in college 11 years ago.