Skip to content

Using Lua scripts (Part 03): Drawing lines

lasers edited this page Jan 5, 2019 · 3 revisions

iii: Drawing lines

How to draw a straight line! so one of the basic things to be able to do is to draw a line there are several commands we need to consider for lines

line thickness cairo_set_line_width (cr,1)

NOTE, you can see here, and in other examples the general form that the cairo commands take cairo_something (cr,settings) we set the value of cr in our main function setup lines, and every time you use a cairo command, the first thing within the curved brackets will be cr

line end cap

cairo_set_line_cap  (cr, CAIRO_LINE_CAP_BUTT)
or
cairo_set_line_cap  (cr, CAIRO_LINE_CAP_ROUND)
or
cairo_set_line_cap  (cr, CAIRO_LINE_CAP_SQUARE)

see here for more info Cairo Manual the default is BUTT, so that is what you get if you don't setup the cap type

and then commands we have seen before cairo_set_source_rgba (cr,1,1,1,1)

and we need to specify where the line is going to start cairo_move_to (cr,100,100)

we could do our setup like we did for our text

line_width=1
line_cap=CAIRO_LINE_CAP_BUTT
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap  (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)

now we need to draw the line and there are 2 ways to do it you can specify the ending coordinates directly cairo_line_to (cr,200,100) or you can specify where the line should go relative to the start cairo_rel_line_to (cr,100,0)

in this case we get the same result... in the first example we start at 100,100 and tell cairo to draw a line to 200,100

in the second example we start at 100,100 and tell cairo to draw a line to a point 100 pixels to the right of where we started and 0 pixels down from where we started

so both examples will give a horizontal line 100 pixels long

once we have finished specifying the coordinates we then tell cairo to actually draw the line cairo_stroke (cr)

i tend to use the absolute method, "line_to" rather than the relative method so altogether:

line_width=1
line_cap=CAIRO_LINE_CAP_BUTT
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
endx=200
endy=100
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap  (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)
cairo_line_to (cr,endx,endy)
cairo_stroke (cr)

NOTE about line thickness we set a line from 100,100 to 200,100 but setting a line thickness greater than 1 will affect not only what the line looks like but where it appears to have been drawn if we set, for example, a line width of 10, then the line will be 5 pixels wide to one side of the base line, and 5 pixels wide to the other side

that is, the top left corner of the line will actually be at 100,95 and the bottom left corner at 100,105 (remember that the larger the x and y numbers the more right and down they are) the line will be more of a rectangle.

making the line more interesting but with some math and tweaking we can easily make this line change in length relative to a conky object

once you get the idea of using variables and strings to affect the coordinates and other values of drawn objects then you are a good way there and everything else is just the complexity of the interactions and what is being drawn

for example we want to make a cpu usage indicator line cpu_perc=tonumber(conky_parse("${cpu}")) I will use tonumber just to make sure... it can be easy to get lost in curved brackets when using compound commands like this :)

this will output a number between 0 and 100 the line we have already drawn is 100 pixels long so its easy enough to do the following

cpu_perc=tonumber(conky_parse("${cpu}"))
line_width=1
line_cap=CAIRO_LINE_CAP_BUTT
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
endx=startx+cpu_perc
endy=starty
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap  (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)
cairo_line_to (cr,endx,endy)
cairo_stroke (cr)

this is what is going to make the line move endx=startx+cpu_perc the horizontal end point of my line will change in relation to the value of cpu_perc as measure through the conky variable ${cpu}

i have made a couple of other changes... instead of saying endx=100+cpu_perc i have put endx=startx+cpu_perc and instead of endy=100 i have endy=starty

using this method, all i have to do is edit startx and starty and those changes will follow on to the other strings

when i am writing scripts i find it time saving to set as few "absolute" vales as possible gives you less things to find later on when you want to make changes

you can do more with lines than just draw lines

you can use lines to draw shapes you can then have these shapes as outlines or fill them in

a triangle for example there are some other things to consider when using multiple lines one thing is how to join the lines together which is set by the following

cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER)
or
cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL)
or
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND)

see here for more details Cairo manual (line join)

MITER is the default so that is what you get when you dont set line join type

we can also use this command cairo_close_path (cr) close path tells cairo that the lines should be joined together at the ends to make one continuous line

this is what you get without close_path on the left and with close_path on the right this is using the default MITER line join also

NOTE as soon as you set cairo_close_path the setting for line cap type becomes redundant, as there are no longer any line ends

here is the code for the figure on the right above

line_width=20
line_cap=CAIRO_LINE_CAP_BUTT --we don't need this any more after closing the path
line_join=CAIRO_LINE_JOIN_MITER --but this will still affect how the lines look
red,green,blue,alpha=1,1,1,1
startx=100
starty=100
pointx=startx+100
pointy=starty+100
endx=pointx-100
endy=pointy
----------------------------
cairo_set_line_width (cr,line_width)
cairo_set_line_cap  (cr, line_cap)
cairo_set_source_rgba (cr,red,green,blue,alpha)
cairo_move_to (cr,startx,starty)
cairo_line_to (cr,pointx,pointy)
cairo_line_to (cr,endx,endy)
cairo_line_to (cr,startx,starty)
cairo_set_line_join (cr, line_join)
cairo_close_path (cr)
cairo_stroke (cr)

NOTE as you can see, you don't have to draw each individual line as you are instead drawing a "path" (imagine a pen being drawn on paper in one continuous line from point to point)

you only need to use cairo_stroke at the end to draw along the path you set to see the lines

it is also good to know that by using the close_path command we don't actually need to draw the third side of the triangle. When you use close_path cairo will draw a line from wherever you stop back to the start.

if we want to fill in the triangle we use cairo_fill (cr) instead of cairo_stroke (cr)

but with cairo_fill the setting for line width no longer applies. also with fill the line join type no longer applies

The fill fills in only the triangle bound by the coordinates we set.

ALSO with cairo_fill, we need not use the close_path command, as the fill command will automatically close the path in order to generate a boundary area to fill in... but it never hurts to use the close_path command and nothing bad will happen if you set redundant commands :D

for example i could specify all 3 sides of the triangle, close_path and then cairo_fill and i will still get a filled in triangle! lua code can be quite forgiving

here is stroke vs fill

and if you want the shape outlined and filled (for example in different colors) we would first use cairo_fill_preserve (instead of just cairo_fill), then set our second color and use cairo_stroke to draw the outline

cairo_set_line_width (cr,20)
cairo_move_to (cr,100,100)--start point
cairo_line_to (cr,200,200)--diagonal line down
cairo_line_to (cr,100,200)--horizontal line
cairo_close_path (cr)--draws vertical line back to start
cairo_set_source_rgba (cr,1,1,1,1)--white
cairo_fill_preserve (cr)--fills in the triangle in white
cairo_set_source_rgba (cr,1,0,0,1)--red
cairo_stroke (cr)--draws the triangle outline in red
You can’t perform that action at this time.