PDA

View Full Version : Dynamic Drop-Down Menus



Foen
December 9th, 2009, 06:20
In ddavison's drop down menu there is a line <lookup>item</lookup> that tells the script which line to look for in the globalLookups.lua file. That's all dandy and useful but I am trying to figure out how to set an if elseif then statement to tell the script where to look in the globalLookups.lua file.

For example if the above drop-down menu has selected swords on it's weapons lookup, then I'd like the next menu to look into <lookup>swords</lookup> or if a mace then maces etc etc that way things can be divided up into subcategories.


The drop-down code doesn't include this facility, but there are a couple of ways you can implement this: having two drop-downs and making only one of them visible, or loading the drop-down contents dynamically.

Two Drop-Downs

In the example, when the weapon type is changed (you must trap this from the onUpdate of the underlying database node or the onValueChanged of the string control) your script can examine the selected value and selectively setVisible the controls associated with a swords drop-down and a second set of controls associated with a maces drop-down. This will work for more than two drop-downs if needed.

Dynamic Loading

When the weapon type is changed, your script can reset the drop-down contents and load a new list into the drop-down, if you are using the version of the drop-down in the Base Ruleset: this version has dynamic population capabilities using an addItems() method. As I write this, I realise there is no 'clear()' method so I'll add one to the code.

Brief Overview of the Base Ruleset Drop-Down

Tags


<DropDown>
<fonts>
<normal>...</normal>
<selected>...</selected>
</fonts>
<frames>
<normal>...</normal>
<selected>...</selected>
</frames>
<position>...</position>
<size>...</size>
<datasource>...</datasource>
<lookup>...</lookup>
<lookupFieldName>...</lookupFieldName>
<target>...</target>
</DropDown>

The fonts and frames tags determine how the rows render, and typically are set so that the selected row is shaded (using the frame) and has a bold font.

The position tag controls where the drop down trigger is positioned (x,y) relative to the inside top right of the target control.

The size is the maximum number of rows displayed in the drop down list. If there are more entries than this the list will have a scrollbar. If there are less, the list will render shorter.

The datasource and lookup tags are mutually exclusive. If present, the datasource tag points to a list in the db.xml which is the source for the list contents (not the target for the selected item). If datasource isn't specified, the lookup tag is queried to find the name of the global list to use.

The lookupFieldName determines, for complex lists, which field in each record is used to populate the list.

The target tag identifies the string/number control to which the list is bound. The target *can* be readonly, in which case the drop down opens, and the value is properly highlighted, but the user cannot change the selected item. It can also be static (for strings) which allows selection only from the list (users cannot type alternative values into the target control).

Methods

