// MenuColorScrolling // Responsible for maintaining the MenuTextArea's colors onscreen // stores setMenuLineColor data and writes it to the screen // in responce to scrollUp and scrollDown events // 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 // Number of lines to scroll down for each press of a scroll button. integer LINES_PER_SCROLL = 12; // Library functions: // replaceListSlice() // 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); } // ========== 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_setDisplayLineColor(integer line, vector color) { callMethod(0, "setDisplayLineColor", [line, color]); } integer getMenuTextAreaPositionRetVal; trigger_getMenuTextAreaPosition() { getMenuTextAreaPositionRetVal = (integer) llFrand(28342); callMethod(getMenuTextAreaPositionRetVal, "getMenuTextAreaPosition", []); } trigger_pong(string moduleName) { callMethod(0, "pong", [moduleName]); } // Global variables manipulated by method calls (link messages): // Stores data that is passed with setMenuLineText. The line number passed // to setMenuLineText corresponds with the index of the text in this list. list textColors = []; // The index in textStrings that is displayed on the topmost line of the screen. integer indexAtTop = 0; integer firstMenuLine; integer lastMenuLine; integer menuLineTotal; string screenWriter; // A boolean telling if the scroller should ignore writes to the screen // or not. Since the scroller calls the same method other components would // to write to the screen, it should ignore itself. //integer ignoreScreenWrites = FALSE; string this; default { state_entry() { this = llGetScriptName(); trigger_getMenuTextAreaPosition(); } link_message(integer sender, integer num, string parameters, key methodName) { if (methodName == "getMenuTextAreaPosition_ret" && num == getMenuTextAreaPositionRetVal) { list paramList = parseStringKeepNulls(parameters); // Return value format: // getMenuTextAreaPosition_ret(integer startline, integer endLine) integer startLine = (integer) llList2String(paramList, 0); integer endLine = (integer) llList2String(paramList, 1); firstMenuLine = startLine; lastMenuLine = endLine; menuLineTotal = (lastMenuLine - firstMenuLine) + 1; state main; } } } state main { link_message(integer sender, integer num, string parameters, key methodName) { if (methodName == "setMenuLineColor") { list paramList = parseStringKeepNulls(parameters); // Method signature: // setMenuLineColor(string moduleName, integer lineNumber, vector color) string moduleName = llList2String(paramList, 0); integer lineNumber = (integer) llList2String(paramList, 1); vector color = (vector) llList2String(paramList, 2); if (moduleName != screenWriter) return; if (lineNumber >= firstMenuLine + indexAtTop && lineNumber <= lastMenuLine + indexAtTop) trigger_setDisplayLineColor(lineNumber - indexAtTop, color); // Note: Was ignorable. textColors = replaceListSlice(textColors, [color], lineNumber); } else if (methodName == "menuScrollUp") { // Method signature: // menuScrollUp() indexAtTop -= LINES_PER_SCROLL; // If we've reached the first index of the text data: if (indexAtTop <= 0) { indexAtTop = 0; } // Notify the other modules of a menu screen-position change: //trigger_setStartLineOffset(indexAtTop); // Set the screen to the scrolled values: integer screenLine; for (screenLine = firstMenuLine; screenLine <= lastMenuLine; screenLine++) { integer textIndex = screenLine + indexAtTop; trigger_setDisplayLineColor(screenLine, llList2Vector(textColors, textIndex)); } } else if (methodName == "menuScrollDown") { // Method signature: // menuScrollDown() indexAtTop += LINES_PER_SCROLL; // Make sure indexAtTop is valid: integer textLineCount = llGetListLength(textColors); // If there's not enough text data to fill the screen when we've scrolled down: if (textLineCount - indexAtTop < menuLineTotal) { // Adjust so that the last text data element is on the last line // of the screen. indexAtTop = textLineCount - menuLineTotal; } //trigger_setStartLineOffset(indexAtTop); integer screenLine; for (screenLine = firstMenuLine; screenLine <= lastMenuLine; screenLine++) { integer textIndex = screenLine + indexAtTop; trigger_setDisplayLineColor(screenLine, llList2Vector(textColors, textIndex)); } } else if (methodName == "cls") { list paramList = parseStringKeepNulls(parameters); // Method signature: // cls(string moduleName) string moduleName = llList2String(paramList, 0); if (moduleName != screenWriter) return; // Clear all menu data: indexAtTop = 0; textColors = []; } else if (methodName == "setScreenWriter") { list paramList = parseStringKeepNulls(parameters); // Method signature: // setScreenWriter(string moduleName) string moduleName = llList2String(paramList, 0); screenWriter = moduleName; } else if (methodName == "ping") { list paramList = parseStringKeepNulls(parameters); // Method signature: // ping(string moduleName) string moduleName = llList2String(paramList, 0); if (moduleName == this) trigger_pong(this); } } }