Dialog Texture Changer

Written by Kitsune
// Script to present a dialog populated with a list of textures
// either from the prims inventory or specified by UUID in a notecard.
//
// Notecard lines have the form:
//    Texture Name=UUID
//
// Note that only the first 24 characters of the texture names
// are actually used - as only 24 chars can be placed in a dialog
// button.  This means that if two textures have the first 24 chars
// the same, the second will be ignored ...
//
// Note however that usually, buttons don't display more than, say,
// around 10 or so characters anyway!!
//
// There are two methods of setting textures - one (gSetTexture = TRUE)
// allows you to use UUIDs, etc, but the other (gSetTexture = FALSE)
// will allow you to specify the rotation and offset values.
//
// There is also an option to just use the values from the texture already
// on the face (but this won't work for ALL_SIDES).
//
// Both allow you to set the face.
//
// Kimm Paulino
// Feb 2012
 
// Controls how the script operates:
integer gReshow = FALSE;
integer gSetTexture = FALSE;               // Use SetTexture method (needed for textures not in the prim inventory)
integer gNotecards = TRUE;               // Get textures to use from a notecard not inventory
integer gPreserveTextures = FALSE;      // Read offset/rotation values from existing texture
 
// configures how textures appear
integer gFace = 1;
vector  gRepeats = <1.0, 1.0, 1.0>;
vector  gOffsets = <1.0, 1.0, 1.0>;
float     gRotationInDegrees = 0.0;
 
// Do not change anything below this line (unless you know what you are doing)
integer gDebug = FALSE;
integer gMenuPage;
integer gNumTextures;
list gTextures;
list gTextureUUIDs;
 
string gNotecardName;
integer gNotecardLine = 0;
key gQueryID;
 
integer gListenChannel;
integer gListenHandle;
float     gListenTimer;
float     LISTEN_TIMEOUT=300.0;
 
string MENU_NEXT="Next>";
string MENU_TOP="Top";
string MENU_BACK="= num_pages)
    {
        // gMenuPage is an index starting at 0...
        // max is a 1...
        gMenuPage = num_pages-1;
    }
 
    // Max buttons on a dialog is 12, so if more than that, then need to 
    // include special next/back button handling
    integer first_texture = 0;
    integer last_texture = gNumTextures-1;
    if (gNumTextures > 12)
    {
        // Note: This yields notecards counting as follows:
        // 0 to 8 = first page,
        // 9 to 17 = next page, etc
        first_texture = gMenuPage * 9;
        last_texture = first_texture + 9 - 1;
        if (last_texture >= gNumTextures)
        {
            // recall last_texture indexed from 0, but
            // gNumTextures is indexed from 1
            last_texture = gNumTextures-1;
        }
 
        if (gMenuPage > 0)
        {
            buttons += [MENU_BACK];
        }
        else
        {
            buttons += [MENU_SPACE];
        }
 
        if (gMenuPage == 0)
        {
            buttons += [MENU_SPACE];
        }    
        else
        {
            buttons += [MENU_TOP];
        }
 
        // If not on the last page, and there are more pages to come ...
        if (gNumTextures > 9 && gMenuPage < (num_pages-1))
        {
            buttons += [MENU_NEXT];
        }
        else
        {
            buttons += [MENU_SPACE];
        }
    }
 
    integer i;
    for (i=first_texture; (i <= last_texture) && (i < gNumTextures); i++)
    {
        buttons += [llList2String (gTextures, i)];
    }
 
    do_dialog (id, "\n\n(click \"Ignore\" when done)", buttons);
}
 
do_dialog (key id, string msg, list buttons)
{
    llListenRemove (gListenHandle);
    gListenChannel = getRandomChannel();
    gListenHandle = llListen (gListenChannel, "", id, "");
    llSetTimerEvent (LISTEN_TIMEOUT);
    llDialog (id, msg, buttons, gListenChannel);
}
 
default
{
    on_rez (integer start_param)
    {
        llResetScript();
    }
 
    state_entry()
    {
        if (read_textures_from_inventory())
        {
            // We have textures in the inventory and have read them
            gNotecards = FALSE;
        }
        else if (read_textures_from_notecards())
        {
            // We have textures read in from a notecard by UUID
            // (or will have pretty soon)
            gNotecards = TRUE;
        }
        else
        {
            llOwnerSay ("Note: There are no textures or notecards in this prim ...");
        }
        gMenuPage = 0;
    }
 
    touch_start(integer total_number)
    {
        // Start menu system again. Note that I don't do anything special
        // with several people trying to touch it at the same time - it will
        // always overlap the processing of gMenuPage, but all that will
        // happen is that peoples next/back might be a bit quirky for a while.
        // Eventually, they will sort themselves out!
        gMenuPage = 0;
        show_dialog (llDetectedKey(0));
    }
 
    listen (integer channel, string name, key id, string msg)
    {
        if (channel == gListenChannel)
        {
            if (msg == MENU_BACK)
            {
                gMenuPage--;
                show_dialog (id);
            }
            else if (msg == MENU_TOP)
            {
                gMenuPage = 0;
                show_dialog (id);
            }
            else if (msg == MENU_NEXT)
            {
                gMenuPage++;
                show_dialog (id);
            }            
            else
            {
                // should be something in the inventory to give out
                apply_texture (msg);
 
                // reshow the dialog
                if (gReshow)
                {
                    show_dialog(id);
                }
            }
        }
    }
 
    timer ()
    {
        // First see if we are timing out on a listen event
        if (gListenHandle != 0)
        {
            // Remove the old listen
            llListenRemove (gListenHandle);
            gListenHandle = 0;
            gListenChannel = 0;
        }
    }
 
    dataserver(key query_id, string line)
    {
        if (query_id == gQueryID)
        {
            if (line != EOF)
            {
                if (llSubStringIndex (line, "=") != 0)
                {
                    list vals = llParseString2List (line, ["="], []);
 
                    // Only store the first 24 characters of the name as this is all we can
                    // show in a dialog anyway
                    string texture = llList2String (vals, 0);
                    string uuid = llList2Key (vals, 1);
                    gTextures += [llGetSubString (texture, 0, 23)];
                    gTextureUUIDs += uuid;
                    doDebug ("Adding: " + texture + " ("+uuid+")");
                }
 
                // Now get the next line
                gNotecardLine++;
                gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
            }
            else
            {
                gNumTextures = llGetListLength (gTextures);
                doDebug ("Found " + (string)gNumTextures + " textures.");
            }
        }
    }
 
    changed (integer change)
    {
        if (change & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
}