Jump to content

Multiple Dialog Menu Lists (Resolved)


MCSythera
 Share

You are about to reply to a thread that has been inactive for 2992 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I have been scouring around for a way to make infinite lists show on dialog menus, as those can only show 12 at a time. The below was modified from Free LSL Scripts. Using 35 test list items, the problem I am encountering is that on the second page, options 10 and 11 repeat. So page one shows 1-11 and the ---> buttons. Page two is ---->, <---- and options 10-19, when it should be 12 to 21. (Page three is 19-28, page four is 28-35, so those two pages only repeat 1.) What would I do to change this?

numSouls = llGetListLength(collectedAvatarIDs);
        if(menuPosition >= 9)
            tempStorage += "    <----";
        else{  }
    
        if (numSouls > menuPosition+9)
            tempStorage += "    ---->";
        else{  }
    
        if (numSouls > 0){
            integer b = menuPosition;
            for( ; b < numSouls; b++){
                tempStorage = tempStorage + [llList2String(collectedAvatarNames,b)];
            }
        }
        tempStorage = llDeleteSubList(tempStorage,12,999);

 

Link to comment
Share on other sites

I wrote a menu handler for rezzing items out of an inventory storage box.  Its a little long winded but it will handle any number of items and deal with the 24 character limit on buttons.  Feel free to adapt as needed.

I won't try and post the code in this message ...just follow this link 

https://wiki.secondlife.com/w/index.php?title=User:Susie_Chaffe

Link to comment
Share on other sites

Look at your code.  You have twelve buttons to play with.  If you have more than 10 list tems, you use one of those for the ---> button.  Then you lose another button to <--- once you're on page 2.  So, you need another variable to track how many of those buttons are lost.  Then you need to subtract that number from the upper range of list items before you construct each new page.  THEN you need to adjust the starting position (menuPosition) itself.

numSouls = llGetListLength(collectedAvatarIDs);integer DirButt;  //Here's your extra button count        if(menuPosition >= 9) //You are beyond page 1        {            tempStorage += "    <----";            ++DirButt;  // Increment it to account for the back button            --menuPosition; // And decrease your starting position by one        }            if (numSouls > menuPosition+9)  //There will be more than one page        {            tempStorage += "    ---->";            ++DirButt;  //Increment it to account for the forward button            if (menuPosition >= (9-DirButt)) //And if you're beyond page 1 ....            {                --menuPosition; //... decrease the starting position by one more            }        }            if (numSouls > 0)        {            integer b = menuPosition;            for( ; b < numSouls - DirButt; b++)            {                tempStorage = tempStorage + [llList2String(collectedAvatarNames,b)];            }        }        tempStorage = llDeleteSubList(tempStorage,12,999);

 I have NOT tested this in world, but the logic looks correct.

ETA:  OK, now I have tested it in world.  I'll leave this post here, but it's not right.  See below.....

 

Link to comment
Share on other sites

Comparing your (incomplete) code example to the script you're modifying, it would be impossible for anyone to correct with what you're offering.

 

For instance, the significance of the number "9" lies with the original script never having more than 9 choices from the listing used in the dialog: The author always includes "[Clear]" and, where you've blanked the else's, always has either a back arrow, a forward arrow or uses "-" in those places instead. So, 12 - 3 = 9.

 

Furthermore, that "9" is used elsewhere in the code, outside of the Menu() subroutine, to update the "menuPosition" variable, so those would require changing as well for your code to work, to reflect the different way you're handling your menus.

 

[ETA] To keep it simple, if you're not going to use a "[Clear]" button, put back the "-" space holders in the else statements and simply change all the occurances of 9 to 10.

Link to comment
Share on other sites

The solution I posted earlier was bothering me because it depended on how the rest of the script was written, as Leprekhan pointed out.  Thus, it could lead to bad menus if you weren't thinking about the rest of the script the way I had it laid out in my mind.  Worse, I don't like the way the OP's script builds a potentially monstrous tempStorage list and then chops off all but the first 12 entries.  It's wasteful of resources.

Here's a full script that is loosely based on the OP's original one but gets around building an unnecessarily long tempStorage list.  To do it, I had to write a somewhat bizarre-looking test into the for loop in my Menu routine, but it works.  Aside from ugly, is there a good reason not to do it this way?

