PDA

View Full Version : Multiple Controls in One Template?



PneumaPilot
November 16th, 2008, 01:47
In working on the nWoD ruleset, I have to create a very large number of checkboxes (for the dots). Up until now, I have been doing this by hand (yes, the xml files are miles long). I would LOVE to be able to have a 5-dot template, a 10-dot template, and a 12-dot template that I could just invoke once instead of creating up to 12 checkbox items at 10 lines of code each.

Is there any way to put multiple items into a single template? I haven't seen anything like this in the examples or in the documentation. Here's what I tried (it didn't work, but it didn't throw errors either):


<template name="dotfive">
<checkbox name="leftbox">
<script>
function onInit()
if anchor then
setAnchor("top", anchor[1], "bottom", "relative", 6);
else
setAnchor("top", "", "top", "absolute", 5);
end
setAnchor("left", "", "left", "absolute", 85);
setAnchor("right", "", "right", "absolute", -7);
end
</script>
</checkbox>

<checkbox>
<anchored>
<to>leftbox</to>
<position>righthigh</position>
<offset>-2,0</offset>
<size>
<width>12</width>
<height>12</height>
</size>
</anchored>
</checkbox>

<checkbox>
<anchored>
<to>leftbox</to>
<position>righthigh</position>
<offset>10,0</offset>
<size>
<width>12</width>
<height>12</height>
</size>
</anchored>
</checkbox>

<checkbox>
<anchored>
<to>leftbox</to>
<position>righthigh</position>
<offset>20,0</offset>
<size>
<width>12</width>
<height>12</height>
</size>
</anchored>
</checkbox>

<checkbox>
<anchored>
<to>leftbox</to>
<position>righthigh</position>
<offset>30,0</offset>
<size>
<width>12</width>
<height>12</height>
</size>
</anchored>
</checkbox>
</template>

PneumaPilot
November 16th, 2008, 01:56
Maybe a script in the template could recursively create new checkbox controls until a given number is reached? Is it even possible to create a control with a script and then have it be persistent? Probably not...

Brenn
November 16th, 2008, 02:07
The best way to do this is to script it. You can create controls at runtime, it turns into a lengthy script, but you can set up a loop to create, say 10 checkboxes, and store them in a table. It also makes lining them up a cinch.

I'll post code where I do this but what I have is nowhere near what you want to do. You'll have to wade through this, but you might see what I'm getting at:

This is from a lua script that I have to create sets out of dice that are rolled and display them in a tracker.


function displaySets(sets)
local sd = 1;
local row = 0;
local totalWidth = 0;
local rowChanged = false;
for i = 1, table.maxn(sets) do
if sets[i].width then
if sets[i].width > 1 then
local currentSet = {};
currentSet = sets[i];
setDisplays[sd] = myParentWindow.createControl("ore_diecontrol","setDisplay" .. sd);
setDisplays[sd].setParentWindow(myParentWindow);
setDisplays[sd].addSet(currentSet);
local sdX, sdY = setDisplays[sd].getCurrentSize();
local pwX, pwY = myParentWindow.getSize();
totalWidth = totalWidth + sdX;
if totalWidth > (pwX-10) then
row = row + 1;
rowChanged = true;
myHeight = myHeight+sdY+2;
setAnchoredHeight(myHeight);
totalWidth = sdX;
end
if (sd == 1) or (rowChanged == true) then
rowChanged = false;
setDisplays[sd].setAnchor("top",self.getName(),"top","absolute",-1 + (row * sdY));
setDisplays[sd].setAnchor("left",self.getName(),"left","absolute",1);
else
setDisplays[sd].setAnchor("top",setDisplays[sd-1].getName(),"top","absolute",0);
setDisplays[sd].setAnchor("left",setDisplays[sd-1].getName(),"right","absolute",-6);
end
sd = sd + 1;
end
else
print("displaySets: Invalid set width, index=" .. i);
end
end
end


