-- 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