aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md15
-rw-r--r--widgets/calendar.lua91
2 files changed, 92 insertions, 14 deletions
diff --git a/README.md b/README.md
index c3a4261..5ec6b61 100644
--- a/README.md
+++ b/README.md
@@ -154,16 +154,25 @@ takes its calendar's colour; today takes a filled pill, coloured by its own
calendar when something is on and `highlight` otherwise, with the number over
it in the heading colour because a calendar colour loses too much contrast
against the fill. Past days in the month dim: the grid is mostly about what is
-still coming. Below the grid, one row per appointment, start time left in the
-calendar's colour and title right in the body colour. Colour-coding the whole
+still coming. Below the grid, one row per appointment: date and start time
+left in the calendar's colour, title right in the body colour. The date is
+day/month with no year, since the window is a week and the grid above already
+names the month. Colour-coding the whole
row makes three calendars read as three unrelated cards, so the time carries
the code and the title stays readable. All-day events read `all day`, never
`00:00`, because midnight is a legitimate start time.
+A legend of the calendar colours is pinned along the card's bottom, in name
+order so it does not reshuffle between frames, and the event rows end above it
+rather than running under it. It lists every calendar khal declared a colour
+for, including ones with nothing on this week: it is a colour key, not a second
+list of what is coming.
+
Events come from a cache file written by `bin/calendar-sample.sh`, which shells
out to `khal`. The card shows as many rows as the cell affords and ends with
`+N more` when the week does not fit, since a card that silently drops the rest
-of the week defeats its own purpose.
+of the week defeats its own purpose. A cell too short for even one row draws
+the grid alone, without the legend, rather than a clipped half-row.
**Calendar colours come from khal's own config**, parsed out of the
`[calendars]` section by the sampler, then mapped onto the board's palette
diff --git a/widgets/calendar.lua b/widgets/calendar.lua
index 82e10d3..6194447 100644
--- a/widgets/calendar.lua
+++ b/widgets/calendar.lua
@@ -41,11 +41,15 @@ local function cal_colour(name, colors, khal_colors)
return colors[role] or colors.value
end
--- 'Dentist' at 13:00 -> '13:00', an all-day event -> 'all day'.
--- Never '00:00' for an all-day event: midnight is a legitimate start time and
--- the two must not read the same.
+-- 'Dentist' on 24 September at 13:00 -> '24/09 13:00', an all-day event ->
+-- '26/09 all day'. Never '00:00' for an all-day event: midnight is a
+-- legitimate start time and the two must not read the same.
+--
+-- Day/month, no year: the grid above already names the month, and the window
+-- is a week, so a year would be three characters of the row spent on the one
+-- field that cannot vary.
local function when(e)
- return e.start or 'all day'
+ return string.format('%02d/%02d %s', e.d, e.m, e.start or 'all day')
end
-- The failure face: the sampler has not run. Named, as the other cached cards
@@ -66,6 +70,33 @@ local function draw_empty(cr, inner, colors, label_f, note, hint)
card.text(cr, inner.x, inner.y + S + S * label_f * 2.6 + S * 0.72, hint)
end
+-- The legend: one coloured dot and name per calendar, along the card's bottom.
+-- Wraps to a second line when the names do not fit, and drops any that still
+-- do not: a legend spilling off the card is worse than a short one, since the
+-- colours are also readable from the grid above.
+local function draw_legend(cr, inner, y, size, names, colors, khal_colors)
+ card.font(cr, card.FONT_MONO, size, false)
+ local r = size * 0.30
+ local x = inner.x
+ local right = inner.x + inner.w
+ for _, name in ipairs(names) do
+ local w = r * 2 + size * 0.45 + card.advance(cr, name)
+ if x + w > right then
+ -- Next line, if the card has one to give.
+ x = inner.x
+ y = y + size * 1.5
+ if y > inner.y + inner.h then return end
+ end
+ card.rgba(cr, cal_colour(name, colors, khal_colors))
+ cairo_new_path(cr)
+ cairo_arc(cr, x + r, y - size * 0.32, r, 0, math.pi * 2)
+ cairo_fill(cr)
+ card.rgba(cr, colors.label, 0.85)
+ card.text(cr, x + r * 2 + size * 0.45, y, name)
+ x = x + w + size * 0.9
+ end
+end
+
function M.draw(cr, rect, colors)
local inner = card.card(cr, rect, colors)
local LABEL_F = 0.30
@@ -113,7 +144,9 @@ function M.draw(cr, rect, colors)
card.text(cr, inner.x, inner.y + label_size, 'CALENDAR')
-- === Month grid =========================================================
- local gy = inner.y + big_size * 1.5
+ -- 2.3, not 1.5: the weekday row sat close enough to the header that the
+ -- initials read as part of it rather than as the top of the grid.
+ local gy = inner.y + big_size * 2.3
local row_h = day_size * 1.55
-- Weekday initials. Monday-first, matching khal's firstweekday = 0.
@@ -173,10 +206,25 @@ function M.draw(cr, rect, colors)
-- === Event table ========================================================
-- Everything below the grid, however much that is. A card too short for even
-- one row draws the grid alone rather than a clipped half-row.
- local avail = (inner.y + inner.h) - grid_bottom
local ev_size = clamp(day_size * 0.78, 7, 18)
local ev_step = ev_size * 1.75
- if avail < ev_step then return end
+
+ -- The legend is pinned to the card's bottom, so the event rows end above it
+ -- rather than running under it. Only calendars that khal declared a colour
+ -- for appear, in the config's own order, which is why the names are sorted
+ -- rather than taken from a hash walk: pairs() would reorder the legend
+ -- between frames.
+ local legend = {}
+ for name in pairs(cal.colors) do legend[#legend + 1] = name end
+ table.sort(legend)
+
+ local legend_size = ev_size * 0.82
+ local legend_h = #legend > 0 and legend_size * 2.0 or 0
+ local floor_y = inner.y + inner.h - legend_h
+
+ local avail = floor_y - grid_bottom
+ if avail < ev_step then legend = {}; legend_h = 0; floor_y = inner.y + inner.h end
+ if (floor_y - grid_bottom) < ev_step then return end
local ey = grid_bottom + ev_size * 1.1
@@ -184,6 +232,10 @@ function M.draw(cr, rect, colors)
card.font(cr, card.FONT_UI, ev_size, false)
card.rgba(cr, colors.label, 0.8)
card.text(cr, inner.x, ey, 'nothing this week')
+ if #legend > 0 then
+ draw_legend(cr, inner, inner.y + inner.h - legend_size * 0.5, legend_size,
+ legend, colors, cal.colors)
+ end
return
end
@@ -211,14 +263,26 @@ function M.draw(cr, rect, colors)
-- A card that silently drops the rest of the week is worse than one showing
-- fewer events and admitting it: the whole point of the card is knowing
-- what is coming.
- local room = math.floor(((inner.y + inner.h) - ey + ev_step) / ev_step)
+ --
+ -- Counted from the same test the drawing loop uses (a row at `ey` fits when
+ -- ey <= floor_y), not an independent division: the two disagreeing by one
+ -- row is what made the overflow line vanish exactly when it was needed,
+ -- since the loop cut the row the count had already spent.
+ local room = 0
+ local probe = ey
+ while probe <= floor_y do room = room + 1; probe = probe + ev_step end
+
local shown = #cal.events
- if room < shown then shown = math.max(room - 1, 1) end
+ -- The overflow line costs a row, so it is only worth taking when it reports
+ -- more than the row it displaces.
+ if room < shown then
+ shown = (room >= 2) and (room - 1) or room
+ end
local hidden = #cal.events - shown
for i = 1, shown do
local e = cal.events[i]
- if ey + ev_step > inner.y + inner.h then break end
+ if ey > floor_y then break end
local colour = cal_colour(e.calendar, colors, cal.colors)
card.font(cr, card.FONT_MONO, ev_size, false)
@@ -237,11 +301,16 @@ function M.draw(cr, rect, colors)
-- The overflow line, in the label colour so it reads as chrome rather than
-- as another appointment.
- if hidden > 0 and ey + ev_step <= inner.y + inner.h + ev_step then
+ if hidden > 0 and ey <= floor_y then
card.font(cr, card.FONT_UI, ev_size * 0.92, false)
card.rgba(cr, colors.label, 0.8)
card.text(cr, inner.x, ey, string.format('+%d more', hidden))
end
+
+ if #legend > 0 then
+ draw_legend(cr, inner, inner.y + inner.h - legend_size * 0.5, legend_size,
+ legend, colors, cal.colors)
+ end
end
return M