Don't click here unless you want to be banned.

LSL Wiki : LibraryCBMenuLineButtonView

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are ia360925.us.archive.org
// MenuLineButtonView
// Responsble for the appearence of the buttons and interpreting 
// buttonPressed events for buttons corresponding to lines onscreen.

// Copyright (C) 2005-2006  Francisco V. Saldana
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
// 
// Francisco V. Saldana can be contacted using his email account 
//  username: dressedinblue, at domain: gmail.com
// and in Second Life by IMming Christopher Omega

// Upon getting its buttonPressed method triggered,
// this component first identifys what line corresponds with the button.
// If a line does not correspond with the button, it doesnt do anything.
// If it does, it triggeres a lineButtonPressed(integer lineNum) event. 

// Library functions:
integer strStartsWith(string str, string prefix) {
    return llSubStringIndex(str, prefix) == 0;
}

string removePrefixFrom(string str, string prefix) {
    if (!strStartsWith(str, prefix)) return str;
    
    integer prefixLen = llStringLength(prefix);
    return llDeleteSubString(str, 0, prefixLen - 1);
}

// Replaces the list elements in dest with elements in src, starting at start.
// For example, if dest was [A, B, C, D], src was [E, F] and start was 1, 
// the list returned would be [A, E, F, D]. 
// If llGetListLength(src) + start > llGetListLength(dest), the returned list length
// will be greater then dest list's length.

string NULL = " ";
list replaceListSlice(list dest, list src, integer start) {
    if (llGetListEntryType(dest, start - 1) == TYPE_INVALID) {
        integer len;
        for(len = llGetListLength(dest); len < start; len++) {
            dest += NULL;
        }
    }
    integer srcLen = llGetListLength(src);
    return llListInsertList(llDeleteSubList(dest, start, start + srcLen - 1), src, start);
}

// Method calling:
// ========== For method invocation ==========
string randomStr(string chars, integer len) {
    integer numChars = llStringLength(chars);
    string ret;
    integer i;
    for (i = 0; i < len; i++) {
        integer randIndex = llFloor(llFrand(numChars));
        ret += llGetSubString(chars, randIndex, randIndex);
    }
    return ret;
}

string SEPERATOR_CHARS = "`~!@#$%^&*()-_+[]{}\|'\";/?.>,<";
integer SEPERATOR_LEN  = 3;
string dumpList2String(list src) {
    // Generate a seperator not present in any of the
    // elements in the list.
    string chars = (string) src; // Squashes all elements together.
    string seperator;
    do {
        seperator = randomStr(SEPERATOR_CHARS, SEPERATOR_LEN);
    } while (llSubStringIndex(chars, seperator) != -1);
    return seperator + llDumpList2String(src, seperator);
}

list parseStringKeepNulls(string src) {
    // The seperator should be the first SEPERATOR_LEN
    // characters in the string.
    return llParseStringKeepNulls(llDeleteSubString(src, 0, SEPERATOR_LEN - 1),
        [llGetSubString(src, 0, SEPERATOR_LEN - 1)], []);
}

callMethod(integer callId, string methodName, list parameters) { 
    llMessageLinked(LINK_THIS, callId,
        dumpList2String(parameters), methodName);
}

returnValue(string methodName, integer methodIdentifyer, list value) {
    llMessageLinked(LINK_THIS, methodIdentifyer, 
        dumpList2String(value), methodName + "_ret");
}
// =============================================

trigger_getMenuTextAreaPosition() {
    callMethod(0, "getMenuTextAreaPosition", []);
}

trigger_addButtonListener(string buttonNamePattern) {
    callMethod(0, "addButtonListener", [buttonNamePattern]);
}

trigger_removeButtonListener(string buttonNamePattern) {
    callMethod(0, "removeButtonListener", [buttonNamePattern]);
}

trigger_lineButtonPressed(integer lineNum, list detectedData) {
    callMethod(0, "lineButtonPressed", [lineNum, dumpList2String(detectedData)]);
}

trigger_pong(string moduleName) {
    callMethod(0, "pong", [moduleName]);
}

// Global variables (interCaps) and constants (ALL_CAPS):
// Prefix of the name of buttons that correspond to lines.
string     LINE_BUTTON_NAME_PREFIX = "Line:";

