View Single Post
Old 05-11-2016, 08:37 PM   #18
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

4. Text

So now we know how to draw stuff. But what about printing text? I mean, lines and circles are pretty and all but at some point we're going to need to communicate some sort of information to the user. Right?

Well, we already know how to choose what color of crayon to use, so the next decision is what font to use.

gfx.setfont(idx[,"fontface", sz, flags])

ReaScript is nice enough to give us a few preset slots we can assign fonts to, determined by giving idx a number from 1 to 16. 0 will give you a default font of some sort, I think. fontface is the font name in text, followed by size and flags like italics, underline or bold.

Fonts can be set like so:
Code:
gfx.setfont(1, "Arial", 28)
...and recalled like so:
Code:
gfx.setfont(1)
Alternatively, you can just set the font manually every time. Up to you.

Edit: cyrilfb was nice enough to figure out how the flags parameter works:

Quote:
It should be the ascii number of the letter you want to use as a flag.

So in ascii:
Bold = 'b' = 98
Italic = 'i' = 105
Underline = 'u' = 117

gfx.setfont(1, "Arial", 28, 98) sets bold text.
gfx.setfont(1, "Arial", 28, 105) sets italic text.
gfx.setfont(1, "Arial", 28, 117) sets underlined text.

I cannot figure out how to combine flags. It would be nice if someone would tell us.
Edit the 2nd: Thanks to the fine gents at Cockos, we have an answer. Looks like the easiest way to do this is with another helper function (which is not in any of the files provided for these tutorials).

Code:
-- Font flag helper function, courtesy of Justin and Schwa
function fontflags(str) 
	
	local v = 0
	
	for a = 1, str:len() do 
		v = v * 256 + string.byte(str, a) 
	end 
	
	return v 

end

-- Used like so:
gfx.setfont(1,"Arial",20, fontflags('iu'))
Now that we have a font, drawing the string is easy as pie:

gfx.drawstr("str")

You can obviously pass it a variable with your string in it and all that as well. Now, unlike the other drawing functions where x and y were provided as parameters, drawstr prints your block of text with its top-left corner at gfx.x, gfx.y, so you have to set them manually beforehand.

Code:
local my_str = "This is a string"

gfx.setfont(1, "Arial", 28)

gfx.x, gfx.y = 100, 100

gfx.drawstr(my_str)
But what if you're drawing a button and you want to center the text inside a rectangle? Since this is Reaper, the do-it-yourself DAW, we'll have to figure out the appropriate coordinates ourselves:

gfx.measurestr("str")

As the name suggests, this will return the dimensions of a given string using the currently-set font. Note that this function returns TWO values, so you have to provide two variables instead of one:

Code:
local str_w, str_h = gfx.measurestr(my_str)
A little more math and we're all set:

Code:
local my_str = "This is a string"

local x, y = 100, 100
local w, h = 200, 80
local r = 10

roundrect(x, y, w, h, r, 1, 0)

gfx.setfont(1, "Arial", 28)
local str_w, str_h = gfx.measurestr(my_str)

gfx.x = x + ((w - str_w) / 2)
gfx.y = y + ((h - str_h) / 2)

gfx.drawstr(my_str)


Great, it's a picture of a button. But how do we show if the button has been clicked? To me, the easiest solution is to simply reverse the background and foreground colors. For this example, the first line can be set to true or false to simulate a user pressing the button. We'll learn how to actually do that in the next lesson.

Code:
local state = true
local my_str = "This is a string"

gfx.set(1, 0.5, 0.5, 1)

local x, y = 100, 100
local w, h = 200, 80
local r = 10

gfx.setfont(1, "Arial", 28)

local str_w, str_h = gfx.measurestr(my_str)
local txt_x = x + ((w - str_w) / 2)
local txt_y = y + ((h - str_h) / 2)

-- Unclicked
if state == false then 

	roundrect(x, y, w, h, r, 1, 0)

	gfx.x = txt_x
	gfx.y = txt_y

	gfx.drawstr(my_str)
	
-- Clicked	
else	
	
	roundrect(x, y, w, h, r, 1, 1)
	
	gfx.x = txt_x
	gfx.y = txt_y
	
	-- Store the current foreground color
	local r, g, b = gfx.r, gfx.g, gfx.b
	
	-- Set our text to the background color instead
	-- Remember the different color conventions; this is the equivalent of RGB 64, 64, 64
	gfx.set(0.25, 0.25, 0.25, 1)
	
	gfx.drawstr(my_str)
	
	-- Set the color back to what it was, before we forget
	gfx.set(r, g, b)
end


And now for something completely different, since you've been so well-behaved today.

Plain text on a plain background starts to get a little boring after a while, no? An easy way to spruce things up is by adding a shadow effect to your big "THIS IS MY AWESOME GUI" label.

For simplicity's sake, we're going to cast our shadows toward the lower-right. The simplest, but least-attractive method is to print a few copies of our text in black, offset a few pixels over and down.

Code:
local my_str = "THIS IS MY AWESOME GUI"
local r, g, b = 1, 0.5, 0.5
local shadow_dist = 4

gfx.setfont(1, "Arial", 28)

-- There's a new variable here, for those of you paying attention
local str_w, __ = gfx.measurestr(my_str)
local x = ((gfx.w - str_w) / 2)
local y = 50 


-- Draw the shadow first, so our main text will be printed on top of it.
gfx.set(0, 0, 0, 1)
for i = 1, shadow_dist do
	gfx.x, gfx.y = x + i, y + i
	gfx.drawstr(my_str)
end


-- Now the main text
gfx.x, gfx.y = x, y
gfx.set(r, g, b, 1)
gfx.drawstr(my_str)


Hawt.
__________________
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; 06-19-2017 at 03:40 PM.
Lokasenna is offline   Reply With Quote