The DropDown is a generic control and the DropDownList (which is created dynamically, so doesn't need to be specified in the sheet data) is a window list control, and hence they expose the same properties/methods as their base classes. In addition, DropDown exposes the following methods.

showList() – displays the DropDownList, but only if it initialises correctly.
hideList() – closes the DropDownList.
getValue() – returns the currently selected value or the empty string if nothing has been selected.
setValue(result) – forces the list to accept the result, but only if it is a valid item from it. It also highlights the item and scrolls to make sure it is visible.
getText() – returns the selected display text or the empty string. Generally the display text and the value are the same, but there may be instances where you want to display are string and store an abbreviation or a number, for example.
add(value, text) – adds the entry to the list. If the text parameter is missing, the value is used for both purposes. If there is only one parameter and it is a table, the code either uses the lookupFieldName to find the right value to use or it looks for a Value field and a Text field in the table.
addItems(list) – recursively calls add() for each item in the list. This can be used to populate a drop down dynamically from code quite quickly.
selectitem(opt) – if passed a pointer to one of the windows in the drop down list itself, this will select that window.

You may note that I have tried to follow the DHTML "select" API, where sensible.

Events

The DropDown exposes no events which can be captured in script, and makes use of the following: onInit, onClickDown, onHover. If you want to make use of these events in script for a DropDown, you'll have to run the 'if super.eventName then super.eventName() end;' test at the beginning of the event handler code to make sure you don't accidentally disable the control.

Other

The control makes use of another template control (<Option>) so you need to copy the code for this across as well. The Option control represents an instance in the list and exposes similar methods/events to the DHTML "option" object.

Finally, a DropDown must have a name otherwise it won't work. This is because it creates sub-controls dynamically and they can be created nameless or with duplicates of existing control names.

Stuart

Visvalor
December 9th, 2009, 18:34
Ok. The visibility part was the easiest for me to wrap my head around :p so I'll go try that and post results in a bit!

Thanks!

Visvalor
December 9th, 2009, 18:51
Ok setting visibility would be dandy except when you get into a few more menus (About 30 options gets messy :P)

How do I just change the value of what is inside <lookup>stuff</lookup>

How do I set stuff as a variable dependent on what is selected in the first menu?

<script>
function onInit()
weaponvar= window.weapon.getDatabaseNode();
weaponvar.onUpdate = update;
update();
end
function update()
if weaponvar.getValue() == "Sword" then
setVisible(true);
else
setVisible(false);
end
end
</script>

Something like that but instead of setVisible , setValue(lookup) ? to something else?

Foen
December 9th, 2009, 19:13
I don't think there is a way to change the contents of a tag (I believe they are read only).

Visvalor
December 9th, 2009, 23:56
My question is can we set the contents of a tag to be a variable or a script

And would tagging a script work :P?

<lookup><script> if then variable stuff</script></lookup>

Seems like it might work.... heh

Foen
December 10th, 2009, 06:04
No, it doesn't work. You can read a tag contents from script:


local myvar = lookup[1];

You cannot write to the tag from script, but you can access many properties controlled by tags using built-in script support (such as using setVisible() to toggle visibility, which is otherwise controlled by the <invisible/> tag).

For custom controls, like the drop-down, any such script support needs to be created by the control author. The drop-down control from Pathfinder doesn't have that support, and the one in the Base Ruleset does have most of that support (except the clear() method was missing).

If you want to have drop-downs that use dynamic lists, you will need to re-write new code into the Pathfinder drop-down, or use the Base Ruleset drop-down and add a clear() method.

Foen

Visvalor
December 10th, 2009, 09:40
weapons = {"sword","mace"}

Ok can be done in globalLookups.lua by any chance :P?

It seems like it could be declared in a string some how o.O?

Foen
December 10th, 2009, 17:07
By all means have a go, but I've tried to outline how I think it could be done.

Visvalor
December 10th, 2009, 17:11
Well I'm trying to find a way other then having 30 menus visible invisible XD

But it worst comes to worst.

Foen
December 10th, 2009, 17:26
My suggestion is to use the revised drop-down in the Base Ruleset, then load the contents dynamically using clear() and addList(). As clear() isn't implemented in the current version, it needs to be added, but the code is straightforward (once you have installed the Base Ruleset drop-down):


In template_DropDown.lua, add:

function clear()
if mylist then
mylist.clear();
end
itemlist = {};
end

in template_DropDownList.lua, add:

function clear()
closeAll();
end

Stuart

Visvalor
December 10th, 2009, 17:28
Sorry my understanding of the script is very limited :P

So I just add that... and how do I get it to load the new menu O.o?

Foen
December 10th, 2009, 17:35
You first need to replace any code you have taken from the Pathfinder ruleset with the equivalent code from the Base Ruleset. I think it is quite complex so I'll have to get back to you on a step-by-step.

Having done that, you need to add the code for the clear() method.

Then you need to add the code that populates the second drop-down based on the selection from the first.

I don't have time now (I'm about to go out) but will try to knock up some sample code over the weekend.

Stuart

Visvalor
December 10th, 2009, 18:27
Woot thanks =D! Foen delivers ^_^!

