9. Working with strings
Note: This lesson refers to the LS GUI library provided in part 6. If you haven't downloaded those files yet, see this post: 6. Introducing the LS GUI library
Just a short lesson today. We're going to look at two classes that are almost, but not quite, doing the same thing:
OptLst, commonly known as "radio buttons", and
ChkLst, a series of checkboxes.
OptLst lets you choose one of the listed options, whereas
ChkLst can have each option turned on or off separately.
As you can see in the library script they use the same parameters for creation - our old buddies
x,y,w,h, and three new ones:
Code:
caption Title / question
opts String separated by commas, just like for GetUserInputs().
ex: "Alice,Bob,Charlie,Denise,Edward"
pad Padding between the caption and each option
opts is the one we'll be focusing on here. By using some of Lua's built-in features for doing work on strings, a list of options, or values, or whatever can be stored as one continuous string. The same thing could be accomplished with a table, but for educational purposes I've opted to do things this way.
As you can see from the example in the code box above, the list of options is simply written out in the form "Option A
,Option B
,Option C
,...". Comma-separated strings, or CSVs, are fairly common in programming and databases, so it's good to be familiar with them; for instance the Reaper function
reaper.GetUserInputs() includes two CSVs in its parameters and returns the user's responses in a third.
The first thing we do with our options is - surprise! - put them into a table:
Code:
-- Parse the string of options into a table
opt_lst.optarray = {}
local tempidx = 1
for word in string.gmatch(opts, '([^,]+)') do
opt_lst.optarray[tempidx] = word
tempidx = tempidx + 1
end
opt_lst.numopts = tempidx - 1
string.gmatch() is really powerful. Almost... TOO powerful... . That crazy jumble of symbols that looks like someone was holding the Shift key down while they typed a number? It's a pattern that Lua will look for in our string (
opts). As you can probably guess, that pattern translates to "Find a group of characters that are before a comma", and in this case we're going to use that group in a
for loop:
Code:
for each group of characters, which we'll call word, do this:
put the word into our table using the current index number
ChkLst only: use the same index number to set that option's initial state
increase the index number
repeat with the next word
The index number is then used to figure out how many options there are, and therefore how many buttons/boxes to draw.
The
:draw() methods for both are pretty similar aside from one drawing circles and the other drawing squares.
OptLst also only has one value telling it which option is selected, while
ChkLst uses a table to store each option's state individually.
Likewise, their mouse methods are virtually identical.
OptLst has a little extra code in
:onmouseup so that the user can drag over the options and have the bubble follow their mouse, but reset to the initial state if the mouse is moved off the option list before they let the button up. Just a visual thing, not necessary by any means.
As with the other interactive elements, both
OptLst and
ChkLst store their current selection in the variable
retval. For
ChkLst,
retval is a table storing option 1's status at index 1, etc.
We can find a few more string functions further down, in the
TxtBox class. For instance, it's a fairly standard convention that double-clicking on a text box will select all of its contents. To do that, our
TxtBox:ondoubleclick() method needs to know how long the string is:
Code:
local len = string.len(self.retval)
string.len() simply returns the length in characters of a given string. Child's play.
Moving on to
:ontype() we can find another new function, in the code for Backspace:
Code:
text = string.sub(text, 1, caret - 1)..(string.sub(text, caret + 1))
string.sub(text, start, end) takes a string,
text, and returns a portion of it from
start to
end. As you can see here, we're using it twice to get the text before and after the character we just backspaced. The
.. in between tells Lua to join two strings together.
A little further down, in the code for typing a character, we can see strings being joined in a different way:
Code:
text = string.format("%s%c%s", string.sub(text, 1, caret), char, string.sub(text, caret + 1))
string.format(formatting, str1, str2...) uses some fancy symbols in its first argument to make sure the remaining arguments fit into a certain format.
%s is just a string, while
%c converts the
char value that was typed from an ASCII number into a character.
We'll take a longer look at the
TxtBox in another lesson.
For a more thorough explanation of patterns, capture characters, and string stuff in general,
see here,
and here.