PDA

View Full Version : Turning off inventory sorting while typing in location field



darrenan
March 1st, 2015, 01:27
Some of my players have been complaining about the behavior of the location field in the inventory list, and how it sorts while typing (this is in 3.5e/PFRPG, but it appears the functionality is in CoreRPG and not overridden in the 3.5e ruleset). The name field doesn't behave this way (it sorts only after losing focus) and they would like the location field to behave the same way. I've been trying to track down what's causing this, to no avail.

I have figured out that the onSortCompare function is getting called everytime a key is pressed. According to the docs this should be called in response to an applySort() call, but I put Debug.chat calls before every applySort() call I could find and none of them appear to be getting called. It doesn't appear to me that the onChar handler in char_invloc.lua is causing this either.

Can someone explain what I'm missing here? Should it be possible to disable the on-type sorting behavior in this list?

Thanks,
D.

Trenloe
March 1st, 2015, 02:31
I'm seeing the sorting happening in CoreRPG as well as 3.5e - as soon as you start typing the location it does a match to the characters you're typing with items already in your inventory and moves them under that item. For example, if you have a backpack and you start typing b-a it will match to the Backpack (if that is the only item starting with b-a) and move the item in question to be listed under the backpack item.

This selection and sorting occurs in CoreRPG in campaign\scripts\char_invloc.lua in the onChar() function. You might be able to move the setSelectionPosition line to the onLoseFocus() function in the same file to only move the item to the location when you tab out. I don't know how well this will work in practice.

darrenan
March 1st, 2015, 02:36
I don't think the onChar function is doing anything more than searching for an autocomplete string, setting the field's value to the found string, and then highlighting the appropriate part of it. I don't see any sorting happening there at all. setSelectionPosition just changes the highlighting of a portion of the string being displayed. Also, if it doesn't find a string that matches what you're typing, everything inside that "if" statement doesn't get executed at all, yet the sorting behavior still happens, so clearly something else is triggering applySort().

EDIT: I have proved this by commenting out the entire contents of the onChar function. The sorting still happens correctly, but autocomplete has been disabled.

darrenan
March 1st, 2015, 03:16
I guess the question I have for Doug or MW is what can trigger a windowlist.onSortCompare other than calling applySort() OR, does applySort() ever get called implicitly as part of some other function? Because I can clearly see onSortCompare getting called many times every time I type a character in the location field. But none of the applySort() calls that are actually in the CoreRPG lua are getting called (which I verified using Debug.chat right before each one).

Trenloe
March 1st, 2015, 03:43
Yeah, I'm seeing the same thing - onSortCompare getting called all the time and no specific applySort or <sortby> parameter for the windowlist in question.

To turn sorting off while the location field has focus try the following. Code in red is new code to add, black is existing code (lots of code removed where you see ...).

In campaign\scripts\char_invlist.lua:


--
-- Please see the license.html file included with this distribution for
-- attribution and copyright information.
--

locationLocked = false;

function setLocationLock(isLocked)
locationLocked = isLocked;
end

function onInit()
OptionsManager.registerCallback("MIID", StateChanged);
...
...
...

function onSortCompare(w1, w2)
if locationLocked then
return false;
end

local n1 = w1.getDatabaseNode();
local n2 = w2.getDatabaseNode();
...
...
...


In campaign\scripts\char_invloc.lua:


...
...
...
function onGainFocus()
window.windowlist.setLocationLock(true);
aAutoFill = {};
...
...
...
function onLoseFocus()
window.windowlist.setLocationLock(false);
super.onLoseFocus();
...
...
...

darrenan
March 1st, 2015, 03:51
I think that would have really strange results. By returning false you're telling it that w2 > w1. That will likely change your entire list in weird ways. I'll try it though, should be amusing.

EDIT: That actually seemed to work. I guess I was wrong. Thanks a lot!

EDIT2: I guess because the list is already sorted in that order as it walks through the list, always returning false shouldn't change anything. Took me a minute to wrap my head around that, but it makes sense now.

EDIT3: I would still like to know what is causing the sort to be called in the first place though...

darrenan
March 1st, 2015, 04:41
Here 'tis, in case anyone wants this functionality: 9242

Tagged for CoreRPG, 3.5e, 4e, 5e, PF and CnC.

Trenloe
March 1st, 2015, 05:47
EDIT3: I would still like to know what is causing the sort to be called in the first place though...
Doing a little digging... The answer is in the control templates. Location uses template string_charinvloc and name (which doesn't sort until losing focus) uses string_charinvname. The definitions are in campaign\template_char.xml:


<template name="string_charinvname">
<string_textlistitem>
<script file="campaign/scripts/char_invname.lua" />
</string_textlistitem>
</template>
<template name="string_charinvloc">
<string_textlistitem>
<nodelete />
<delaykeyupdate merge="delete" />
<script file="campaign/scripts/char_invloc.lua" />
</string_textlistitem>
</template>

These are both based on template string_textlistitem (common\template_lists.xml):


<template name="string_textlistitem">
<stringu>
<delaykeyupdate />
<script file="common/scripts/list_textitem.lua" />
</stringu>
</template>

The key here is the delayupdate parameter. Info on this here: https://www.fantasygrounds.com/refdoc/stringcontrol.xcp What this means is that if this is present "If present and editing the value of this control using the keyboard, changes won't be written to the database and update event functions will not be called until the focus is moved away from the control." So, as standard, any control based on the string_textlistitem template won't run any update code, if there is typing in the control, until the control loses focus.

Now, notice that the original definition of string_charinvloc actually removes this parameter: <delaykeyupdate merge="delete" /> Therefore, for this control the update events *will* be executed each time a key is pressed in the location field - which results in the onSortCompare code being executed.

Note: just removing the <delaykeyupdate merge="delete" /> from the template won't be enough to stop the onUpdate (and sort) code running as the onChar event mentioned by me in an earlier post will trigger an event with setValue and so the onSortCompare code runs. So, it appears that the best solution is the lock flag discussed above.

Hope that is clear (as mud?) as to why the onSortCompare runs for location and not name - and why it runs after each key press.

darrenan
March 1st, 2015, 20:25
Nice. I had looked at all those files and for some reason I completely overlooked delaykeyupdate everytime. Thanks for sleuthing that out!

darrenan
March 1st, 2015, 20:51
Still trying to connect the dots here, just for my own edification. If someone can confirm this it will really help my understanding of how things work.

Does string_charinvloc automatically call windowinstance.notifyUpdate on it's parent window (the list item windowsclass/instance) when it changes? Per the documentation:


function notifyUpdate( )

Notifies the window that some of its contents have been changed and a minimized window should be hilighted.

Most built-in controls call this method automatically, but this may be useful for some custom control types and data handling schemes.

If so, that gets the change notification up to the list item level. What is the mechanism for bubbling the event from there up to the list itself, where the sorting actually occurs? When windowinstance.notifyUpdate gets called, does it automatically call the parent's notifyUpdate as well? That would explain it if true.

Sorry for beating this dead horse, just trying to understand how things work.