User:ANSI Soderstrom/Extended Dialog Example

From Second Life Wiki
Jump to: navigation, search

Leave a comment

Extended Dialog Example

Some People in SL are asking me, how would myself realize a extended dialog menu (with timeout, dynamic content, sort-option, ...)

Before i invent the wheel every week new, i will post my "best" code here, so in future i can simply refer to this page.

<lsl> // Extended Dialog Example for your Items // (C) 09/2010 ANSI Soderstrom

// First, let us define some example choices... list TEST_DIALOG_CHOICES = ["A","B","C","1","2","3","a","b","c","test1","test3","test2"];

float TimeOut = 30; // (in Seconds) We need a Timeout for the Listener, not least because laaaaag. float maxButtons = 12; // How many Buttons shall we have per Page ? (12 is the maximum)

integer Sort = TRUE; // Should i Sort the List ? (Logically) 0..9 --> a...b --> A...B integer Sort_Ascending = TRUE; // (TRUE = Ascending, FALSE = Descending) permute the list vertically. Have only Effect if Sort == TRUE;

integer CHANNEL; // We need a global channel... integer PAGE; // ...and a global memory for the actual Pagenumber

key LastMenuUser; // ...and don´t forget who is the actual controluser.

list CreateNavigation(integer PAGES) {

   list navi = ["No Clue"];
   if((PAGE < 1 || PAGE == PAGES) && PAGES != 1) { 
       PAGE = PAGES; 
       navi += ["<<<","FIRST"];
   } else if((PAGE > PAGES || PAGE == 1) && PAGES != 1) { 
       PAGE = 1; 
       navi += ["LAST",">>>"];
   } else if (PAGES != 1) {
       navi += ["<<<",">>>"];
   }
   if(PAGES==1) {
       navi += [" "," "];
   } 
   return navi;   

}

list Padding(integer FillUp) {

   list PlaceHolder;
   if(FillUp<0) { 
       do {
           PlaceHolder += ["~"];       // Nr# 126 in ASCII Table (Highest one, will be ever the last Letter in List?)
           ++FillUp;
       } while(FillUp!=0);
   } 
   return PlaceHolder;

}

CreateMenu(key id, list menu) {

   if(Sort) {
       menu = llListSort(menu,1,Sort_Ascending);
   }
   integer PAGES = llCeil(llGetListLength(menu)/(maxButtons-3));
   list NAVIGATION = CreateNavigation(PAGES);
   integer length = (integer)maxButtons-llGetListLength(NAVIGATION);
   list NEW_MENU = llList2List(menu,(PAGE*length-length),(PAGE*length-1)) + Padding(llGetListLength(menu)-(PAGE*length));
   llDialog(id, "(Page " + (string)PAGE + "/" + (string)PAGES + ")\n \nSelect your Height",NAVIGATION + NEW_MENU, CHANNEL);    

}

default {

   state_entry() {
       // prevent errormessages
       if(maxButtons > 12) {
           maxButtons = 12;
       }
       // Let us scramble the List... (...as example)
       TEST_DIALOG_CHOICES = llListRandomize(TEST_DIALOG_CHOICES,1);
       // and clear the timerview
       llSetText("",<1,1,1>,1); 
   }
   
   touch_start(integer i) {
       // If we touch in this state, iam sure we are on the first Page
       PAGE = 1;
       // Let us find a random channel
       CHANNEL = -llRound(llFrand(1000000));
       // remember for the user
       LastMenuUser = llDetectedKey(0);
       // All done, we have the point to create our first menupage
       CreateMenu(LastMenuUser,TEST_DIALOG_CHOICES); 
       // and for better code reading, we use a new state !
       state Dialog;
   }

}

state Dialog {

   state_entry() {
       // Listen to the opened channel
       llListen(CHANNEL,"",NULL_KEY,"");
       // and count the time down to our timeout
       llSetTimerEvent(1);
       // Reset the timer...
       llResetTime();
   }    
   
   listen(integer channel, string name, key id, string message) {
       // if we have clicked a menuchoice, we can find the answer from the dialog here
       if(~llListFindList(TEST_DIALOG_CHOICES,[message])) {
           // for debugging, tell us our choice
           llSay(0, "Your Choice : " + message);
           // and back to standby
           state default;
       } else  {
           // we have clicked a Navigation button, find out which button ...
           if(message == "<<<" || message == "BACK") {
               --PAGE;
           } else if(message == ">>>") {
               ++PAGE;
           } else if(message == "FIRST") {
               PAGE = 1;
           } else if(message == "LAST") {
               PAGE = llCeil(llGetListLength(TEST_DIALOG_CHOICES)/(maxButtons-3));
           } else {
               // ... or for confusing, abort all :) (will reached with the "No Clue"-Button)
               state default;   
           }
           // if we click a button, be sure we reset the timercount and start a new timeout-counter
           llResetTime();
           // We are still in the listen event, so we can draw a new menu
           CreateMenu(id,TEST_DIALOG_CHOICES);     
       }
   }
   
   touch_start(integer i) {
       // listen only to the control-user and give him the chance to draw a new menu if one page is not appearing...
       if(llDetectedKey(0) == LastMenuUser) {
           CreateMenu(llDetectedKey(0),TEST_DIALOG_CHOICES);   
       }
   }
   
   timer() {
       // draw the timeout-counter on the prim
       llSetText((string)(llRound(TimeOut - llGetTime())) + " seconds left",<1,1,1>,1);
       // and tell us if we run out of time...
       if(llGetTime() > TimeOut) {
           llSay(0,"Dialog expired");
           // back to standby
           state default;
       }
   }

} </lsl>