Created
August 11, 2016 10:10
-
-
Save Katharine/3b722cbb789dc7e9d037b1a5dcb57ef5 to your computer and use it in GitHub Desktop.
Demo of old LSL UI proof of concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// LSL UI test script with a draft of some helpers. | |
// All client->script communication occurs on this channel. Any channel is valid except DEBUG_CHANNEL and 0. | |
// Immediate response: ready [major] [minor] | |
// Delayed response: permission [granted] | |
// No further messages may be sent until permission is received with granted = TRUE. | |
// Requesting permission implicitly revokes any previous permissions, which will also silently close any | |
// open floaters. | |
UIRequestPermission(integer channel) | |
{ | |
llOwnerSay("!suinit " + (string)channel + " Test post; please ignore."); | |
} | |
// Names for all elements and floaters must be unique; any non-unique name will be rejected. | |
// Any element may be a child of any element or floater; however, the behaviour of most such | |
// combinations is undefined. Floaters and panels can contain anything. | |
// All commands may return the following error if badly formed: | |
// badsyntax [command] [human readable message] | |
// All creation commands can return the following to indicate duplication: | |
// duplicate [command] [name] | |
// All commands referring to an existing element can return the following error if not found: | |
// notfound [command] [name] | |
// By convention, the title should be in ALL CAPS. This is not a requirement. | |
// If the floater is resizable, the given height and width are taken as minima. | |
UICreateFloater(string name, integer width, integer height, integer resizable, string title) | |
{ | |
llOwnerSay("!floater " + name + " " + (string)width + " " + (string)height + " " + (string)resizable + " :" + title); | |
} | |
// The list layout in all methods is of the same format, consisting of alternating keys and values: | |
// [key, value, key, value, ...] | |
// The following keys are accepted (all are optional): | |
// width: int - width in pixels | |
// height: int - height in pixels | |
// top: int - distance from top of parent view | |
// bottom: int - distance from bottom of parent view (broken) | |
// right: int - distance from right of parent view (broken) | |
// follows: int - mask of the UI_FOLLOWS constants indicating which edges to track on resize (default: top|left) | |
// bottom_delta: int - distance of bottom from top of adjacent view (broken) | |
// top_delta: int - distance of top from bottom of adjacent view | |
// left_pad: int - left padding | |
// right_pad: int - right padding | |
// left_delta: int - distance of left from right of adjacent view | |
// font: string - name of font to use. Valid options are SansSerif, Monospace, DejaVu and Helvetica. | |
// font_size: string - font size. Valid options are Small, Medium, Large and Huge. | |
// font_style: string - font style. Valid options are BOLD, ITALIC and UNDERLINE. Styles may be combined using |, e.g. BOLD|ITALIC. | |
// | |
// All of these settings are optional and sane defaults are usually available. | |
// Combining foo and foo_delta is undefined. | |
// Only the top and left related positioning keys currently work as expected. | |
// Creates a button at with the given label | |
// Buttons will send the following message on click: | |
// commit [button_name] | |
UICreateButton(string name, string parent, string label, list layout) | |
{ | |
llOwnerSay("!button " + name + " " + parent + " " + llDumpList2String(layout, " ") + " :" + label); | |
} | |
// Creates a text label with the specified content. If word_wrap is true it will wrap, if false | |
// it will truncate with an ellipsis. | |
UICreateText(string name, string parent, integer word_wrap, string content, list layout) | |
{ | |
llOwnerSay("!text " + name + " " + parent + " " + (string)word_wrap + " " + llDumpList2String(layout, " ") + " :" + content); | |
} | |
// Creates a single-line input field. | |
// value - initial_value | |
// max_length - maximum length in bytes | |
// revert_on_sec - if TRUE, the content will revert to the last committed value on hitting sec | |
// spellcheck - enables spellcheck | |
// require_enter - if FALSE, commits when the field loses focus. If TRUE, only on pressing return/enter. | |
UICreateInput(string name, string parent, string value, integer max_length, integer revert_on_esc, integer spellcheck, integer require_enter, list layout) | |
{ | |
llOwnerSay("!input " + name + " " + parent + " " + (string)max_length + " " + (string)revert_on_esc + " " + (string)spellcheck + " " + (string)(!require_enter) + " " + llDumpList2String(layout, " ") + " :" + value); | |
} | |
// Creates a panel for holding other elements. | |
// bevel_style - one of in, out, bright and none. | |
// border_width - the number of single-pixel lines drawn, between zero and two. | |
UICreatePanel(string name, string parent, integer border_width, string bevel_style, list layout) | |
{ | |
llOwnerSay("!panel " + name + " " + parent + " " + (string)border_width + " " + bevel_style + " " + llDumpList2String(layout, " ")); | |
} | |
UICreateSlider(string name, string parent, string label, string orientation, integer label_width, integer text_width, integer show_text, integer can_edit_text, integer decimal_digits, float default_value, float min_value, float max_value, float increment, list layout) | |
{ | |
llOwnerSay("!slider " + llDumpList2String([name, parent, orientation, label_width, text_width, show_text, can_edit_text, decimal_digits, default_value, min_value, max_value, increment], " ") + " " + llDumpList2String(layout, " ") + " :" + label); | |
} | |
UICreateSwatch(string name, string parent, string label, integer immediate, vector default_colour, list layout) | |
{ | |
llOwnerSay("!swatch " + name + " " + parent + " " + (string)immediate + " " + (string)default_colour + " " + llDumpList2String(layout, " ") + " :" + label); | |
} | |
// Sets the text for the element given, if the operation is sane. | |
// If the operation is not defined for the element given, the following is returned: | |
// invalid settext [name] [found_type] | |
// Do not rely on the content of found_type being useful. It is intended for debugging. | |
UISetText(string element, string text) | |
{ | |
llOwnerSay("!settext " + element + " :" + text); | |
} | |
// These constants are for use with the `follows` layout key. | |
integer UI_FOLLOWS_NONE = 0x00; | |
integer UI_FOLLOWS_LEFT = 0x01; | |
integer UI_FOLLOWS_RIGHT = 0x02; | |
integer UI_FOLLOWS_TOP = 0x10; | |
integer UI_FOLLOWS_BOTTOM = 0x20; | |
integer UI_FOLLOWS_ALL = 0x33; | |
// Given a message from the client, returns a list with the command followed by each argument. | |
list UIParseMessage(string message) | |
{ | |
if(llGetSubString(message, 0, 35) != llGetKey()) return []; | |
message = llDeleteSubString(message, 0, 36); | |
if(llGetSubString(message, 0, 0) != "!") return []; | |
message = llDeleteSubString(message, 0, 0); | |
integer colon = llSubStringIndex(message, ":"); | |
string last_arg; // = "" | |
integer has_last_arg = ~colon; | |
if(has_last_arg) | |
{ | |
if(colon != llStringLength(message) - 1) | |
{ | |
last_arg = llGetSubString(message, colon+1, -1); | |
} | |
message = llDeleteSubString(message, colon, -1); | |
} | |
list args = llParseString2List(message, [" "], []); | |
if(has_last_arg) | |
{ | |
args += last_arg; | |
} | |
return args; | |
} | |
// -------------------- | |
// A test script. | |
FallbackMainMenu() | |
{ | |
llDialog(llGetOwner(), "Choose an option", ["Test 1", "Test 2", "Test 3", "Text", "Colour", "Opacity"], FALLBACK_CHANNEL); | |
} | |
FallbackColourMenu() | |
{ | |
llDialog(llGetOwner(), "Adjust the colour", ["R-", "G-", "B-", "R+", "G+", "B+", "Done"], FALLBACK_CHANNEL); | |
} | |
FallbackOpacityMenu() | |
{ | |
llDialog(llGetOwner(), "Adjust the opacity", ["More", "Less", "Done"], FALLBACK_CHANNEL); | |
} | |
AdjustColour(vector delta) | |
{ | |
vector c = llGetColor(0); | |
c += delta; | |
llSetColor(c, ALL_SIDES); | |
} | |
integer COMM_CHANNEL = -234532; | |
integer FALLBACK_CHANNEL = -265346; | |
default | |
{ | |
state_entry() | |
{ | |
llListen(COMM_CHANNEL, "", llGetOwner(), ""); | |
} | |
touch_start(integer num) | |
{ | |
if(llDetectedKey(0) == llGetOwner()) | |
{ | |
UIRequestPermission(COMM_CHANNEL); | |
llSetTimerEvent(1.0); | |
} | |
} | |
listen(integer channel, string name, key id, string message) | |
{ | |
list args = UIParseMessage(message); | |
string command = llList2String(args, 0); | |
if(command == "ready") // Immediate response from requesting permissions. | |
{ | |
llSetTimerEvent(0); | |
llSay(0, "Ready! Client version " + llList2String(args, 1) + "." + llList2String(args, 2)); | |
} | |
else if(command == "permission") // Delayed response from requesting permissions | |
{ | |
if(llList2Integer(args, 1)) // permission granted | |
{ | |
state sui; | |
} | |
else | |
{ | |
state dialogs; | |
} | |
} | |
} | |
timer() | |
{ | |
state dialogs; | |
} | |
on_rez(integer n) | |
{ | |
llResetScript(); | |
} | |
} | |
state sui | |
{ | |
state_entry() | |
{ | |
llListen(COMM_CHANNEL, "", llGetOwner(), ""); | |
llSay(0, "Permission granted!"); | |
UICreateFloater("test", 200, 250, TRUE, "LSL TEST FLOATER"); | |
UICreateButton("testbutton", "test", "Testing!", [ | |
"top", 5, | |
"left", 5, | |
"width", 100 | |
]); | |
UICreateButton("test2", "test", "Another test", [ | |
"width", 100, | |
"top_delta", 0 | |
]); | |
UICreateButton("test3", "test", "Stretching button", [ | |
"width", 190, | |
"top_delta", 0, | |
"follows", UI_FOLLOWS_TOP | UI_FOLLOWS_LEFT | UI_FOLLOWS_RIGHT | |
]); | |
UICreateText("summary", "test", TRUE, "This floater was generated using LSL. Hooray!", [ | |
"height", 35, | |
"top_delta", 10, | |
"left", 5, | |
"follows", UI_FOLLOWS_TOP | UI_FOLLOWS_LEFT | UI_FOLLOWS_RIGHT | |
]); | |
UICreateText("owner", "test", FALSE, "A link: secondlife:///app/agent/" + (string)llGetOwner() + "/about", [ | |
"height", 10, | |
"top_delta", 5, | |
"left", 5, | |
"follows", UI_FOLLOWS_TOP | UI_FOLLOWS_LEFT | UI_FOLLOWS_RIGHT | |
]); | |
UICreateSlider("opacity", "test", "Opacity", "horizontal", FALSE, FALSE, TRUE, FALSE, 2, llGetAlpha(0), 0, 1, 0.05, [ | |
"top_delta", 5, | |
"left", 5, | |
"follows", UI_FOLLOWS_TOP | UI_FOLLOWS_LEFT | UI_FOLLOWS_RIGHT | |
]); | |
UICreateSwatch("swatch", "test", "", TRUE, llGetColor(0), [ | |
"top_delta", 5, | |
"left", 5, | |
"height", 50, | |
"width", 40 | |
]); | |
UICreateInput("input", "test", "", 255, TRUE, TRUE, TRUE, [ | |
"width", 190, | |
"height", 23, | |
"top", 225, | |
"follows", UI_FOLLOWS_BOTTOM | UI_FOLLOWS_LEFT | UI_FOLLOWS_RIGHT | |
]); | |
UICreatePanel("panel", "test", 1, "none", [ | |
"width", 80, | |
"height", 30, | |
"top", 5, | |
"left", 110, | |
"follows", UI_FOLLOWS_TOP | UI_FOLLOWS_RIGHT | |
]); | |
UICreateText("paneltext", "panel", FALSE, "Panel!", [ | |
"width", 80, | |
"height", 12, | |
"top", 0, | |
"left", 2, | |
"follows", UI_FOLLOWS_TOP | UI_FOLLOWS_LEFT, | |
"font", "SansSerif", | |
"font_size", "Huge", | |
"font_style", "BOLD" | |
]); | |
} | |
touch_start(integer n) | |
{ | |
// Race condition because I'm lazy. | |
UIRequestPermission(COMM_CHANNEL); | |
state default; | |
} | |
listen(integer channel, string name, key id, string message) | |
{ | |
list args = UIParseMessage(message); | |
string command = llList2String(args, 0); | |
if(command == "commit") // When some control is "committed" | |
{ | |
string element = llList2String(args, 1); | |
if(element == "input") | |
{ | |
llSetText(llList2String(args, 2), <1.0, 1.0, 1.0>, 1.0); | |
} | |
else if(element == "slider") | |
{ | |
UISetText("summary", "Slider value: " + llList2String(args, 2)); | |
} | |
else if(element == "opacity") | |
{ | |
llSetAlpha(llList2Float(args, 2), ALL_SIDES); | |
} | |
else if(element == "swatch") | |
{ | |
llSetColor((vector)llList2String(args, 2), ALL_SIDES); | |
} | |
else | |
{ | |
UISetText(element, "Clicked!"); | |
UISetText("summary", "Clicked button " + element); | |
} | |
} | |
// Error commands | |
else if(command == "badsyntax") | |
{ | |
llSay(0, "Syntax error in '" + llList2String(args, 1) + "' command."); | |
llSay(0, llList2String(args, 2)); | |
} | |
else if(command == "invalid") | |
{ | |
llSay(0, "Attempt to perform invalid " + llList2String(args, 1) + " operation on " + llList2String(args, 2) + " (" + llList2String(args, 3) + ")"); | |
} | |
else if(command == "notfound") | |
{ | |
llSay(0, "Attempt in " + llList2String(args, 1) + " command to reference non-existent element " + llList2String(args, 2)); | |
} | |
else | |
{ | |
llSay(0, "Garbage message: " + llList2CSV(args)); | |
} | |
} | |
on_rez(integer n) | |
{ | |
llResetScript(); | |
} | |
} | |
state dialogs | |
{ | |
state_entry() | |
{ | |
llListen(FALLBACK_CHANNEL, "", llGetOwner(), ""); | |
FallbackMainMenu(); | |
} | |
listen(integer channel, string name, key id, string message) | |
{ | |
if(message == "Test 1") | |
{ | |
llOwnerSay("You clicked Test 1!"); | |
FallbackMainMenu(); | |
} | |
else if(message == "Test 2") | |
{ | |
llOwnerSay("You clicked Test 2!"); | |
FallbackMainMenu(); | |
} | |
else if(message == "Test 3") | |
{ | |
llOwnerSay("You clicked Test 3!"); | |
FallbackMainMenu(); | |
} | |
else if(message == "Text") | |
{ | |
state textbox; | |
} | |
else if(message == "Colour") | |
{ | |
FallbackColourMenu(); | |
} | |
else if(message == "Opacity") | |
{ | |
FallbackOpacityMenu(); | |
} | |
else if(message == "R+") | |
{ | |
AdjustColour(<0.05,0,0>); | |
FallbackColourMenu(); | |
} | |
else if(message == "R-") | |
{ | |
AdjustColour(<-0.05,0,0>); | |
FallbackColourMenu(); | |
} | |
else if(message == "G+") | |
{ | |
AdjustColour(<0,0.05,0>); | |
FallbackColourMenu(); | |
} | |
else if(message == "G-") | |
{ | |
AdjustColour(<0,-0.05,0>); | |
FallbackColourMenu(); | |
} | |
else if(message == "B+") | |
{ | |
AdjustColour(<0,0,0.05>); | |
FallbackColourMenu(); | |
} | |
else if(message == "B-") | |
{ | |
AdjustColour(<0,0,-0.05>); | |
FallbackColourMenu(); | |
} | |
else if(message == "More") | |
{ | |
llSetAlpha(llGetAlpha(0) + 0.05, ALL_SIDES); | |
FallbackOpacityMenu(); | |
} | |
else if(message == "Less") | |
{ | |
llSetAlpha(llGetAlpha(0) - 0.05, ALL_SIDES); | |
FallbackOpacityMenu(); | |
} | |
else if(message == "Done") | |
{ | |
FallbackMainMenu(); | |
} | |
} | |
touch_start(integer num) | |
{ | |
FallbackMainMenu(); | |
} | |
on_rez(integer n) | |
{ | |
llResetScript(); | |
} | |
} | |
state textbox | |
{ | |
state_entry() | |
{ | |
llListen(FALLBACK_CHANNEL, "", llGetOwner(), ""); | |
llTextBox(llGetOwner(), "Enter some text: ", FALLBACK_CHANNEL); | |
} | |
listen(integer channel, string name, key id, string message) | |
{ | |
llSetText(message, <1.0, 1.0, 1.0>, 1.0); | |
state dialogs; | |
} | |
touch_start(integer num) | |
{ | |
state dialogs; | |
} | |
on_rez(integer n) | |
{ | |
llResetScript(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment