Jump to content

Dialog difficulty


Carbon Philter
 Share

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

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

Recommended Posts

Back for more help please, everyone.

I'm messing with a dialog and lists and have been trying to minimise the shedload of if/else if statements needed to cover all the eventualities in the lists.

I've got the script reacting as required in test mode by reporting what dialog button is clicked under either selected submenu but I cannot for the life of me work out how to recall the main dialog to make a second selection on the other submenu without having to reclick on the prim..

I reckon it has to be something to do with recalling the script back to the main dialog menu or resetting it somehow. I tried using llResetScript at the end but that somehow just cancels out the OwnerSay report of the clicked button and I then tried recalling the main dialog at the end but that too seems to just be ignored.

Is it possible to recall the main dialog or do I have to revert to using all the if statements or, worse still, accept having to click the prim two times to get to each submenu selection?

Thanks in anticipation.

Script follows:

 

list Main = ["Number", "Distance", "Close"]; //main menu buttons

list Ldist = ["7", "8", "Back", "4", "5", "6", "1", "2", "3"];
list Lno = ["G", "H", "Back", "D", "E", "F", "A", "B", "C"];

string vnumber;
string vdistance;

integer menu; //variable to keep track of which menu is chosen

default
{state_entry() //when script starts
    {
        llListen(10,"", llGetOwner(), "");
    }
    touch_start(integer x) //when touched
    {   //make menu variable equal 0
        menu = 0;   //show main menu, called Main
        llDialog(llDetectedKey(0), "Click on button to change number or distance", Main, 10);
    }
       
    listen(integer channel, string name, key id, string message)
    {
        if (menu == 0) //if the object is touched
        {
          if (message == "Number") //number is chosen
           {
              menu = 1;    //make menu variable equal 1
            llDialog(id, "Choose the number", Lno, 10);
            }
            else if (message == "Distance") //distanceis chosen
           {
              menu = 2;    //make menu variable equal 2
            llDialog(id, "Choose the distance from rezzer", Ldist, 10);
            }
            else if (message == "Close")
           {
             }
        }

        else if (menu == 1) //if menu equals 1, number is chosen
        {
            vnumber = message;
            llOwnerSay(vnumber + " has been clicked");
        }


        else if (menu == 2) //if menu equals 2, distance is chosen
        {
            vdistance = message;
            llOwnerSay(message + " has been clicked");
        }
//        llResetScript();     
    }
}

Link to comment
Share on other sites

But as I understand it, a script reset isn't really what you want to do anyway.  Rather, I think you want to reprompt with the Main dialog whenever "Back" is selected from either submenu.  So, I'd add the following to the listen() handler, before the test for menu==1 :

        else        if ("Back" == message)        {            menu = 0;   //show main menu, called Main            llDialog(id, "Click on button to change number or distance", Main, 10);        }

 You might also want to make this bit into a function, because it also appears almost identically in the touch_start() handler.

Link to comment
Share on other sites

The method I use is to have a "curmenu" (current menu) string variable that defaults to "Main Menu". The values are exactly what's on the buttons. So when the "Sub-menu 1" button is clicked, the Listen handler treats it just like any other menu button. It sets the "curmenu" variable's value to the button text (the message) and calls the menu() routine. The menu routine decides which set of buttons to display according to the value of curmenu..

menu(){

if(curmenu == "Main Menu"){

// set up the buttons string for the "Main Menu"

}else if(curmenu == "Sub-menu 1"){

// set up the buttons string for "Sub-menu 1"

}else if

....

}

llDialog(....);

}

 

listen(...............){

if((message == "Main Menu") || (message == "Sub-menu 1") || (message == "Sub-menu 2")){

curmenu = message;

}else if(..........){

// handlers for non-menu buttons

}

menu();

}

 

Something like that. The listen handler can test the curmenu variable so that buttons with identical names can be used in different menus.

You can get rid of a few "if...else" lines but I don't think you can get rid of many. For instance, you could have the button strings in a list - one list element for each menu - and use "curmenu" as an integer/index to the list. But, if the text on one or more buttons is set according to something else (e.g. an on/off toggle) then it's easier to do the if...else if checks.

On the other hand, the MLP system uses someone's menu system that does it completely differently.

Link to comment
Share on other sites

Thnaks for response, guys. I'll have to do some more thinking.....

Qie, on first look I reckoned yours was the straighforward solution but unfortunately it doesn't perform as expected. What I was hoping is that once making the selection of either distance or number value, the main dialog would reappear to allow access to the other submenu. I added your suggested code and the script works as before - dialog closes after first value is selected - but with addition that clicking 'Back' gives me the report that Back was clicked and dialog still simply closes.

Phil, I think ( :) ) I understand your concept but it looks a tad more complex on first pass so will have to go concentrate to try to absorb the principles as you describe your approach.

 

Carbon

Link to comment
Share on other sites

These things are only difficult to grasp and understand when we haven't yet understood them. When we've got it, they are really very simple :)

