--[[
calendar wheel by Wlourf (14 jan. 2010)
This script is designed to draw dates on a circular way on the left of the screen.
Some text can be added in the circle with the file calendar.txt (see below)
Some parameters (colors, sizes ... ) can be adjusted (see below).
As this script draw a lot of things, a short update of the conky is not necessary.
Call this script in Conky using the following before TEXT (assuming you save this script to ~/scripts/calendar.lua):
lua_load ~/scripts/calendar.lua
lua_draw_hook_pre draw_calendar
v1.0 - 14 jan. 2010 - Original release
v1.1 - 19 jan. 2010 - Calendar are now drawn in an PNG file and this file
is called at every conky call, when day change, a new PNG file is created.
- An x offset can be added to "Today's block"
- An y offset can be added too to "Today's block"
]]
require 'cairo'
require 'imlib2'
-------------------------- parameters (part one) are set here -----------------------------------
--text file calendar (absolute path, can be "" if no file used)
calendar_file="/home/soprano/Documenti/Documenti/ubuntu/conky/wheelcalendar/calendar_wheel/calendar.txt"
--format of in this text file
--MMDD;N;TEXT
--MMDD = month day
--N = 0 or 1 (1 to display same colors as week-ends)
--TEXT = Text to display (use * for multiline)
--some paths to images created (absolutes paths)
image_tmp="/tmp/img_tmp.png" --used to rotate a single date
image_calendar="/tmp/conky-calendar-arc.png"
image_dates="/tmp/conky-calendar-dates.png"
--more parameters below
-------------------------- end of parameters (part one) -----------------------------------
function string:split(delimiter)
--source for the split function :
http://www.wellho.net/resources/ex.php4?item=u108/split
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 )
end
table.insert( result, string.sub( self, from ) )
return result
end
function conky_draw_calendar()
if conky_window==nil then return end
local width=conky_window.width
local height=conky_window.height
--sometimes, there is problem with init and width & height are set to 0 or 2 !!
if width 60 days are displayed)
--even number between 20 and 30 for nice effect
range = 20
--not sure of the engish words so I leave then in french !
--fleche (arrow) is the segment from x=0 to x=radius-xc (with xc =center of the circle)
--fleche for the external circle
--fleche2 for the internal circle
--fleche2 must be < fleche
fleche=150
fleche2=fleche*.5
--corde (chord) is the vertical segment (where x=0) of the external circle
--if 'corde' too close to 'height', imlib will display some warnings
corde=height--200
--colors RGB (0-255)
--week day
wday={36,35,33}
--week-end and bank holidays
eday={181,181,181}
--color of today
dday={218,68,18}
--vertical gradient (both circle and dates)? (true/false)
vgradient=true
--horizontal gradient for the circle? (0 to 1, 0 is the best choice for "moon like" circle )
hgradient=0
--you can change the font here
font="Antipasto"
--font_size (of dates) must be less than delta (= heigth of a day)
delta = yc/(range+0.5)
--the font-size has to be adjusted depending on the font used
font_size=delta-2
--information text (from calendar.txt)
info_color={36,35,33}
--font size of text infos
font_size_info=font_size
--today_xoffset is the offset for the date of today (can be positive/null/negative, in pixels)
today_xoffset=10
--where today will be displayed (value between -range to + range)?
-- 0 = center of the arc
-- -range = top of the arc
-- +range = bottom of the arc
today_yoffset=-10
-------------------------- end of the parameters, ouf -----------------------------------
--some calculations
--radius for external circle
--radius2 for internal circle
--delta = number of arcs in the circle
radius=(corde^2+4*fleche^2)/(8*fleche)
radius2=(corde^2+4*fleche2^2)/(8*fleche2)
decal=2*(delta-font_size)
wday[1]=wday[1]/255
wday[2]=wday[2]/255
wday[3]=wday[3]/255
eday[1]=eday[1]/255
eday[2]=eday[2]/255
eday[3]=eday[3]/255
--xc =x center of external circle
--xc2=x center of internal circle
xc = fleche - radius
xc2 = fleche2 - radius2
--local cs=cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, w, h)
h_txt = height/(2*range+1)
--local cs2=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 100, h_txt)
-- conky_window.drawable
cr2=cairo_create(cs2)
t = os.date('*t') -- date in table
--read the calendar file
file = io.open(calendar_file,"r")
tabcal={}
idx=1
if file ~= nil then
while true do
line = file:read("*l")
if line == nil then break end
lineok = string.split(line,";") --text = line .. "\n" .. text
if (#lineok)==3 then
tabcal[idx]={lineok[1],lineok[2],lineok[3]}
idx=idx+1
end
end
end
angmini=math.atan((corde/2)/(radius-fleche))
local imageDates=imlib_create_image(width,height)
imlib_context_set_image(imageDates)
imlib_image_set_has_alpha(1)
imlib_save_image(image_dates)
--imlib_context_set_image(imageDates)
--imlib_free_image()
--get the date
s = os.time(t) -- date in seconds
for i=-range,range do
s2 = s + 3600*24*(i-today_yoffset) --date diff in seconds
wd = os.date("%w",s2)
md = os.date("%m%d",s2)
dt = os.date("%a. %d",s2),os.date("%d",s2),os.date("%b",s2)
--percentage of vertical gradient
pc=(range-math.abs(i))/range
if not vgradient then pc=1 end
--angle min et max of one block
ang0=angmini*((i-0.5)/range)
ang1=angmini*(i+0.5)/range
angm=(ang0+ang1)/2
--read the calendar.txt array
flag = false
for idy=1,idx-1 do
if tabcal[idy][1] == md then
if (i-today_yoffset) == 0 then
today = tabcal[idy]
end
if tabcal[idy][2] == "1" then
flag = true
end
break
end
end
--colors
if wd=="6" or wd=="0" or flag == true then
colR,colG,colB=eday[1],eday[2],eday[3]
else
colR,colG,colB=wday[1],wday[2],wday[3]
end
--offset of today
offset=0
if (i-today_yoffset)==0 then offset=today_xoffset end
--cairo_set_source_rgba (cr,colR, colG, colB,pc);
pat = cairo_pattern_create_radial (xc+offset, yc, radius,
xc2+offset,yc,radius2);
cairo_pattern_add_color_stop_rgba (pat, 0, colR, colG, colB, pc);
cairo_pattern_add_color_stop_rgba (pat, 1, colR, colG, colB, hgradient);
cairo_set_source (cr, pat);
--draw the arcs
x1,y1=radius*math.cos(ang0)+xc+offset,radius*math.sin(ang0)+yc+offset*math.atan(ang0)
x2,y2=radius*math.cos(ang1)+xc+offset,radius*math.sin(ang1)+yc+offset*math.atan(ang1)
-- xm,ym=radius*math.cos(angm)+xc,radius*math.sin(angm)+yc
-- am=(ym-yc)/(xm-xc)
-- bm=ym-am*xm
cairo_move_to(cr,x1,y1)
cairo_line_to(cr,x2,y2)
cairo_line_to(cr,xc,yc)
cairo_fill(cr)
--write text info if needed
have=""
if today ~= nil then
cairo_select_font_face(cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL )
cairo_set_line_width(cr,0)
cairo_set_font_size(cr,font_size_info)
cairo_set_source_rgba (cr, info_color[1]/255, info_color[2]/255, info_color[3]/255,1);
have = string.split(today[3],"*")
for i=1,#have do
cairo_move_to(cr,10,height/2+(i-#have/2)*font_size_info)
cairo_show_text(cr, have
)
cairo_fill(cr)
end
end
--lenght of the arc
dx,dy=math.abs(x2-x1),math.abs(y2-y1)
h_txt=math.sqrt(dx*dx+dy*dy)
w_txt=font_size*10
--write text in another image
--didn't find to work in memory only
local cs2=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w_txt, h_txt)
local cr2=cairo_create(cs2)
cairo_set_font_size (cr2, font_size);
if (i-today_yoffset)==0 then
colR, colG, colB = dday[1]/255,dday[2]/255,dday[3]/255
pc=1
end
cairo_select_font_face(cr2, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL)
cairo_move_to(cr,xc+(delta+radius)*math.cos(ang0),corde/2+(radius-fleche)*math.tan(ang0))
cairo_move_to(cr2,0,h_txt-decal+offset*math.atan(ang0))
cairo_set_source_rgba (cr2, colR, colG, colB,pc)
cairo_show_text(cr2, " " .. dt)
cairo_stroke(cr2)
--write ONE date in picture
cairo_surface_write_to_png(cs2,image_tmp)
--cairo_destroy(cr2)
--put date text on cairo surface
local imageTmp = imlib_load_image(image_tmp)
imlib_context_set_image(imageTmp)
rot_img = imlib_create_rotated_image(angm)
imlib_free_image()
--image is now a square
imlib_context_set_image(rot_img)
w_img0, h_img0 = imlib_image_get_width(), imlib_image_get_height()
---look for center of text
rt=radius+w_txt/2
xt=rt*math.cos(angm)+xc-w_img0/2+offset
yt=rt*math.sin(angm)+yc-h_img0/2
imlib_context_set_image(imageDates)
imlib_blend_image_onto_image(rot_img, 1, 0, 0, w_img0, h_img0, xt,yt, w_img0, h_img0)
local imageDates=imlib_context_get_image()
imlib_context_set_image(rot_img)
imlib_free_image()
cairo_destroy(cr2)
cairo_surface_destroy(cs2)
end
--write to disk images with dates only
imlib_context_set_image(imageDates)
imlib_save_image(image_dates)
--write to disk image with arc only
cairo_surface_write_to_png(cs,image_calendar)
--make final image
local imageCal = imlib_load_image(image_calendar)
imlib_context_set_image(imageCal)
imlib_blend_image_onto_image(imageDates, 1, 0, 0, width, height, 0,0, width, height)
imlib_save_image(image_calendar)
imlib_free_image()
imlib_context_set_image(imageDates)
imlib_free_image()
--free memory
cairo_destroy(cr)
cairo_surface_destroy(cs)
end
function conky_main()
actual_date = os.date("%H%M") --os.date("%Y%m%d")
actual_cal = imlib_load_image(image_calendar)
if (conky_parse('${updates}')+0) <2 then return end
if variable ~= actual_date or actual_cal == nil then
--print (os.date("%H%M%S"),'new picture')
conky_draw_calendar()
variable = actual_date
else
--print (os.date("%H%M%S"),'use old picture')
end
if actual_cal == nil then
actual_cal = imlib_load_image(image_calendar)
end
imlib_context_set_image(actual_cal)
imlib_render_image_on_drawable(0,0)
imlib_free_image()
end