// Related to LINE_BUTTON_NAME_PREFIX
// However, this is a specially formatted identifyer
// for the ButtonAbstractionLayer. % means wildcard.
// so Line:% means "match any string that starts with 'Line:'"
string     LINE_BUTTON_IDENTIFYER     = "Line:%";

// Color button changes to when its pressed.
vector    COLOR_PRESSED  = <1, 0, 0>;

// Color button changes to when its released, the button
// stays this color after the press->release process.
vector    COLOR_RELEASED = <0, 1, 0>;

// Color button changes to when its disabled, 
// the button is COLOR_RELEASED when its enabled.
vector    COLOR_DISABLED = <0.16078, 0.12941, 0.14118>;

// The first line on the screen that's a menu button
integer firstButtonLine;

// The last line on the screen that's a menu button
integer lastButtonLine;

// A bitfield, llPow(2, lineNum) == bit for button.
integer enabledLines     = -1;

// Black-boxes the math involved with determining
// if a line-button is enabled or not.
integer isLineButtonEnabled(integer lineNum) {
    integer bit = (integer) llPow(2, lineNum);
    return ((enabledLines & bit) == bit); 
}

// A list of the button's link numbers, the index of the link number
// in this list corresponds to the line the button is for.
list buttonLinkNumbers = [];

refreshLinkNumbers() {
    integer linkNumber = 1;
    buttonLinkNumbers  = [];
    while(llGetLinkKey(linkNumber) != NULL_KEY) {
        string name = llGetLinkName(linkNumber);
        if (strStartsWith(name, LINE_BUTTON_NAME_PREFIX)) {
            integer lineNumber = (integer) removePrefixFrom(name, LINE_BUTTON_NAME_PREFIX);
            buttonLinkNumbers = replaceListSlice(buttonLinkNumbers, [linkNumber], lineNumber);
        }
        linkNumber++;
    }
}
enableLineButton(integer lineNum) {
    // Only enable it if its already disabled.
    if (!isLineButtonEnabled(lineNum)) {
        // If there are no lines enabled, the button listener is 
        // probobly disabled as well.
        if (enabledLines == 0) {
            trigger_addButtonListener(LINE_BUTTON_IDENTIFYER);
        }
        enabledLines = enabledLines | (integer) llPow(2, lineNum);
        integer linkNum = llList2Integer(buttonLinkNumbers, lineNum);
        llSetLinkColor(linkNum, COLOR_RELEASED, ALL_SIDES);
    }
}

disableLineButton(integer lineNum) {
    // Only disable it if its already enabled.
    if (isLineButtonEnabled(lineNum)) {
        enabledLines = enabledLines & ~(integer) llPow(2, lineNum);
        // If there are no enabled lines:
        if (enabledLines == 0) {
            trigger_removeButtonListener(LINE_BUTTON_IDENTIFYER);
        }
        integer linkNum = llList2Integer(buttonLinkNumbers, lineNum);
        llSetLinkColor(linkNum, COLOR_DISABLED, ALL_SIDES);
    }
}

disableAll() {
    integer buttonNumber;
    for(buttonNumber = firstButtonLine; buttonNumber <= lastButtonLine; buttonNumber++) {
        disableLineButton(buttonNumber);
    }
}

enableAll() {
    integer buttonNumber;
    for(buttonNumber = firstButtonLine; buttonNumber <= lastButtonLine; buttonNumber++) {
        enableLineButton(buttonNumber);
    } 
}

// ============ llDetected* Related ============
integer DETECTED_GROUP       = 1001;
integer DETECTED_KEY         = 1002;
integer DETECTED_LINK_NUMBER = 1003;
integer DETECTED_NAME        = 1004;
integer DETECTED_POS         = 1006;
integer DETECTED_ROT         = 1007;

list getDetectedValue(list detectedData, integer detectedConstant) {
    integer index = llListFindList(detectedData, [(string) detectedConstant]);
    if (index != -1) {
        return llList2List(detectedData, index + 1, index + 1);
    }
    return [];
}
// =============================================

buttonInit() {
    //llSay(0, "LineButtonLayer starting up...");
    refreshLinkNumbers();
    trigger_addButtonListener(LINE_BUTTON_IDENTIFYER);
}

