Library Cycle Dialog Items
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
Cycle Dialog Items w/ Callback
Introduction
It's typical for a script to need more than the maximum-allowed amount of items per dialog window.
This script allows for cycling through multiple pages of items and provides a way to customize everything, as well as a callback function that end users can edit without having to look through the entire script body if they do not desire.
Script
// Cycle Dialog Items by Hawkster Westmoreland
// May 23, 2011
// Allow a dialog to cycle through more than 12 items
// define a channel for listening
integer CHANNEL = -2476;
// define a list containing all the possible menu items
list ALL_MENU_ITEMS = ["0","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","26"];
// the maximum number of buttons that can be displayed in the dialog at one time
integer MAX_DIALOG_BUTTONS = 12;
// the dialog's message
string DIALOG_MESSAGE = "Pick a Number";
// define tokens for the Prev and Next operations
string PREV_BUTTON = "<< Prev";
string NEXT_BUTTON = "Next >>";
// this function is called when an actual menu item is selected that is
// neither the PREV_BUTTON nor NEXT_BUTTON items, so feel free to
// replace the body of this function with your own code
MenuItemSelectedCallback(integer channel, string name, key id, string message)
{
llOwnerSay("You selected: " + message);
}
// ==============================================================
// You may not need to change anything below this section, but
// feel free to look through the code if you would like to modify
// the basic functionality.
// ==============================================================
// the number of menu items available (calculated in state_entry)
integer ITEMS_COUNT = 0;
// define a cycle number to keep track of which sublist to display
integer CYCLE_INDEX = 0;
// figure out which sublist cycle should be displayed
//
// items can be any list that has a bunch of items in it
// direction can be PREV_BUTTON, NEXT_BUTTON, or a blank String
list GetMenuCycle(list items, string direction)
{
// the sublist that will be generated by the next few operations
list sublist = [];
// calculate the number of items available
ITEMS_COUNT = llGetListLength(items);
// check to see what the direction was (if one was specified)
if(direction == PREV_BUTTON)
{
// display the previous cycle if the preconditions are met
if(CYCLE_INDEX > 0)
{
// the index can be cycled backward safely
CYCLE_INDEX--;
}
}
else if(direction == NEXT_BUTTON)
{
// display the next cycle if the preconditions are met
CYCLE_INDEX++;
}
// figure out which button cycle needs to be displayed
if(CYCLE_INDEX == 0) // first cycle
{
// check the number of available items
if(ITEMS_COUNT <= MAX_DIALOG_BUTTONS)
{
// the entire list can be displayed as one complete dialog
sublist = llList2List(items, 0, ITEMS_COUNT - 1);
}
else
{
// grab the sublist from the beginning until MAX_DIALOG_BUTTONS - 2
// to take into account the need for a NEXT_BUTTON item
sublist = llList2List(items, 0, MAX_DIALOG_BUTTONS - 2);
// append the NEXT_BUTTON item to the end of the cycle
sublist += [NEXT_BUTTON];
}
}
else // second...n cycle
{
// make sure we did not go over the list bounds
integer start_index = 0;
// (MAX_DIALOG_BUTTONS - 1) represents the first cycle with the
// NEXT button
//
// ((CYCLE_INDEX - 1) * (MAX_DIALOG_BUTTONS - 2)) calculates
// every cycle after the first (with NEXT and PREV buttons)
start_index = (MAX_DIALOG_BUTTONS - 1) + ((CYCLE_INDEX - 1) * (MAX_DIALOG_BUTTONS - 2));
// calculate how many items we'll have left after this cycle
integer items_left = ITEMS_COUNT - start_index;
// check to see if we'll have another cycle after this one
if(items_left > MAX_DIALOG_BUTTONS - 2)
{
// we can fill another dialog with PREV and NEXT buttons, so
// this is just another regular cycle (with MAX_DIALOG_BUTTONS - 3) to ensure that
// the total number of items pulled from ALL_MENU_ITEMS is actually equal to
// (MAX_DIALOG_BUTTONS - 2)
sublist = llList2List(items, start_index, start_index + (MAX_DIALOG_BUTTONS - 3));
// add the PREV button and NEXT button
sublist = [PREV_BUTTON] + sublist + [NEXT_BUTTON];
}
else
{
// we can finish the list along with a PREV button, so this
// is the final cycle for the list
sublist = llList2List(items, start_index, ITEMS_COUNT - 1);
// add the PREV button to the beginning of the cycle
sublist = [PREV_BUTTON] + sublist;
}
}
// return the generated sublist cycle
return sublist;
}
default
{
state_entry()
{
// listen on the specified channel
llListen(CHANNEL, "", llGetOwner(), "");
}
changed(integer change)
{
// check to see if the object owner changed
if(change & CHANGED_OWNER)
{
// reset the script so calls to llGetOwner()
// will correctly reference the new owner
llResetScript();
}
}
listen(integer channel, string name, key id, string message)
{
if(message == NEXT_BUTTON)
{
// user clicked the NEXT_BUTTON option, so get the next
// cycle of menu items
llDialog(llGetOwner(), DIALOG_MESSAGE, GetMenuCycle(ALL_MENU_ITEMS, NEXT_BUTTON), CHANNEL);
}
else if(message == PREV_BUTTON)
{
// user clicked the PREV_BUTTON option, so get the previous
// cycle of menu items
llDialog(llGetOwner(), DIALOG_MESSAGE, GetMenuCycle(ALL_MENU_ITEMS, PREV_BUTTON), CHANNEL);
}
else
{
// user clicked an actual item, so do something with it
MenuItemSelectedCallback(channel, name, id, message);
}
}
touch_start(integer total_number)
{
// display the dialog if the owner touched me
if(llDetectedKey(0) == llGetOwner())
{
// display the dialog with the current menu cycle
llDialog(llGetOwner(), DIALOG_MESSAGE, GetMenuCycle(ALL_MENU_ITEMS, ""), CHANNEL);
}
}
}
How It Works
The state_entry() function sets up a listen on the specified channel and waits for interaction. When the object containing the script is touched, a dialog is displayed with the current sub-list cycle available. When the PREV or NEXT buttons are clicked, the sub-list cycle is re-calculated and sent back to the dialog for display. Finally, when an element is clicked that is neither the PREV nor NEXT buttons, the MenuItemSelectedCallback(integer, string, key, string) function is invoked to process user-defined code.