PDA

View Full Version : Ordered window lists



phantomwhale
October 1st, 2011, 01:29
Had a bit of a ramble in a different thread, but today has bought me to a core understanding that I think was lost on me - is it true to say we don't have ordered window lists ?

I understand we can set the onSortCompare() function, and maybe that's what I need here, but I want a list that will just be implicitly ordered. So every newly added entry is always the "last" entry.

Right now this is not the case. If you create a three entry list (id-0001, id-0002 and id-0003) and delete the middle entry, then the next entry you create will be id-0002. It will appear on the bottom of the window list, but once the window is closed and reopened, it then appears in the middle of the list.

So one thought is I need to override window creation to ensure the generated id number is always the latest one (e.g. don't reuse missing sequence numbers) - and then the default sorting works for me. Or maybe I need to add a hidden "order" number on the elements and the list itself to facilitate this ? The advantage of that is I could later add buttons to resort the list later on, and changing node values is easier and less client side-effect prone that changing database node names.

Has anyone already done something like this ? Most window lists seem to be sorted on name in the rulesets I've looked at, but I need a list of grouped enemies, and I don't want the order changing randomly - plus I want to be able to figure out who is the leader from the database nodes alone, as I have a problem using the library functions to access windowlists within windowlists on the client side (they appear as blank, even though the data has been sent over).

-PW-

StuartW
October 1st, 2011, 06:48
I'd use a hidden 'order' field on the window entries and sort on those. You'd need some code to work out what the next value should be: for short lists, you could iterate over the list once, retrieve the current highest value, and then add 1 to it. Unfortunately you can't just take the size of the list (#entries) and add 1, if items can be deleted from the middle of it.

Stuart

Moon Wizard
October 2nd, 2011, 09:39
The other option is that you could create the database records under the windowlist data node explicitly using any valid XML name, instead of the default window creation logic. The id-XXXXX format is just the default format for windowlist creation.

The other thing to mention is that the sorting is not stable within FG unless your onSortCompare function has a unique value to filter on. (i.e. list elements will constantly reshuffle) This is why I added the w1.getDatabaseNode().getName() < w2.getDatabaseNode().getName() as the last line in all of the onSortCompare functions in the 3.5E ruleset revision.

Regards,
JPG

phantomwhale
October 2nd, 2011, 13:30
Yeah, I had just noticed that the "default" sorting sometimes fails too ! (although the first element is always the same, so that was all I really needed).

Will add the "sort by node name" function to lists as the default, but may go for a hidden ordering flag to allow me to reorder elements within a list by changing a single node value, rather than changing a node name (which would technically need to be an add and delete, I think, as nodes cannot be programatically renamed, probably for a good reason too !)

Thanks for pitching in guys, starting to see some light at the end of the tunnel on this one.

phantomwhale
October 3rd, 2011, 10:52
First cut at this - have hit a problem with the super variable though.

Firstly, I created a nice ordered list template:



<template name="orderedlist">
<windowlist>
<script file="scripts/template_orderedlist.lua" />
</windowlist>
</template>


And then the code as follows:



local lastIndex = 1
local orderingNode = "order"

function onInit()
for _,node in pairs(getDatabaseNode().getChildren()) do
lastIndex = math.max(lastIndex, node.getChild(orderingNode) and node.getChild(orderingNode).getValue() or 1)
end
lastIndex = lastIndex + 1

-- tried to create window here (see notes)
end

-- override creating windows to set the order field
function createWindow(...)
Util.debug("Creating ordered window")
win = super.createWindow(...)
if not NodeManager.get(win.getDatabaseNode(), orderingNode) then
local ordernode = NodeManager.createChild(win.getDatabaseNode(), orderingNode, "number")
ordernode.setValue(lastIndex)
lastIndex = lastIndex + 1
end
return win
end

-- Sort by order index value - maintains list order
function onSortCompare(w1, w2)
if not w1.getDatabaseNode().getChild(orderingNode) then
return false
elseif not w2.getDatabaseNode().getChild(orderingNode) then
return true
else
return w1.getDatabaseNode().getChild(orderingNode).getVal ue() > w2.getDatabaseNode().getChild(orderingNode).getVal ue()
end
end


What I noted was the debug line never got called, and the ordering nodes were not being set.

How odd, I thought. so looked around the code for a while, and then tried adding in two different commands in the onInit() method. Firstly I added self.createWindow() as the last line. The effect of this were all new lists had an extra blank window entry - but still no calls to the debug method ?

Secondly, I tried super.createWindow() and was told I had a Script Error trying to index global 'super'. So it seems that in my template that wraps the windowlist object, I don't have a super environment variable to refer back to the original createWindow() method ? Furthermore, attempts to call createWindow(), even using the self variable (which should call the overloading method, always use the in built method that I am unable to access ?

So my conclusion is that createWindow() is impossible to overload ? (I think getDatabaseNode() also behaves like this). I am confused here, as I'm sure that I've overridden this method successfully before in other coding experiments, but admittedly can't be positive of that.

Moon_wizard - any chance of confirming this ?

I guess I can try subscribing to the best "event" I've got as a different strategy, which is probably onChildAdded() on the database node. But wanted to see if this solution works first, as it seems more elegant right now !

phantomwhale
October 3rd, 2011, 11:23
Ok, popped a getDatabaseNode().onChildAdded = onWindowCreated event handler into the onInit() method and added the following to replace the createWindow(...) overload :


function onWindowCreated(source, child)
if not NodeManager.get(child, orderingNode) then
local ordernode = NodeManager.createChild(child, orderingNode, "number")
ordernode.setValue(lastIndex)
lastIndex = lastIndex + 1
end
end

Looks pretty good now. Still interested in the use of super to refer to "core engine" methods though.

Moon Wizard
October 5th, 2011, 23:44
I'm pretty sure that you can not overload the default function names for FG objects. However, you can override the function names from derived objects (i.e. templates).

This means that you want to avoid using the same function names as the ones FG provides. It also means that you can not override the FG internal functions, which is good since the internal functions are not called through LUA and would not see the overloads anyways.

Regards,
JPG