Foen
December 12th, 2009, 07:12
I have posted an extension on the FG Wiki (https://oberoten.dyndns.org/fgwiki/index.php/DropDown_Lists) which includes all the code required for drop-down lists, including the missing clear() methods, and a demo windowclass that shows how lists can be populated dynamically.

Open any campaign with the extension, then type /test in the chat entry to bring up the demo.

Foen

Visvalor
December 12th, 2009, 07:17
Woot thanks! I'll look into it in the morning :D!

drahkar
January 10th, 2010, 18:35
Got one for you. Can you think of a quick way of locking a field once something has been entered into it? So that it can't be changed again?

Which the first question would be nice, a better one would be if I could set it up so that a player, once then have chosen something from a DropDown, the DropDown disables itself for them. I haven't taken the time to go through the DropDown code to see how hard it would be to incorporate into what you have there and figured I'd get yor thoughts on it.

Foen
January 10th, 2010, 20:42
It could be done, but would be quite field-specific. For example, the field could start off with a default value (say "") and the onValueChanged event would look to see if its current value was the default: if so, it is read/write, otherwise it is read-only. You'd also need to check during onInit.

Foen

drahkar
January 10th, 2010, 21:35
Its the reference that would change the state from read/write to read only I'm looking for. How would I set a field ready only in script? I've had a hard time finding anything referencing to read only.

Foen
January 10th, 2010, 21:40
You would use control.setReadOnly(true) to do that.

For number controls/fields, the documentation is here (https://www.fantasygrounds.com/refdoc/numbercontrol.xcp#setReadOnly), and for string controls/fields, the documentation is here (https://www.fantasygrounds.com/refdoc/stringcontrol.xcp#setReadOnly).

Hope that helps

Foen

drahkar
January 10th, 2010, 21:47
Excellent. That helps a LOT. Thanks!

phantomwhale
December 11th, 2010, 01:03
I have posted an extension on the FG Wiki (https://oberoten.dyndns.org/fgwiki/index.php/DropDown_Lists) which includes all the code required for drop-down lists, including the missing clear() methods, and a demo windowclass that shows how lists can be populated dynamically.

Open any campaign with the extension, then type /test in the chat entry to bring up the demo.

Foen

Hi,

These don't appear to be on the Wiki anymore - I know Obertron had some problems with it, perhaps they got wiped ?

In any case, I was looking to bring some dropdown functionality into Savage Worlds, so can borrow from the BRP ruleset for now. But thought it was worth raising in case others were looking to reuse dropdown menus outside of Smiteworks products ?

Regards,
Ben

Visvalor
December 11th, 2010, 02:14
Reusing dropdown outside of Smiteworks.... I don't understand that last part :P. How can you use the drop down code from a ruleset outside of FG? Is it a LUA thing?

phantomwhale
December 11th, 2010, 03:08
Reusing dropdown outside of Smiteworks.... I don't understand that last part :P. How can you use the drop down code from a ruleset outside of FG? Is it a LUA thing?

I more meant from a legal point of view - for instance, the Savage Worlds ruleset comes with a Card handling library. People have discussed adding cards to many other (free, non-smiteworks owned) rulesets, and suggested extracting the card handling out of Savage Worlds to make it reusable. But as that code is currently "owned" by Smiteworks, it wouldn't really be permissible.

So equivalently, if you wanted to add dropdowns to a non-Smiteworks owned ruleset, and just copied the code out of the BRP ruleset, then you'd be on tenuous legal group, as that code is copyrighted. But if there is an approved extension on the wiki, released outside of copyright, that it's in a lot safer area.

StuartW
December 11th, 2010, 06:47
I have re-uploaded the extension, which was developed outside of a SmiteWorks copyright environment, but then re-used in BRP, so you shouldn't have any problems using this code for your own rulesets or modifications. It remains OGL, so you can't claim it as your own work.

Stuart