1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
-- Sky: sunrise, sunset, day length and the moon, over the daylight arc.
--
-- Adapted from the Conky-Mirage theme's sky tile by alexsson-xexpanderx
-- (see lib/weather.lua). The arc is the one the old weather card drew, minus
-- its time labels: the rows carry the times now.
local card = require 'lib.card'
local data = require 'lib.data'
local weather = require 'lib.weather'
local M = {}
-- The dot is placed by evaluating the curve at t rather than by computing a
-- point on a circle: the curve IS the path, so evaluating it keeps the dot on
-- the arc if the control points are ever adjusted.
local function draw_arc(cr, x, y, w, h, colors, rise, set, now)
local pad = math.max(4, w * 0.012)
local x0, x1 = x + pad, x + w - pad
local base = y + h - pad
local top = y + h * 0.08
-- Cubic Bezier control points, chosen so the curve peaks near the middle.
local p0 = { x0, base }
local c1 = { x0 + (x1 - x0) * 0.22, top - h * 0.14 }
local c2 = { x1 - (x1 - x0) * 0.22, top - h * 0.14 }
local p3 = { x1, base }
-- The horizon the sun rises from and sets into.
card.rgba(cr, colors.rule, 0.6)
cairo_set_line_width(cr, 1)
cairo_move_to(cr, x0, base)
cairo_line_to(cr, x1, base)
cairo_stroke(cr)
card.rgba(cr, colors.rule, 0.9)
cairo_set_line_width(cr, 1.5)
cairo_move_to(cr, p0[1], p0[2])
cairo_curve_to(cr, c1[1], c1[2], c2[1], c2[2], p3[1], p3[2])
cairo_stroke(cr)
local t = weather.sun_t(now, rise, set) or 0
local function bez(a, b, c, d)
local u = 1 - t
return u * u * u * a + 3 * u * u * t * b + 3 * u * t * t * c + t * t * t * d
end
-- At night the dot is parked at an end, so it takes the dim colour: a bright
-- dot on the horizon would read as a sun that is still up.
card.rgba(cr, weather.is_day(now, rise, set) and colors.body or colors.label)
cairo_new_path(cr)
cairo_arc(cr, bez(p0[1], c1[1], c2[1], p3[1]), bez(p0[2], c1[2], c2[2], p3[2]),
math.max(3, math.min(9, h * 0.045)), 0, math.pi * 2)
cairo_fill(cr)
end
function M.draw(cr, rect, colors)
local inner = card.card(cr, rect, colors)
local w = weather.parse(data.slurp(weather.CACHE))
if not w then
card.notice(cr, inner, colors, 'SKY', 'no weather data', 'bin/weather-fetch.sh')
return
end
local now = os.time()
local rise, set = w.sun.rise, w.sun.set
local phase, lit = weather.moon(now)
local rows = {
{ 'SUNRISE', os.date('%H:%M', rise) },
{ 'SUNSET', os.date('%H:%M', set) },
{ 'DAYLIGHT', weather.duration(set - rise) },
{ 'MOON', weather.num(lit * 100, '%') },
}
local y = card.standard(cr, inner, colors, {
icon = card.ICON.sky, title = 'SKY',
big = weather.moon_icon(phase), big_font = card.FONT_MONO,
big_color = colors.heading, rows = rows, share = 0.65,
})
-- An arch taller than about 0.6 of its width reads as a door, not a day.
local arc_h = math.min(inner.y + inner.h - y, inner.w * 0.6)
if arc_h >= 50 then
draw_arc(cr, inner.x, inner.y + inner.h - arc_h, inner.w, arc_h, colors, rise, set, now)
end
end
return M
|