Thursday, October 14, 2010

Splitting text into individual letters

One Lua trick that I use a lot is taking a string and splitting it up into individual characters which then get stored in a table.

I used this approach for my circle writing function and many other functions. This is how it's done.

You need the following function in the Lua script above the main function. I did not write this function and I cant remember exactly where I got it from but whoever did write it has my thanks!

function string:split(delimiter)
local result = { }
local from = 1
local delim_from, delim_to = string.find( self, delimiter, from )
while delim_from do
table.insert( result, string.sub( self, from , delim_from-1 ) )
from = delim_to + 1
delim_from, delim_to = string.find( self, delimiter, from )
table.insert( result, string.sub( self, from ) )
return result

These are the lines that split up the text...
print (text) --> text

sub=string.gsub(text, ".", "%1|")
-- the above inserts "|" after every character
print (sub) --> t|e|x|t|

split=string.split(sub, "|")
-- the above splits the string whenever a "|" occurs and also deletes the "|"
the resulting split up characters are stored in a table called split in this case

-- slen is the length of the original text,
so will be the number of entries in that table "split"

so that:
split[1] = "t"
split[2] = "e"
split[3] = "x"
split[4] = "t"

now I can deal with each character individually.
I could give each character a different font, or a different color
or, in the case of my square font conky below, convert each character to the square font.

Square text conky

I had an idea for a conky. I wanted it to be extremely compact and involve text in different orientations. This is what I ended up with!

The problem was that I spent a long time looking for a square font. I found several fonts that I liked but when I came to rotate them and put rotated letters next to regularly orientated letters I found that none of the fonts were actually square. Non were the same width as height.

So I decided to make my own font using the Lua script. I had done something similar in my ascii text lua; a function that read each letter of the text I wanted displayed and converted the letter into ascii.

In this case I created my own square font out of the webdings font. With webdings a "g" gave me a solid color square, while "c" gave me a black square with a color outline. I simply constructed my letters using those blocks like so:

if letter=="T" then
cairo_translate (cr, acrosst, downt)
cairo_rotate (cr, rotate)
cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, fontsize);
cairo_set_source_rgba (cr, red, green, blue, alpha);
cairo_move_to (cr, 0, 0);
cairo_show_text (cr, "ggggg")
cairo_move_to (cr, 0, ldown);
cairo_show_text (cr, "ccgcc")
cairo_move_to (cr, 0, ldown);
cairo_show_text (cr, "ccgcc")
cairo_move_to (cr, 0, ldown);
cairo_show_text (cr, "ccgcc")
cairo_move_to (cr, 0, ldown);
cairo_show_text (cr, "ccgcc")
cairo_rotate (cr, -1*rotate)
cairo_translate (cr, -1*acrosst, -1*downt)
I actually really like the look of the resulting square "font". And everything fitted nicely together with no gaps :)

Go here to take a look at the code via the link. This is another really long script, mainly because of the letter conversion function. Originally I set up the function converting lowercase letters into upper case letters of the square font. But I didn't like the way they looked, so I re-wrote the letter conversion function to include converting uppercase letters to a different version of the square font.

I just used the lua command string.upper to make everything uppercase and fed it to the conversion function. I never bothered to delete the lowercase conversion lines :)

Final Fantsy VII

I am a big final fantasy 7 fan, so when rabidofx posted a FF7 themed conky, I immediately thought of the potential to turn the FF7 bottom combat panel into a conky display.

And this is what I eventually came up with!

I have tried to be as faithful as I can to the FF7 panel while still allowing the conky to function as a source of information.

It still needs some work and the script needs a good cleanup and improvements to make it more user friendly. You can get the code here at conky-pitstop! Or here on the crunchbanglinux forum. While your on the forum check out rabidfox's post directly above. He has modified ADcomps Adeskbar to look like materia slots (very nice!).

So why does it take 2200 lines of lua code to produce my FF7 panel conky?
Well 3 reasons... first because it's just a little messy. A lot of copying and pasting went on and I'm sure that I could comb through it an eliminate a large number of supurflouous lines :)

Second drawing in lua with the cairo library takes a lot of lines. To draw the blue shaded rectangles required this:
pat = cairo_pattern_create_linear (sa, sd, rh, rw)
cairo_pattern_add_color_stop_rgba (pat, 0, red-1, green-1, blue, alpha)
cairo_pattern_add_color_stop_rgba (pat, 1, red-1, green-1, blue-1, alpha)
cairo_set_source (cr, pat)
cairo_rectangle (cr, sa, sd, rw, rh)
cairo_fill (cr)
I could have used less lines and specified the positions and colors etc in the actual pattern and drawing lines, but this way is just so much easier for fine tuning. I set the colors up like this becasue I kept forgetting which number represented what in the cairo_set_pattern lines! :)

The grey border around the blue was also line intensive.

Reason 3, and perhaps the main reason for the length of the script is the way you have to use cairo to display text. And if you look closely you will see that every piece of text has a black "shadow" ...which is simply the same piece of text, colored black and printed behind and offset a little.

font="Acknowledge TT (BRK)"
cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, fsize);
cairo_set_source_rgba (cr, red, green, blue, alpha);
cairo_move_to (cr, across, down);
cairo_show_text (cr, text)
cairo_set_source_rgba (cr, red, green, blue, alpha);
cairo_move_to (cr, across, down);
cairo_show_text (cr, text)
So I had to set the font, set the font size, set the red, green, blue and alpha, set the position, write the font, fontsize and color setup lines, move cairo to the coordinates and then tell it to diaplay the text. That gave me the shadow, then I had to change the color and position, set up the text drawing variables and draw the main text.

I kept this format throughout the script, so i could easily change colors and positions without wading through a sea of setup lines.