list collectedAvatarIDs = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];list collectedAvatarNames = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y"];integer menuPosition;integer gLsn;Menu(){    integer Last;    list tempStorage;    integer numSouls = llGetListLength(collectedAvatarIDs);    if(menuPosition >= 9)   //This is NOT the first menu page    {        tempStorage += "    <----";    }        if (numSouls > menuPosition+9)  //If there are menu pages beyond this one ....    {        tempStorage += "    ---->";    }    else    // This is the last menu page    {        Last = TRUE;    }    if (numSouls > 0)    {        integer b;        integer len = llGetListLength(tempStorage);        //Behold a bizarre test .....                for(b = menuPosition + len + Last - 1 ; (len < 12)&&(b < numSouls); ++b)        {            tempStorage = tempStorage + [llList2String(collectedAvatarNames,b)];            len = llGetListLength(tempStorage);        }    }    gLsn = llListen(-12345,"","","");        llSetTimerEvent(10.0);    llDialog(llGetOwner()," \n",tempStorage,-12345);}default{    touch_start(integer total_number)    {        llListenRemove(gLsn);        menuPosition = 0;        Menu();    }        listen(integer channel, string name, key id, string msg)    {        llListenRemove(gLsn);        llSetTimerEvent(0.0);        if (~llSubStringIndex(msg,"---->"))        {            menuPosition += 10;        }        else if (~llSubStringIndex(msg,"<----"))        {            menuPosition -= 10;        }        Menu();    }        timer()    {        llSetTimerEvent(0.0);        llListenRemove(gLsn);    }}

 

 

  • Like 3
Link to comment
Share on other sites

Yes, sorry for not including more of the code, I included what I thought was the issue. Currently the whole thing I have is over 1000 lines, so yeah. But that does look great. I will see about using that. I'm still going to have to rewrite most of the code I have now because I wanted to change a few things. I don't expect the lists to get too high, and I plan to change some of the tests over to use the avatar ID to determine name instead of storing it in a list. But it's still important to have a way to order the lists.

 