The method I use really is very simple.:-

If a menu button is pressed, the listen handler simply changes the value of the "curmenu" variable to the requested menu - the main menu or a submenu. If a non-menu button is pressed, the listen handler does what it needs to do for the button and leaves the "curmenu" variable alone. At the end of the listen handler, the menu() routine is called. The menu() routine simply sets up the buttons string according to the "curmenu" value.

I use the text on the menu buttons for the "curmenu" value. You're using an integer value (0 for the main menu). My way needs fewer lines because I also use the button/"curmenu" name/value in the dialog's text an the menu's name

The difficulty with using a "Back" button in the way that Qie described, is keeping tabs on where you are when submenus have submenus and so on, and each with a "Back" button. I did it with Back buttons once, and it wasn't anywhere near as simple as my usual method. Qie is a top scripter, btw, and he does know what he's writing about.

Link to comment
Share on other sites

I am not sure if I understand your problem, but for what i understand this should make the trick

     else if (menu == 1) //if menu equals 1, number is chosen
        {
            vnumber = message;
            llOwnerSay(vnumber + " has been clicked");
            menu = 0;   //show main menu, called Main
            llDialog(id, "Click on button to change number or distance", Main, 10);
        }

        else if (menu == 2) //if menu equals 2, distance is chosen
        {
            vdistance = message;
            llOwnerSay(message + " has been clicked");
            menu = 0;   //show main menu, called Main
            llDialog(id, "Click on button to change number or distance", Main, 10);
        }

Link to comment
Share on other sites

I am glad I did :matte-motes-smile:

The logic is very easy. Every time you call the llDialog you bring up your pop up menu. Every time you click a button on the menu the script run into the listen event. So if you need another menu you have to do it here (as you already did with your sub menus) as when the listen event is processed the script is waiting for the next click.

Link to comment
Share on other sites

Another straightforward approach (actually a variant of Georg's suggestion) is to put your main dialog in state default and have it direct all selections to a new state, in which you do all your branching to subdialogs.  If the user clicks a "Reset" button in any of those subdialogs, jump back to state default.  It's like resetting the script but much less drastic.  Changing states also clears all open listen handles, so you aren't leaving orphan dialogs behind.

Link to comment
Share on other sites

another example....

list gLstTop = ["Letter", "Number"];list gLstLtr = ["a", "b", "c"];list gLstNum = ["1", "2",, "3"];uDialog( key vKeyAvt ){    llDialog( llGetOwner(), "Main Menu", top + ["cancel"], 10 );}default{    state_entry(){        llListen( 10, "", llGetOwner(), "" );    }        touch_end( integer vIntTch ){        uDialog();    }        listen( integer vIntChm, string vStrNom, key vKeySrc, string vStrMsg ){        if (~vIntChn = llListFindList( gLstTop + gLstLtr + gLStNum, [vStrMsg] )){            if ((gLstTop != []) > vIntChn){ //-- main menu choice //-- pop a dialog for which ever menu and tack a "back" button on the list            }else{                if ((gLstLtr != []) > (vIntChn -= (gLstTop != []))){                    //-- letter was chosen                }else{                   //-- number was chosen                }                uDialog(); //-- remenu main for letter/number choice            }        }else if ("back" == vStrMsg){            uDialog();        }    }        changed( integer vBitChg ){        if (CHANGED_OWNER & vBitChg){            llResetScript();        }    }}

 the trick here is to search all the lists at once, without having the "back" buttons in there, then always remenu to the main if a sublist choice was made, and do the same if the back button was chosen... you could cheat and include the back button in the sublists, and just ignore it in the listen, but this lets you handle it separately so that you could add logic that says if both a letter an number are already stored, don't remenu, and instead do something else. optionally you could menu directly to the other sub if you get a value for one.

ETA:
notice we don't actually test for the cancel button... essentially, if it's not a valid menu index we do nothing, just as if the ignore button was pressed on the dialog.

Link to comment
Share on other sites

Every time you use that trick of reassigning the channel number variable, I swear I'm going to remember it, but I always get surprised the next time.  :smileyhappy:

This time, though, I don't quite see what's going on.  Should it be

if (~(vIntChn = llListFindList( gLstTop + gLstLtr + gLstNum, [vStrMsg] )))     ?  That is, doesn't the ~ act on the entire definition in parens?  Or is an extra set of parens not necessary?

Link to comment
Share on other sites

works the same either way, because assignment is a higher precedence, although the parens could be used to make it explicit. in most languages it will either work as expected, or give a compile error w/o the extra parens

it is quasi-bad practice to do reuse variables like that... normally if you would be using the channel value, you shouldn't re-use it for something else... but since we never actually use it's original value, there's no sense in declaring another variable when one is already sitting there, so that part is good.

quasi bad, in that if you do later want to edit it and add code that makes use of the original value, you may get unexpected results.

Link to comment
Share on other sites

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

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

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...