string this;
default {
    state_entry() {
        this = llGetScriptName();
        buttonInit();
        trigger_getMenuTextAreaPosition();
    }
    
    link_message(integer sender, integer num, string parameters, key methodName) {
        if (methodName == "getMenuTextAreaPosition_ret") {
            list paramList = parseStringKeepNulls(parameters);
            // Return value format:
            // getMenuTextAreaSize_ret(integer startline, integer endLine)
            integer startLine = (integer) llList2String(paramList, 0);
            integer endLine   = (integer) llList2String(paramList, 1);
            firstButtonLine = startLine;
            lastButtonLine = endLine;
            disableAll();
            state running;
        }
    }
}
 
state running {
    state_entry() {
    }
    
    link_message(integer sender, integer num, string parameters, key methodName) {
        if (methodName == "buttonPressed") {
            list paramList = parseStringKeepNulls(parameters);
            // Method signature:
            // buttonPressed(string buttonName, list detectedData)
            // Triggered when a registered button is pressed.
            
            string buttonName   = llList2String(paramList, 0);
            list   detectedData = parseStringKeepNulls(llList2String(paramList, 1));
            
            // If the button released is a line button:
            if (strStartsWith(buttonName, LINE_BUTTON_NAME_PREFIX)) {
                // The rest of the string is the number of the line the button corresponds to.
                integer lineNum = (integer) removePrefixFrom(buttonName, LINE_BUTTON_NAME_PREFIX);
                if (isLineButtonEnabled(lineNum)) {
                    trigger_lineButtonPressed(lineNum, detectedData);
                    integer linkNum = (integer) llList2String(getDetectedValue(detectedData, DETECTED_LINK_NUMBER), 0);
                    llSetLinkColor(linkNum, COLOR_PRESSED, ALL_SIDES); 
                }
            }
        } else if (methodName == "buttonReleased") {
            list paramList = parseStringKeepNulls(parameters);
            // Method signature:
            // buttonReleased(string buttonName, list detectedData)
            // Triggered when a registered button is released.
            
            string buttonName   = llList2String(paramList, 0);
            list   detectedData = parseStringKeepNulls(llList2String(paramList, 1));
            
            // If the button released is a line button:
            if (strStartsWith(buttonName, LINE_BUTTON_NAME_PREFIX)) {
                // The rest of the string is the number of the line the button corresponds to.
                integer lineNum = (integer) removePrefixFrom(buttonName, LINE_BUTTON_NAME_PREFIX);
                if (isLineButtonEnabled(lineNum)) {
                    integer linkNum = (integer) llList2String(getDetectedValue(detectedData, DETECTED_LINK_NUMBER), 0);
                    llSetLinkColor(linkNum, COLOR_RELEASED, ALL_SIDES);
                }
            }
        } else if (methodName == "disableLineButton") {
            list paramList = parseStringKeepNulls(parameters);
            // Method signature:
            // disableLineButton(integer lineNum) 
            integer lineNum = (integer) llList2String(paramList, 0);
            disableLineButton(lineNum);
        } else if (methodName == "disableAllLineButtons") {
            // Method signature:
            // disableAllLineButtons()
            disableAll();
        } else if (methodName == "enableLineButton") {
            list paramList = parseStringKeepNulls(parameters);
            // Method signature:
            // enableLineButton(integer lineNum)
            integer lineNum = (integer) llList2String(paramList, 0);
            enableLineButton(lineNum);
        } else if (methodName == "enableAllLineButtons") {
            // Method signature:
            // enableAllLineButtons()
            enableAll();
        } else if (methodName == "reregisterButtons") {
            // Method signature:
            // reregisterButtons()
            buttonInit();
        } else if (methodName == "ping") {
            list paramList = parseStringKeepNulls(parameters);
            // Method signature:
            // ping(string moduleName)
            string moduleName = llList2String(paramList, 0);
            if (moduleName == this)
                trigger_pong(this);
        }
    }
    
    changed(integer change) {
        if (change & CHANGED_LINK) {
            refreshLinkNumbers();
        }
    }
}


LibraryContentBrowser
There is no comment on this page. [Display comments/form]