Second question, which I have not figured out a good way for, is what should I do for the selection? For example, if someone picks option 15 from page 2, that's obviously just option 15. But right now the only way I've found to do that is to go down the list if(msg == llList2String(collectedAvatarNames,15)){ // do for 15 }. There has to be a better way to do that. I've thought of do-while and for loops, but that always gives me the last option in that list, not the one that is selected.

Link to comment
Share on other sites

You don't need to do much searching.  You have the selected name from the button label, and your two lists are in exactly the same order. So

integer idx = llListFindList(collectedAvatarNames,[msg]);key This_AvID = llList2Key(collectedAvatarUUIDs,idx);

 You don't even have to check for if (~idx) since you know that the message began life as an element in collectedAvatarNames. In your specific example, idx will turn out to be 15, but you don't need to know that up front.  That's what llListFindList tells you.

Link to comment
Share on other sites

I see, very nice. That certainly makes things simpler.

 

Now I notice you keep using ~, in front of the msg for the back and forward buttons, and then above in a check I wouldn't have to do. I looked it up and they don't explain it very well. What does it actually DO in the instance of checking to see if the msg is equal to the forward or back button?

Link to comment
Share on other sites

~ is a bitwise NOT.  Using it reverses all bits in the number it's applied to. So ~n = -(n+1) .  Thus, you will find that ~n is ZERO when n = -1 but non-zero for all other values of n.  In LSL, 0 = FALSEllListFindList will return a value of -1 if it can't find what you're looking for.  Therefore, ~llListFindList([0,1,2,3,4,5,6],[n])  will only be TRUE (that is, non-zero) if n is in the range [0,1,2,3,4,5,6].  If you don't include the ~ operator, you'll miss the case where n = 0.

Link to comment
Share on other sites

Okay, I don't really know how to implement those into a listener.

 

        integer idx = llListFindList(detected,[msg]);        key idxID = llList2Key(detected,idx);        if(msg == llList2String(llParseString2List(llGetDisplayName(idxID),[" "],[]),0)){            time = 0;            string spanked = llList2String(llParseString2List(llGetDisplayName(idxID),[" "],[]),0);            llPlaySound("475a3e83-6801-49c6-e7ad-d6386b2ecc29",1.0);            llSay(0,"Sythera spanks "+spanked+" hard!");        }

 Shouldn't that work when the menu buttons are formatted to show llList2String(llParseString2List(llGetDisplayName(avatarUUID),[" "],[]),0)?

Link to comment
Share on other sites

OK, forget the math.  Let's just do examples....

Let  list Letters = [ "A","B","C","D","E","F"];

llListFindList( Letters ,["B"]) = 1 , so if( llListFindList( Letters, ["B"]) ) evaluates to if (TRUE)

llListFindList( Letters ,["A"]) = 0 , so if( llListFindList( Letters, ["AB"]) ) evaluates to if (FALSE)

Now try the same thing with ~

~llListFindList( Letters ,["B"]) = 1 , so if( ~llListFindList( Letters, ["B"]) ) evaluates to if (TRUE)

~llListFindList( Letters ,["A"]) = 0 , so if( ~llListFindList( Letters, ["A"]) ) evaluates to if (TRUE)

That is, if you are looking to see if the letter "A" is anywhere in Letters, asking without the ~ will give you the wrong answer because it will miss the first element in the list.  If you include the ~, you will get the correct answer: "YES, the letter "A" is in the list Letters."

Link to comment
Share on other sites

Oh, so the check would be as simple as

else if(~llListFindList(detected,[msg])){        time = 0;        llPlaySound(“475a3e83-6801-49c6-e7ad-d6386b2ecc29”,1.0);        llSay(0,”Sythera spanks “+msg+” hard!”);}

 That checks the entire list, 0 (first selection) included, and if the selection is in the list, says the name that was selected? Or would that just return it as the number where the selection is in that list, and output a number instead of the button name?


I can already see the issue that that, as the 'detected' list is a series of IDs, from which the names are drawn into tempStorage for the selection. How would I get the list position that is clicked to determine, in this case, who to spank?

Link to comment
Share on other sites

But the buttons in the menu are the first display name of that avatar ID. So the button selection is not in the list. Instead, I've just changed else if to else and that way when they select an option not on the standard menu options (IE: a name from the sensor sweep), it will just say their name via msg.

Link to comment
Share on other sites

Yeah, they would be. Because to build the buttons all I did was filter out the display name from the ID. So ID at position 3 would have display name name and clicking name on the menu button would be the 4th button. What I didn't understand above was how to go through the lists of IDs to get the same position as the button with name on it, while listening for name and not a position or ID.

Link to comment
Share on other sites

I really don't understand what the problem is.  When someone clicks a dialog button other than your forward or back buttons, they are clicking on a name. You have a list of names and a parallel list of IDs.  If you know one, you know the other.  Take a look at the generic form of the solution I posted, now at http://community.secondlife.com/t5/LSL-Library/A-Simple-MultiPage-Dialog-Menu-System/m-p/2126747#M726 .

Right at the bottom, after disposing of the two directional buttons, see

        else        {            //Do whatever the selected button directs..... your choice        }

 

Link to comment
Share on other sites

Oh! I wasn't being clear. I'm not using the same example as before where I was using parallel lists of IDs and names. I'm only using a list of IDs, and extracting the name from the ID for use in the dialog buttons. The names are not actually stored anywhere but during the sorting of the buttons when displayed (tempStorage). But yeah, I changed my else if to else, so that it does work, because msg is the name on the button, so I can just use msg itself without evaluating it in any way. Essentially, it means that I account for all pre-made dialog options, forward and back buttons included. The only other buttons displayed are the names of the evaluated IDs in the list, so that if any name is clicked, it automatically does the action I want for that name using msg to determine that clicked name.

Link to comment
Share on other sites

That's fine, but you do have a list of the names used on the current set of dialog buttons (tempStorage) and you know which UUIDs were used to create them.  Therefore, every time you click a button and send a name as msg, you also implicitly know the UUID that goes with it.  The simplest (and safest) way to tie the two together explicitly would be to keep a second temporary list of UUIDs every time you generate a tempStorage list.  The more elegant and viscerally rewarding way would be to calculate how tempStorage relates to your master list of UUIDs. Either way would work.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2992 days.

Please take a moment to consider if this thread is worth bumping.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...