View Single Post
Old 05-17-2016, 03:58 PM   #50
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

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.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate

Last edited by Lokasenna; 05-18-2016 at 03:33 PM.
Lokasenna is offline   Reply With Quote