dotfiles/awesome/lib/lain/widget/cal.lua

227 lines
6.4 KiB
Lua

--[[
Licensed under GNU General Public License v2
* (c) 2018, Luca CPZ
--]]
local helpers = require('lain.helpers')
local markup = require('lain.util.markup')
local awful = require('awful')
local naughty = require('naughty')
local floor = math.floor
local os = os
local pairs = pairs
local string = string
local tconcat = table.concat
local type = type
local tonumber = tonumber
local tostring = tostring
-- Calendar notification
-- lain.widget.cal
local function factory(args)
args = args or {}
local cal = {
attach_to = args.attach_to or {},
week_start = args.week_start or 2,
three = args.three or false,
followtag = args.followtag or false,
week_number = args.week_number or 'none',
week_number_format = args.week_number_format or args.week_number == 'left' and '%3d | ' or '| %-3d',
icons = args.icons or helpers.icons_dir .. 'cal/white/',
notification_preset = args.notification_preset or {
font = 'Monospace 10',
fg = '#FFFFFF',
bg = '#000000',
},
}
function cal.get_week_number(m, st_day, x)
local date = os.date('*t', m)
local week_step = (x ~= 0 and floor((x + st_day) / 7) - 1 or 0)
local display_time = os.time({
year = date.year,
month = date.month,
day = date.day + 7 * week_step,
})
return string.format(cal.week_number_format, os.date('%V', display_time))
end
function cal.sum_week_days(x, y)
return (x + y) % 7
end
function cal.build(month, year)
local current_month, current_year = tonumber(os.date('%m')), tonumber(os.date('%Y'))
local is_current_month = (not month or not year) or (month == current_month and year == current_year)
local today = is_current_month and tonumber(os.date('%d')) -- otherwise nil and not highlighted
local t = os.time({ year = year or current_year, month = month and month + 1 or current_month + 1, day = 0 })
local d = os.date('*t', t)
local mth_days, st_day, this_month = d.day, (d.wday - d.day - cal.week_start + 1) % 7, os.date('%B %Y', t)
local notifytable = {
[1] = string.format('%s%s\n', string.rep(' ', floor((28 - this_month:len()) / 2)), markup.bold(this_month)),
}
for day_num = 0, 6 do
notifytable[#notifytable + 1] = string.format(
'%3s ',
os.date('%a', os.time({ year = 2006, month = 1, day = day_num + cal.week_start }))
)
end
notifytable[#notifytable] =
string.format('%s\n%s', notifytable[#notifytable]:sub(1, -2), string.rep(' ', st_day * 4))
local strx
for x = 1, mth_days do
strx = x
if x == today then
if x < 10 then
x = ' ' .. x
end
strx = markup.bold(markup.color(cal.notification_preset.bg, cal.notification_preset.fg, x) .. ' ')
end
strx = string.format('%s%s', string.rep(' ', 3 - tostring(x):len()), strx)
notifytable[#notifytable + 1] =
string.format('%-4s%s', strx, (x + st_day) % 7 == 0 and x ~= mth_days and '\n' or '')
end
if string.len(cal.icons or '') > 0 and today then
cal.icon = cal.icons .. today .. '.png'
end
cal.month, cal.year = d.month, d.year
if cal.week_number ~= 'none' then
local m = os.time({ year = year or current_year, month = month and month or current_month, day = 1 })
local head_prepend = string.rep(' ', tostring(string.format(cal.week_number_format, 0)):len())
if cal.week_number == 'left' then
notifytable[1] = head_prepend .. notifytable[1] -- month-year row
notifytable[2] = head_prepend .. notifytable[2] -- weekdays row
notifytable[8] = notifytable[8]:gsub('\n', '\n' .. cal.get_week_number(m, st_day, 0)) -- first week of the month
for x = 10, #notifytable do
if cal.sum_week_days(st_day, x) == 2 then
notifytable[x] = cal.get_week_number(m, st_day, x) .. notifytable[x]
end
end
elseif cal.week_number == 'right' then
notifytable[8] = notifytable[8]:gsub('\n', head_prepend .. '\n') -- weekdays row
for x = 9, #notifytable do
if cal.sum_week_days(st_day, x) == 1 then
notifytable[x] = notifytable[x]:gsub('\n', cal.get_week_number(m, st_day, x - 7) .. '\n')
end
end
-- last week of the month
local end_days = cal.sum_week_days(st_day, mth_days)
if end_days ~= 0 then
end_days = 7 - end_days
end
notifytable[#notifytable] = notifytable[#notifytable]
.. string.rep(' ', 4 * end_days)
.. cal.get_week_number(m, st_day, mth_days + end_days)
end
end
return notifytable
end
function cal.getdate(month, year, offset)
if not month or not year then
month = tonumber(os.date('%m'))
year = tonumber(os.date('%Y'))
end
month = month + offset
while month > 12 do
month = month - 12
year = year + 1
end
while month < 1 do
month = month + 12
year = year - 1
end
return month, year
end
function cal.hide()
if not cal.notification then
return
end
naughty.destroy(cal.notification)
cal.notification = nil
end
function cal.show(seconds, month, year, scr)
local text = tconcat(cal.build(month, year))
if cal.three then
local current_month, current_year = cal.month, cal.year
local prev_month, prev_year = cal.getdate(cal.month, cal.year, -1)
local next_month, next_year = cal.getdate(cal.month, cal.year, 1)
text = string.format(
'%s\n\n%s\n\n%s',
tconcat(cal.build(prev_month, prev_year)),
text,
tconcat(cal.build(next_month, next_year))
)
cal.month, cal.year = current_month, current_year
end
if cal.notification then
local title = cal.notification_preset.title or nil
naughty.replace_text(cal.notification, title, text)
return
end
cal.notification = naughty.notify({
preset = cal.notification_preset,
screen = cal.followtag and awful.screen.focused() or scr or 1,
icon = cal.icon,
timeout = type(seconds) == 'number' and seconds or cal.notification_preset.timeout or 5,
text = text,
})
end
function cal.hover_on()
cal.show(0)
end
function cal.move(offset)
offset = offset or 0
cal.month, cal.year = cal.getdate(cal.month, cal.year, offset)
cal.show(0, cal.month, cal.year)
end
function cal.prev()
cal.move(-1)
end
function cal.next()
cal.move(1)
end
function cal.attach(widget)
widget:connect_signal('mouse::enter', cal.hover_on)
widget:connect_signal('mouse::leave', cal.hide)
widget:buttons(
awful.util.table.join(
awful.button({}, 1, cal.prev),
awful.button({}, 3, cal.next),
awful.button({}, 2, cal.hover_on),
awful.button({}, 5, cal.prev),
awful.button({}, 4, cal.next)
)
)
end
for _, widget in pairs(cal.attach_to) do
cal.attach(widget)
end
return cal
end
return factory