Dialog Menus Control

This is example of usage and function library needed in each scripts to use this dialog menus module.
IMPORTANT NOTE: This menus control REQUIRED Nargus Dialog Control script. You MUST have both Nargus Dialog Control and Nargus Dialog Menus in the same prim for it to work.
==Menus Usage==
# Initialize menus control using:
#* llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
# Using "packDialogMessage" function to generate new menu, and add it to menus list:
#* llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(....), "MenuName");
#* While "MenuName" is the same of this menu, ie: MainMenu
# To make a dialog button show a sub-menu, use following as return value of the button:
#* MENU_<name>
#* Replace "<name>" with the actual name of the added menu (without parenthesis).
# Repeat (2) and (3) for all menus you want
# To show a menu, use:
#* llMessageLinked(LINK_THIS, lnkMenuShow, "MenuName", llGetOwner());
#* Where "MenuName" is the name of menu to show. To show last-used menu, leave this field empty.
# Dialog will return value the same way as usual call to Nargus Dialog Module script.
==Sample Scripts==
* OnTouchSelectTexture (Tiyuk Quellmalz)
If anyone uses this module, please IM Nargus Asturias, I'd love to hear what you think.
==Scripts & Example==
// READ ME:
// To see this sample in action;
// Put "Nargus Dialog Control" and "Nargus Dialog Menus" along with this script
// in a prim and touch.
// Dialog constants
integer lnkDialog = 14001;
integer lnkDialogNotify = 14004;
integer lnkDialogResponse = 14002;
integer lnkDialogTimeOut = 14003;
integer lnkDialogReshow = 14011;
integer lnkDialogCancel = 14012;
integer lnkMenuClear = 15001;
integer lnkMenuAdd = 15002;
integer lnkMenuShow = 15003;
string seperator = "||";
integer dialogTimeOut = 0;
// ********** DIALOG FUNCTIONS **********
string packDialogMessage(string message, list buttons, list returns){
 string packed_message = message + seperator + (string)dialogTimeOut;
 
 integer i;
 integer count = llGetListLength(buttons);
 for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);
 return packed_message;
}
dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
dialogCancel(){
 llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
 llSleep(1);
}
dialogNotify(key id, string message){
 list rows;
 
 llMessageLinked(LINK_THIS, lnkDialogNotify,
 message + seperator + (string)dialogTimeOut + seperator,
 id);
}
// ********** END DIALOG FUNCTIONS **********
default{
 state_entry(){
 llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
 llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
 "[ Main Menu ]\n" +
 "Messages go here",
 [ "BUTTON_1", "BUTTON_2", "BUTTON_3", "BUTTON_X" ],
 [ "MENU_SubMenu1", "MENU_SubMenu2", "MENU_SubMenu3", "EXIT" ]
 ), "MainMenu");
 llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
 "[ Sub Menu 1 ]\n" +
 "Messages go here",
 [ "SUB_1_1", "SUB_1_2", "SUB_1_3", "MAIN MENU", "SUB_3", "BUTTON_X" ],
 [ "1.1", "1.2", "1.3", "MENU_MainMenu", "MENU_SubMenu3", "EXIT" ]
 ), "SubMenu1");
 llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
 "[ Sub Menu 2 ]\n" +
 "Messages go here",
 [ "SUB_2_1", "SUB_2_2", "SUB_2_3", "MAIN MENU", "SUB_1", "BUTTON_X" ],
 [ "2.1", "2.2", "2.3", "MENU_MainMenu", "MENU_SubMenu1", "EXIT" ]
 ), "SubMenu2");
 llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
 "[ Sub Menu 3 ]\n" +
 "Messages go here",
 [ "SUB_3_1", "SUB_3_2", "SUB_3_3", "MAIN MENU", "SUB_2", "BUTTON_X" ],
 [ "3.1", "3.2", "3.3", "MENU_MainMenu", "MENU_SubMenu2", "EXIT" ]
 ), "SubMenu3");
 
 llSetText("Touch me to show menu", <1,1,1>, 1);
 }
 link_message(integer sender_num, integer num, string str, key id){
 if(num == lnkDialogTimeOut){
 dialogNotify(llGetOwner(), "Menu time-out. Please try again.");
 state default;
 }else if(num == lnkDialogResponse){
 llWhisper(0, str);
 }
 }
 
 touch_start(integer num_detected){
 llMessageLinked(LINK_THIS, lnkMenuShow, "", llDetectedOwner(0));
 }
}
Nargus Dialog Menus v1.01 (by Nargus Asturias)
// ********** DIALOG MENUS MODULE ********** //
// By Nargus Asturias
// Version 1.01
//
// Multi-layer menus management module for Nargus Dialog Control.
// Use same packing method as Nargus Dialog Control
//
// HOW TO USE:
// 1) Initialize menu by sending "lnkMenuClear" signal:
// llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
//
// 2) Add menu dialog using provided function (or manually, please referr to Nargus Dialog Control 
// manual). Make sure signal is sent with "lnkMenuAdd" and key field is menu's name;
// llMessageLinked(LINK_THIS, lnkMenuAdd, ......, "MainMenu");
//
// To make a button show submenu, use following as return value of the button:
// MENU_<name>
// Replace "<name>" with the actual name of the added menu (without parenthesis).
//
// 3) Repeat (2) for as much menus as needed
//
// 4) To show a menu, use:
// llMessageLinked(LINK_THIS, lnkMenuShow, name, llGetOwner());
// When "name" is name of the menu to show. To show last-used menu, leave this field empty.
//
// 5) Dialog will return value the same way as usual call to Nargus Dialog Module script.
// ******************************************* //
// Dialog constants
integer lnkDialog = 14001;
integer lnkDialogNotify = 14004;
integer lnkDialogResponse = 14002;
integer lnkDialogTimeOut = 14003;
integer lnkDialogReshow = 14011;
integer lnkDialogCancel = 14012;
string seperator = "||";
integer dialogTimeOut = 0;
// ********** DIALOG FUNCTIONS **********
dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
dialogCancel(){
 llSleep(1);
 llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
}
// ********** END DIALOG FUNCTIONS **********
// Constants
integer lnkMenuClear = 15001;
integer lnkMenuAdd = 15002;
integer lnkMenuShow = 15003;
// Menus variables
list menuNames; // List of names of all menus
list menus; // List of packed menus command, in order of menuNames
// Variables
integer lastMenuIndex; // Latest called menu's index
// ********** Menu Functions **********
clearMenusList(){
 menuNames = [];
 menus = [];
 lastMenuIndex = 0;
}
addMenu(string name, string message, list buttons, list returns){
 // Reduced menu request time by packing request commands
 string packed_message = message + seperator + (string)dialogTimeOut;
 
 integer i;
 integer count = llGetListLength(buttons);
 for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);
 // Add menu to the menus list
 menuNames += [name];
 menus += [packed_message];
}
showMenu(string name, key id){
 if(llGetListLength(menuNames) <= 0) return;
 
 integer index;
 if(name != ""){
 index = llListFindList(menuNames, [name]);
 if(index < 0) index = lastMenuIndex;
 }else index = lastMenuIndex;
 
 lastMenuIndex = index;
 
 // Load menu command and execute
 string packed_message = llList2String(menus, index); 
 llMessageLinked(LINK_THIS, lnkDialog, packed_message, id);
}
// ********** States **********
default{
 state_entry(){
 clearMenusList();
 }
 link_message(integer sender_num, integer num, string str, key id){
 // Menu response commands
 if(num == lnkDialogResponse){
 if(llGetSubString(str, 0, 4) == "MENU_"){
 str = llDeleteSubString(str, 0, 4);
 showMenu(str, id);
 }
 }
 
 // Menu management commands
 else if(num == lnkMenuClear)
 clearMenusList();
 else if(num == lnkMenuAdd){
 list data = llParseString2List(str, [seperator], []);
 string message = llList2String(data, 0);
 list buttons = [];
 list returns = [];
 integer i;
 integer count = llGetListLength(data);
 for(i=2; i<count;){
 buttons += [llList2String(data, i++)];
 returns += [llList2String(data, i++)];
 }
 addMenu((string)id, message, buttons, returns);
 }else if(num == lnkMenuShow){
 dialogCancel();
 showMenu(str, id);
 }
 }
}