In this case I have the oreDieControl that I'm creating declared as a template in desktopTemplates.xml. It has an associated script file.

Hope that helps, kinda tired right now or I'd go into a bit more detail ;)

PneumaPilot
November 16th, 2008, 02:12
Ahh, thank you very much! Yes, createControl was something I was looking for, and the idea about storing the new controls in a table is brilliant. Thanks a ton! I will try to implement this maybe tomorrow...

Brenn
November 16th, 2008, 02:24
If you are digging this far into it I strongly recommend that you take a browse through the XML and Scripting Reference (https://www.fantasygrounds.com/refdoc/).

If it is an inherited class they have links at the top of a particular item so you can easily see what methods are inherited and available to you. I have it open most all of the time when I'm working with FG.

also here is the entire script I posted a fragment of above, some of that is a bit out of context. Note that getSetWidth() and getSetHeight() have nothing to do with the size of the control, they how you describe the roll in case you are unfamiliar with ORE.


function displaySets(sets)
local sd = 1;
local row = 0;
local totalWidth = 0;
local rowChanged = false;
for i = 1, table.maxn(sets) do
if sets[i].width then
if sets[i].width > 1 then
local currentSet = {};
currentSet = sets[i];
setDisplays[sd] = myParentWindow.createControl("ore_diecontrol","setDisplay" .. sd);
setDisplays[sd].setParentWindow(myParentWindow);
setDisplays[sd].addSet(currentSet);
local sdX, sdY = setDisplays[sd].getCurrentSize();
local pwX, pwY = myParentWindow.getSize();
totalWidth = totalWidth + sdX;
if totalWidth > (pwX-10) then
row = row + 1;
rowChanged = true;
myHeight = myHeight+sdY+2;
setAnchoredHeight(myHeight);
totalWidth = sdX;
end
if (sd == 1) or (rowChanged == true) then
rowChanged = false;
setDisplays[sd].setAnchor("top",self.getName(),"top","absolute",-1 + (row * sdY));
setDisplays[sd].setAnchor("left",self.getName(),"left","absolute",1);
else
setDisplays[sd].setAnchor("top",setDisplays[sd-1].getName(),"top","absolute",0);
setDisplays[sd].setAnchor("left",setDisplays[sd-1].getName(),"right","absolute",-6);
end
sd = sd + 1;
end
else
print("displaySets: Invalid set width, index=" .. i);
end
end
end
function unselectAllBut(selName)
for k, v in ipairs(setDisplays) do
if v.getName() ~= selName then
if v.isSelected == true then
v.setSelected(false);
end
end
end
end
function getSelectedSet()
local selSet = {width = 0, height = 0};
for k, v in ipairs(setDisplays) do
if v.isSelected then
selSet.width = v.getSetWidth();
selSet.height = v.getSetHeight();
end
end
return selSet;
end
function setMasterDieNumber(value)
for k, v in ipairs(setDisplays) do
if setDisplays[k].getSetHeight() == value then
setDisplays[k].containsMasterDie(true);
return true;
end
end
return false;
end
function setExpertDieNumber(value)
for k, v in ipairs(setDisplays) do
if setDisplays[k].getSetHeight() == value then
setDisplays[k].containsExpertDie(true);
return true;
end
end
return false;
end
function setParentWindow(parentWin)
myParentWindow = parentWin;
end
function onClose()
for i = table.maxn(setDisplays), 1, -1 do
setDisplays[i].destroy();
setDisplays[i] = nil;
end;
end
function onInit()
myHeight = 28;
myWidth = 260;
setDisplays = {};
end

Bidmaron
November 16th, 2008, 04:07
If you are digging this far into it I strongly recommend that you take a browse through the XML and Scripting Reference (https://www.fantasygrounds.com/refdoc/).

If it is an inherited class they have links at the top of a particular item so you can easily see what methods are inherited and available to you. I have it open most all of the time when I'm working with FG.

also here is the entire script I posted a fragment of above, some of that is a bit out of context. Note that getSetWidth() and getSetHeight() have nothing to do with the size of the control, they how you describe the roll in case you are unfamiliar with ORE.


What is ORE?

Brenn
November 16th, 2008, 04:13
What is ORE?


One Roll Engine, created by Greg Stolze (who also does work for White Wolf).

A basic free version is contained in the rules for Nemesis (https://www.nemesis-system.com/).

Greg has published a game called Reign (https://www.gregstolze.com/reign/) which uses a 'beefed-up' version of ORE. It's this game that I'm currently writing a ruleset for.

The system has also been used in other games, such as Godlike and Wild Talents.

Heh, more info than you probably needed.

Foen
November 16th, 2008, 06:52
Hi

You might want to take a look at the ammocounter control used in the default d20 ruleset.



<genericcontrol name="ammocounter">
<anchored>
<to>attackframe</to>
<position>belowright</position>
<offset>3,-1</offset>
<size>
<width>102</width>
<height>22</height>
</size>
</anchored>
<stateicons>
<on>indicator_checkon</on>
<off>indicator_checkoff</off>
</stateicons>
<spacing>
<horizontal>10</horizontal>
<vertical>10</vertical>
</spacing>
<slotcount>
<horizontal>10</horizontal>
<vertical>2</vertical>
</slotcount>
<fields>
<max>maxammo</max>
<count>ammo</count>
</fields>
<script file="scripts/charsheet_ammocounter.lua" />
</genericcontrol>

You can check the Lua script file out, I've not included a full copy of it here

This creates mulitple checkboxes dynamically based on parameters in the xml which drive the layout. In this case it is two rows each of ten checkboxes, but it could be whatever you want.

Foen

PneumaPilot
November 16th, 2008, 20:20
Foen, what would I do without you, man!? That's awesome! I was browsing around in the D20 set looking for something similar, but I guess I just missed the ammo counter. I should have known to look for it, as much D&D as I've done. This is the absolute perfect solution for this need. Thanks a ton!

PneumaPilot
November 18th, 2008, 03:09
Dang, I was so excited about this and now it's just not working. I can't figure out where the D20 ammocounter is actually being DRAWN. I mean, I read and understand the charsheet_ammocounter.lua file, but in the updateSlots() method it keeps adding widgets to a slots[] array, and I can't find any place where this array is drawn. Maybe it doesn't need to be?

Anywho, I can't get the blasted thing to work, even when I hardcode numbers into the <fields> and erstwise use all of the same settings that they do. I'm missing something somewhere, but can't figure out what...

Foen
November 18th, 2008, 06:03
There is no need for a separate draw routine: addBitMapWidget both creates the widget and renders it. The updateSlots method is called whenever the control needs to be redrawn and the rendering happens within that method.

Foen

PneumaPilot
November 18th, 2008, 14:20
Ahh, okay, that helps me narrow down my problem a little further. I still can't figure out why my version of this thing isn't working, though.

Anyway, I think I am going to work around it anyway. Since most of this effort is for the NPC window, where much of the standard character sheet content can be left out and sometimes extra is needed, I think I am just going to do a windowlist approach. That way, if a user wants to add a ton of abilities, he will have a limitless amount of space to do so, and if it's only important to know one dice pool for a given character, then one entry is all that will show up.

If I do it that way, I will only have to make 10 checkboxes, and I can just do them the same as I have been. At least until I'm able to get a better grasp on how some of this other stuff works.

Xarxus
February 12th, 2022, 01:11
I'd like to have a template with more different controls. The example I saw you showed are with multiple instances of the same control (i.e. checkbox), but in my case there are different controls.
Is there a way to do this?

Xarxus
February 12th, 2022, 20:34
Or even there is a way to define a code to use over and over as a part of some window?