Wednesday, February 10, 2010

Here is the annotated Lua script for my custom bars.

For simplicity I have put in the settings for only 1 bar.

require "cairo"

So first we have the table below.
The table has a format like this:
but for ease of use and so that the settings can be edited easily the table is split up line by line as follows:
BUT you still have to have all of the brackets (I'm not sure that they have to be curly brackets, but they certainly work.) and all of the commas or you will get an error.
table = {
I have used comments throughout the table so that each setting is easily identified. The comments do not interrupt the format of the table.
--conky object for output
--rectangle width
--rectangle height
--NOTE about width and height. For a bordered rectangle with line width lw (specified below)
--the border is drawn 1/2 lw inside and 1/2 lw outside the boundary of the rectangle, so that
--final width=rw+lw and final height=rh+lw. I did not automate this below as it is possible
--to specify a line width (lw) greater than either width (rw) or height (rh).
--eg if you want a rectangle 200 pixels long and a border line width of 8, then rw=100-8=92
Above is a note about how to set up the heights and widths. If something isn't obvious to anyone who might use the script it's nice to explain things,
--background rectangle color set
--background rectangle alpha
--indicator rectangle color set
--indicator rectangle alpha
--border line width
--border line color set
--border line alpha
--position, x and y
--set rotation in degrees (will require x and y to be reconfigured)
So we have all of the variables set. Each variable will be passed into the various functions and applied to the bars when they are drawn.

There are 2 functions and one sub function in this script. From looking at my last annotated script a function is written and then called below, and then when it is called information is passed up to the function. Here, to see how the information is passed I'll look at the second function first. This is the function that we will be calling in conky:
function conky_draw_shape()
this is the name of the function
local updates=conky_parse('${updates}')
if update_num > 5 then
if conky_window==nil then return end
local w=conky_window.width
local h=conky_window.height
local cs=cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, w, h)
The above should be familiar. It sets the 5 cycle delay and the surface onto which cairo will draw. Next comes a local function. This function called "parse" which takes the table entry "co" (the conky object whose output will be displayed by the bar) and performs the conky_parse command on it.
local function parse(cr,pt)
Here is the local function name and the strings that will be set when the function is used below.
local str=''
local value=0
The pt part is the important part (note that there is nothing important about the term pt, it is just the name of a string and could be anything. Perhaps pt stands for parse table). pt is one of the strings that is set by the parse function from information fed to the function when it is called. Also you should remember 'co' as one of the variables we set in the settings table.
The function is parsing 'co' the conky object, running that through the tonumber command and then storing the information in a string named "value"
if value == nil then value = 0 end
The line above is calling the first function in the script, and feeding the function 3 things: cr, pt and value. As we saw the "value" string is generated above and it is that string that will be passed to the draw_table function.
Here is the end of the local function. Below is the remaining commands of the "global" function called "draw_shape"
for i in pairs(table) do

parse(cr, table[i])
These 2 lines is where the "magic" happens :) These lines read the contents of the table, and pass each set of variables to the parse function. In this case the letter "i" is extremely important and cannot be substituted. Perhaps "i" stands for "instance" or "index", I don't know exactly. So basically what is being done is that for every set of data ie {A1=1,B1=2,C1=3,D1=4} in the settings table the "parse" function is being called and fed the cr string as well as every string that the set contains ( A1, B1, C1, D1).

As you can see the parse function is being sent 2 things cr and table[i]. Then as we saw the parse function (local function parse(cr,pt)) takes cr and stores it as cr and takes the output of table[i] and stores it as pt. Then in the parse function we see pt['co'] which is the same as "table['co']". So the table is being searched for the string co, and the value of co is being formatted (str=string.format('${%s}',pt['co'])) and stored in the string called "str".

So for the data set "table= {A1=1,B1=2,C1=3,D1=4}"

and as in the parse function table[i] = pt[i] so that


I hope that all makes sense.
So to recap...
  • function draw_shape is generating the strings: cr and table[i]
  • function parse is being fed cr (but not doing anything with it) and table[i] and renaming table[i] as the string pt.
  • parse is looking through the string "pt" for the table setting 'co' then parsing and formatting the output and storing it as the string "value".
parse is then feeding the strings "cr", "pt" and the new string "value" up to the function settings_table.

Now we are going back to the point after the settings table (confused yet? :) )
Here we have the first function in the Lua script and we have already seen where the strings cr, pt and value are being fed from.
function draw_table(cr, pt, value)
local width=pt['rw']
local height=pt['rh']
local bgalpha=pt['rab']
local indalpha=pt['rai']
local across=pt['rx']
local down=pt['ry']
local lwide=pt['lw']
local lalpha=pt['la']
local bgcolr=pt['bg_red']
local bgcolg=pt['bg_green']
local bgcolb=pt['bg_blue']
local incolr=pt['in_red']
local incolg=pt['in_green']
local incolb=pt['in_blue']
local lcolr=pt['l_red']
local lcolg=pt['l_green']
local lcolb=pt['l_blue']
local rotate=pt['rot']
Above are a number of lines that are searching the table information (stored in the string pt) for the various bits and pieces of information. Then when the specific bit of information is found, that information is being set as a local string. For example:
local width=pt['rw']
string pt is being searched for the table setting "rw" (rectangle width) and storing the value of this setting in the local string "width".
--indicator calculation
local inum=(((width-lwide)/100)*value)
The above calculation allows the bars to be resized while maintainig the correct proportions of the indicator line.
--set initial rotation
cairo_rotate (cr, rotate*math.pi/180)
Here we are applying the local string rotate (initially set in the settings table as "rot") and performing the rotation, if any.
--background bar
cairo_rectangle (cr, (across+(lwide/2)), (down+(lwide/2)), (width-lwide), (height-lwide))
cairo_set_source_rgba (cr, bgcolr, bgcolg, bgcolb, bgalpha);
cairo_fill (cr)
Above we are drawing the background bar using the local strings we set above. The calculations in the code are to account for the way that the outline of rhe rectangle is drawn. This was explained towards the top of the script.
--indicator bar
cairo_rectangle (cr, (across+(lwide/2)), (down+(lwide/2)), inum, (height-lwide))
cairo_set_source_rgba (cr, incolr, incolg, incolb, indalpha);
cairo_fill (cr)
Above we generate the indicator bar.
--border line
cairo_set_line_width (cr, lwide);
cairo_rectangle (cr, across, down, width, height)
cairo_set_source_rgba (cr, lcolr, lcolg, lcolb, lalpha);
cairo_stroke (cr)
And above we draw the outline, if any.
--resets rotation
cairo_rotate (cr, (rotate*-1)*math.pi/180)
Then we reset rotation.
Below you can look through the functions that have been described above, but in the correct order.
function conky_draw_shape()
local updates=conky_parse('${updates}')
if update_num > 5 then
if conky_window==nil then return end
local w=conky_window.width
local h=conky_window.height
local cs=cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, w, h)
local function parse(cr,pt)
local str=''
local value=0
if value == nil then value = 0 end
for i in pairs(table) do
parse(cr, table[i])
That's the end.
Here is an approach that achieves the same result as a settings table, in that you can achieve multiple outputs from a single instance of a function. But I think that this next approach is easier to implement and considerable shorter code wise. And here is my first take at explaining the use of arrays in a Lua script.

No comments:

Post a Comment